summaryrefslogtreecommitdiff
path: root/i386-gen.c
diff options
context:
space:
mode:
authorThomas Preud'homme <robotux@celest.fr>2016-12-17 11:04:34 +0000
committerThomas Preud'homme <robotux@celest.fr>2016-12-17 11:04:34 +0000
commit3f2e65a51523fbb98a44b71c29ae3a3fcc13854b (patch)
tree6e401550a4eddcc55a9db4b685e6a4968550a661 /i386-gen.c
parent83bd60f5184818823d7be84af0930236d0d892f7 (diff)
New upstream version 0.9.27~git20161217.cd9514ab
Diffstat (limited to 'i386-gen.c')
-rw-r--r--i386-gen.c130
1 files changed, 85 insertions, 45 deletions
diff --git a/i386-gen.c b/i386-gen.c
index c18b9c3..a8c6f4a 100644
--- a/i386-gen.c
+++ b/i386-gen.c
@@ -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;