mirror of
https://github.com/mirror/tinycc.git
synced 2025-03-08 08:40:08 +08:00
i386-gen: preserve fp control word in gen_cvt_ftoi
- Use runtime function for conversion
- Also initialize fp with tcc -run on windows
This fixes a bug where
double x = 1.0;
double y = 1.0000000000000001;
double z = x < y ? 0 : sqrt (x*x - y*y);
caused a bad sqrt because rounding precision for the x < y comparison
was different to the one used within the sqrt function.
This also fixes a bug where
printf("%d, %d", (int)pow(10, 2), (int)pow(10, 2));
would print
100, 99
Unrelated:
win32: document relative include & lib lookup
win32: normalize_slashes: do not mirror silly gcc behavior
This reverts part of commit 8a81f9e103
winapi: add missing WINAPI decl. for some functions
This commit is contained in:
parent
69c2e7f96c
commit
73faaea227
91
i386-gen.c
91
i386-gen.c
@ -338,6 +338,15 @@ static void gadd_sp(int val)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void gen_static_call(int v)
|
||||||
|
{
|
||||||
|
Sym *sym;
|
||||||
|
|
||||||
|
sym = external_global_sym(v, &func_old_type, 0);
|
||||||
|
oad(0xe8, -4);
|
||||||
|
greloc(cur_text_section, sym, ind-4, R_386_PC32);
|
||||||
|
}
|
||||||
|
|
||||||
/* 'is_jmp' is '1' if it is a jump */
|
/* 'is_jmp' is '1' if it is a jump */
|
||||||
static void gcall_or_jmp(int is_jmp)
|
static void gcall_or_jmp(int is_jmp)
|
||||||
{
|
{
|
||||||
@ -570,6 +579,12 @@ ST_FUNC void gfunc_prolog(CType *func_type)
|
|||||||
func_bound_offset = lbounds_section->data_offset;
|
func_bound_offset = lbounds_section->data_offset;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef TCC_TARGET_PE
|
||||||
|
if (0 == strcmp(funcname, "main"))
|
||||||
|
gen_static_call(TOK___tcc_fpinit);
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* generate function epilog */
|
/* generate function epilog */
|
||||||
@ -582,7 +597,7 @@ ST_FUNC void gfunc_epilog(void)
|
|||||||
&& func_bound_offset != lbounds_section->data_offset) {
|
&& func_bound_offset != lbounds_section->data_offset) {
|
||||||
int saved_ind;
|
int saved_ind;
|
||||||
int *bounds_ptr;
|
int *bounds_ptr;
|
||||||
Sym *sym, *sym_data;
|
Sym *sym_data;
|
||||||
/* add end of table info */
|
/* add end of table info */
|
||||||
bounds_ptr = section_ptr_add(lbounds_section, sizeof(int));
|
bounds_ptr = section_ptr_add(lbounds_section, sizeof(int));
|
||||||
*bounds_ptr = 0;
|
*bounds_ptr = 0;
|
||||||
@ -594,20 +609,16 @@ ST_FUNC void gfunc_epilog(void)
|
|||||||
greloc(cur_text_section, sym_data,
|
greloc(cur_text_section, sym_data,
|
||||||
ind + 1, R_386_32);
|
ind + 1, R_386_32);
|
||||||
oad(0xb8, 0); /* mov %eax, xxx */
|
oad(0xb8, 0); /* mov %eax, xxx */
|
||||||
sym = external_global_sym(TOK___bound_local_new, &func_old_type, 0);
|
gen_static_call(TOK___bound_local_new);
|
||||||
greloc(cur_text_section, sym,
|
|
||||||
ind + 1, R_386_PC32);
|
|
||||||
oad(0xe8, -4);
|
|
||||||
ind = saved_ind;
|
ind = saved_ind;
|
||||||
/* generate bound check local freeing */
|
/* generate bound check local freeing */
|
||||||
o(0x5250); /* save returned value, if any */
|
o(0x5250); /* save returned value, if any */
|
||||||
greloc(cur_text_section, sym_data,
|
greloc(cur_text_section, sym_data,
|
||||||
ind + 1, R_386_32);
|
ind + 1, R_386_32);
|
||||||
oad(0xb8, 0); /* mov %eax, xxx */
|
oad(0xb8, 0); /* mov %eax, xxx */
|
||||||
sym = external_global_sym(TOK___bound_local_delete, &func_old_type, 0);
|
gen_static_call(TOK___bound_local_delete);
|
||||||
greloc(cur_text_section, sym,
|
|
||||||
ind + 1, R_386_PC32);
|
|
||||||
oad(0xe8, -4);
|
|
||||||
o(0x585a); /* restore returned value, if any */
|
o(0x585a); /* restore returned value, if any */
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -626,10 +637,8 @@ ST_FUNC void gfunc_epilog(void)
|
|||||||
ind = func_sub_sp_offset - FUNC_PROLOG_SIZE;
|
ind = func_sub_sp_offset - FUNC_PROLOG_SIZE;
|
||||||
#ifdef TCC_TARGET_PE
|
#ifdef TCC_TARGET_PE
|
||||||
if (v >= 4096) {
|
if (v >= 4096) {
|
||||||
Sym *sym = external_global_sym(TOK___chkstk, &func_old_type, 0);
|
|
||||||
oad(0xb8, v); /* mov stacksize, %eax */
|
oad(0xb8, v); /* mov stacksize, %eax */
|
||||||
oad(0xe8, -4); /* call __chkstk, (does the stackframe too) */
|
gen_static_call(TOK___chkstk); /* call __chkstk, (does the stackframe too) */
|
||||||
greloc(cur_text_section, sym, ind-4, R_386_PC32);
|
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
@ -992,52 +1001,13 @@ ST_FUNC void gen_cvt_itof(int t)
|
|||||||
/* XXX: handle long long case */
|
/* XXX: handle long long case */
|
||||||
ST_FUNC void gen_cvt_ftoi(int t)
|
ST_FUNC void gen_cvt_ftoi(int t)
|
||||||
{
|
{
|
||||||
int r, r2, size;
|
|
||||||
Sym *sym;
|
|
||||||
CType ushort_type;
|
|
||||||
|
|
||||||
ushort_type.t = VT_SHORT | VT_UNSIGNED;
|
|
||||||
ushort_type.ref = 0;
|
|
||||||
|
|
||||||
gv(RC_FLOAT);
|
gv(RC_FLOAT);
|
||||||
if (t != VT_INT)
|
save_reg(TREG_EAX);
|
||||||
size = 8;
|
save_reg(TREG_EDX);
|
||||||
else
|
gen_static_call(TOK___tcc_cvt_ftol);
|
||||||
size = 4;
|
vtop->r = TREG_EAX; /* mark reg as used */
|
||||||
|
if (t == VT_LLONG)
|
||||||
o(0x2dd9); /* ldcw xxx */
|
vtop->r2 = TREG_EDX;
|
||||||
sym = external_global_sym(TOK___tcc_int_fpu_control,
|
|
||||||
&ushort_type, VT_LVAL);
|
|
||||||
greloc(cur_text_section, sym,
|
|
||||||
ind, R_386_32);
|
|
||||||
gen_le32(0);
|
|
||||||
|
|
||||||
oad(0xec81, size); /* sub $xxx, %esp */
|
|
||||||
if (size == 4)
|
|
||||||
o(0x1cdb); /* fistpl */
|
|
||||||
else
|
|
||||||
o(0x3cdf); /* fistpll */
|
|
||||||
o(0x24);
|
|
||||||
o(0x2dd9); /* ldcw xxx */
|
|
||||||
sym = external_global_sym(TOK___tcc_fpu_control,
|
|
||||||
&ushort_type, VT_LVAL);
|
|
||||||
greloc(cur_text_section, sym,
|
|
||||||
ind, R_386_32);
|
|
||||||
gen_le32(0);
|
|
||||||
|
|
||||||
r = get_reg(RC_INT);
|
|
||||||
o(0x58 + r); /* pop r */
|
|
||||||
if (size == 8) {
|
|
||||||
if (t == VT_LLONG) {
|
|
||||||
vtop->r = r; /* mark reg as used */
|
|
||||||
r2 = get_reg(RC_INT);
|
|
||||||
o(0x58 + r2); /* pop r2 */
|
|
||||||
vtop->r2 = r2;
|
|
||||||
} else {
|
|
||||||
o(0x04c483); /* add $4, %esp */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
vtop->r = r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* convert from one floating point type to another */
|
/* convert from one floating point type to another */
|
||||||
@ -1060,18 +1030,13 @@ ST_FUNC void ggoto(void)
|
|||||||
/* generate a bounded pointer addition */
|
/* generate a bounded pointer addition */
|
||||||
ST_FUNC void gen_bounded_ptr_add(void)
|
ST_FUNC void gen_bounded_ptr_add(void)
|
||||||
{
|
{
|
||||||
Sym *sym;
|
|
||||||
|
|
||||||
/* prepare fast i386 function call (args in eax and edx) */
|
/* prepare fast i386 function call (args in eax and edx) */
|
||||||
gv2(RC_EAX, RC_EDX);
|
gv2(RC_EAX, RC_EDX);
|
||||||
/* save all temporary registers */
|
/* save all temporary registers */
|
||||||
vtop -= 2;
|
vtop -= 2;
|
||||||
save_regs(0);
|
save_regs(0);
|
||||||
/* do a fast function call */
|
/* do a fast function call */
|
||||||
sym = external_global_sym(TOK___bound_ptr_add, &func_old_type, 0);
|
gen_static_call(TOK___bound_ptr_add);
|
||||||
greloc(cur_text_section, sym,
|
|
||||||
ind + 1, R_386_PC32);
|
|
||||||
oad(0xe8, -4);
|
|
||||||
/* returned pointer is in eax */
|
/* returned pointer is in eax */
|
||||||
vtop++;
|
vtop++;
|
||||||
vtop->r = TREG_EAX | VT_BOUNDED;
|
vtop->r = TREG_EAX | VT_BOUNDED;
|
||||||
|
@ -478,13 +478,24 @@ long long __ashldi3(long long a, int b)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__i386__)
|
#ifndef _WIN32
|
||||||
/* FPU control word for rounding to nearest mode */
|
void __tcc_fpinit(void)
|
||||||
unsigned short __tcc_fpu_control = 0x137f;
|
{
|
||||||
/* FPU control word for round to zero mode for int conversion */
|
unsigned c = 0x137F;
|
||||||
unsigned short __tcc_int_fpu_control = 0x137f | 0x0c00;
|
__asm__ __volatile__ ("fldcw %0" : "=m" (c));
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
long long __tcc_cvt_ftol(long double x)
|
||||||
|
{
|
||||||
|
unsigned c0, c1;
|
||||||
|
long long ret;
|
||||||
|
__asm__ __volatile__ ("fnstcw %0" : "=m" (c0));
|
||||||
|
c1 = c0 | 0x0C00;
|
||||||
|
__asm__ __volatile__ ("fldcw %0" : "=m" (c1));
|
||||||
|
__asm__ __volatile__ ("fistpll %0" : "=m" (ret));
|
||||||
|
__asm__ __volatile__ ("fldcw %0" : "=m" (c0));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
#endif /* !__x86_64__ */
|
#endif /* !__x86_64__ */
|
||||||
|
|
||||||
/* XXX: fix tcc's code generator to do this instead */
|
/* XXX: fix tcc's code generator to do this instead */
|
||||||
|
15
libtcc.c
15
libtcc.c
@ -78,21 +78,13 @@ ST_FUNC void asm_global_instr(void)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/********************************************************/
|
/********************************************************/
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
// GCC appears to use '/' for relative paths and '\\' for absolute paths on Windows
|
|
||||||
static char *normalize_slashes(char *path)
|
static char *normalize_slashes(char *path)
|
||||||
{
|
{
|
||||||
char *p;
|
char *p;
|
||||||
if (path[1] == ':') {
|
for (p = path; *p; ++p)
|
||||||
for (p = path+2; *p; ++p)
|
if (*p == '\\')
|
||||||
if (*p == '/')
|
*p = '/';
|
||||||
*p = '\\';
|
|
||||||
} else {
|
|
||||||
for (p = path; *p; ++p)
|
|
||||||
if (*p == '\\')
|
|
||||||
*p = '/';
|
|
||||||
}
|
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1036,6 +1028,7 @@ LIBTCCAPI TCCState *tcc_new(void)
|
|||||||
#ifdef TCC_TARGET_I386
|
#ifdef TCC_TARGET_I386
|
||||||
s->seg_size = 32;
|
s->seg_size = 32;
|
||||||
#endif
|
#endif
|
||||||
|
s->runtime_main = "main";
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
1
tcc.h
1
tcc.h
@ -665,6 +665,7 @@ struct TCCState {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef TCC_IS_NATIVE
|
#ifdef TCC_IS_NATIVE
|
||||||
|
const char *runtime_main;
|
||||||
/* for tcc_relocate */
|
/* for tcc_relocate */
|
||||||
void *runtime_mem;
|
void *runtime_mem;
|
||||||
# ifdef HAVE_SELINUX
|
# ifdef HAVE_SELINUX
|
||||||
|
22
tccpe.c
22
tccpe.c
@ -1726,7 +1726,6 @@ ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack)
|
|||||||
static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
|
static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
|
||||||
{
|
{
|
||||||
const char *start_symbol;
|
const char *start_symbol;
|
||||||
ADDR3264 addr = 0;
|
|
||||||
int pe_type = 0;
|
int pe_type = 0;
|
||||||
|
|
||||||
if (find_elf_sym(symtab_section, PE_STDSYM("WinMain","@16")))
|
if (find_elf_sym(symtab_section, PE_STDSYM("WinMain","@16")))
|
||||||
@ -1742,16 +1741,13 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
|
|||||||
|
|
||||||
start_symbol =
|
start_symbol =
|
||||||
TCC_OUTPUT_MEMORY == s1->output_type
|
TCC_OUTPUT_MEMORY == s1->output_type
|
||||||
? PE_GUI == pe_type ? "__runwinmain" : "_main"
|
? PE_GUI == pe_type ? "__runwinmain" : "__runmain"
|
||||||
: PE_DLL == pe_type ? PE_STDSYM("__dllstart","@12")
|
: PE_DLL == pe_type ? PE_STDSYM("__dllstart","@12")
|
||||||
: PE_GUI == pe_type ? "__winstart" : "__start"
|
: PE_GUI == pe_type ? "__winstart" : "__start"
|
||||||
;
|
;
|
||||||
|
|
||||||
if (!s1->leading_underscore || strchr(start_symbol, '@')) {
|
if (!s1->leading_underscore || strchr(start_symbol, '@'))
|
||||||
++start_symbol;
|
++start_symbol;
|
||||||
if (start_symbol[0] != '_')
|
|
||||||
start_symbol = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* grab the startup code from libtcc1 */
|
/* grab the startup code from libtcc1 */
|
||||||
if (start_symbol)
|
if (start_symbol)
|
||||||
@ -1776,21 +1772,13 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TCC_OUTPUT_MEMORY == s1->output_type)
|
if (TCC_OUTPUT_MEMORY == s1->output_type) {
|
||||||
pe_type = PE_RUN;
|
pe_type = PE_RUN;
|
||||||
|
s1->runtime_main = start_symbol;
|
||||||
if (start_symbol) {
|
|
||||||
addr = get_elf_sym_addr(s1, start_symbol, 1);
|
|
||||||
if (PE_RUN == pe_type && addr)
|
|
||||||
/* for -run GUI's, put '_runwinmain' instead of 'main' */
|
|
||||||
add_elf_sym(symtab_section,
|
|
||||||
addr, 0,
|
|
||||||
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
|
|
||||||
text_section->sh_num, "main");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pe->type = pe_type;
|
pe->type = pe_type;
|
||||||
pe->start_addr = addr;
|
pe->start_addr = (DWORD)tcc_get_symbol_err(s1, start_symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
ST_FUNC int pe_output_file(TCCState * s1, const char *filename)
|
ST_FUNC int pe_output_file(TCCState * s1, const char *filename)
|
||||||
|
2
tccrun.c
2
tccrun.c
@ -97,7 +97,7 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
|
|||||||
if (tcc_relocate(s1, TCC_RELOCATE_AUTO) < 0)
|
if (tcc_relocate(s1, TCC_RELOCATE_AUTO) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
prog_main = tcc_get_symbol_err(s1, "main");
|
prog_main = tcc_get_symbol_err(s1, s1->runtime_main);
|
||||||
|
|
||||||
#ifdef CONFIG_TCC_BACKTRACE
|
#ifdef CONFIG_TCC_BACKTRACE
|
||||||
if (s1->do_debug) {
|
if (s1->do_debug) {
|
||||||
|
4
tcctok.h
4
tcctok.h
@ -194,8 +194,8 @@
|
|||||||
DEF(TOK__remu, "_remu")
|
DEF(TOK__remu, "_remu")
|
||||||
#endif
|
#endif
|
||||||
#ifdef TCC_TARGET_I386
|
#ifdef TCC_TARGET_I386
|
||||||
DEF(TOK___tcc_int_fpu_control, "__tcc_int_fpu_control")
|
DEF(TOK___tcc_fpinit, "__tcc_fpinit")
|
||||||
DEF(TOK___tcc_fpu_control, "__tcc_fpu_control")
|
DEF(TOK___tcc_cvt_ftol, "__tcc_cvt_ftol")
|
||||||
#endif
|
#endif
|
||||||
#ifdef TCC_ARM_EABI
|
#ifdef TCC_ARM_EABI
|
||||||
DEF(TOK___ashrdi3, "__aeabi_lasr")
|
DEF(TOK___ashrdi3, "__aeabi_lasr")
|
||||||
|
@ -968,15 +968,15 @@ extern "C" {
|
|||||||
LONG64 InterlockedExchangeAdd64(LONG64 volatile *Addend,LONG64 Value);
|
LONG64 InterlockedExchangeAdd64(LONG64 volatile *Addend,LONG64 Value);
|
||||||
LONG64 InterlockedCompareExchange64(LONG64 volatile *Destination,LONG64 ExChange,LONG64 Comperand);
|
LONG64 InterlockedCompareExchange64(LONG64 volatile *Destination,LONG64 ExChange,LONG64 Comperand);
|
||||||
#else
|
#else
|
||||||
LONG InterlockedIncrement(LONG volatile *lpAddend);
|
LONG WINAPI InterlockedIncrement(LONG volatile *lpAddend);
|
||||||
LONG InterlockedDecrement(LONG volatile *lpAddend);
|
LONG WINAPI InterlockedDecrement(LONG volatile *lpAddend);
|
||||||
LONG InterlockedExchange(LONG volatile *Target,LONG Value);
|
LONG WINAPI InterlockedExchange(LONG volatile *Target,LONG Value);
|
||||||
|
|
||||||
#define InterlockedExchangePointer(Target,Value) (PVOID)InterlockedExchange((PLONG)(Target),(LONG)(Value))
|
#define InterlockedExchangePointer(Target,Value) (PVOID)InterlockedExchange((PLONG)(Target),(LONG)(Value))
|
||||||
|
|
||||||
LONG InterlockedExchangeAdd(LONG volatile *Addend,LONG Value);
|
LONG WINAPI InterlockedExchangeAdd(LONG volatile *Addend,LONG Value);
|
||||||
LONG InterlockedCompareExchange(LONG volatile *Destination,LONG Exchange,LONG Comperand);
|
LONG WINAPI InterlockedCompareExchange(LONG volatile *Destination,LONG Exchange,LONG Comperand);
|
||||||
LONGLONG InterlockedCompareExchange64(LONGLONG volatile *Destination,LONGLONG Exchange,LONGLONG Comperand);
|
LONGLONG WINAPI InterlockedCompareExchange64(LONGLONG volatile *Destination,LONGLONG Exchange,LONGLONG Comperand);
|
||||||
|
|
||||||
__CRT_INLINE LONGLONG InterlockedAnd64 (LONGLONG volatile *Destination,LONGLONG Value) {
|
__CRT_INLINE LONGLONG InterlockedAnd64 (LONGLONG volatile *Destination,LONGLONG Value) {
|
||||||
LONGLONG Old;
|
LONGLONG Old;
|
||||||
|
@ -31,4 +31,10 @@ int _start(void)
|
|||||||
exit(ret);
|
exit(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int _runmain(int argc, char **argv)
|
||||||
|
{
|
||||||
|
_controlfp(0x10000, 0x30000);
|
||||||
|
return main(argc, argv, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
// =============================================
|
// =============================================
|
||||||
|
@ -59,6 +59,6 @@ int _runwinmain(int argc, char **argv)
|
|||||||
szCmd = "";
|
szCmd = "";
|
||||||
else if (szCmd > p && szCmd[-1] == '\"')
|
else if (szCmd > p && szCmd[-1] == '\"')
|
||||||
--szCmd;
|
--szCmd;
|
||||||
|
_controlfp(0x10000, 0x30000);
|
||||||
return WinMain(GetModuleHandle(NULL), NULL, szCmd, SW_SHOWDEFAULT);
|
return WinMain(GetModuleHandle(NULL), NULL, szCmd, SW_SHOWDEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,6 +18,12 @@
|
|||||||
system PATH.
|
system PATH.
|
||||||
|
|
||||||
|
|
||||||
|
Include and library search paths
|
||||||
|
--------------------------------
|
||||||
|
On windows, the standard "include" and "lib" directories are searched
|
||||||
|
relatively from the location of the executables (tcc.exe, libtcc.dll).
|
||||||
|
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
---------
|
---------
|
||||||
Open a console window (DOS box) and 'cd' to the examples directory.
|
Open a console window (DOS box) and 'cd' to the examples directory.
|
||||||
|
Loading…
Reference in New Issue
Block a user