History

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

grischka committed 13 years ago

Commit 73faaea1 parent 69c2e7f11 files · +77 −107Browse files

Unified · Split

11 files
  1. i386-gen.c +28 −63
  2. lib/libtcc1.c +17 −6
  3. libtcc.c +4 −11
  4. tcc.h +1 −0
  5. tccpe.c +5 −17
  6. tccrun.c +1 −1
  7. tcctok.h +2 −2
  8. win32/include/winapi/winbase.h +6 −6
  9. win32/lib/crt1.c +6 −0
  10. win32/lib/wincrt1.c +1 −1
  11. win32/tcc-win32.txt +6 −0
i386-gen.c+28−63
@@ -338,6 +338,15 @@ static void gadd_sp(int val) · 337 unmodified lines
338 }338 }
339}339}
340 340
341static void gen_static_call(int v)
342{
343 Sym *sym;
344
345 sym = external_global_sym(v, &func_old_type, 0);
346 oad(0xe8, -4);
347 greloc(cur_text_section, sym, ind-4, R_386_PC32);
348}
349
341/* 'is_jmp' is '1' if it is a jump */350/* 'is_jmp' is '1' if it is a jump */
342static void gcall_or_jmp(int is_jmp)351static void gcall_or_jmp(int is_jmp)
343{352{
@@ -570,6 +579,12 @@ ST_FUNC void gfunc_prolog(CType *func_type) · 226 unmodified lines
570 func_bound_offset = lbounds_section->data_offset;579 func_bound_offset = lbounds_section->data_offset;
571 }580 }
572#endif581#endif
582
583#ifndef TCC_TARGET_PE
584 if (0 == strcmp(funcname, "main"))
585 gen_static_call(TOK___tcc_fpinit);
586#endif
587
573}588}
574 589
575/* generate function epilog */590/* generate function epilog */
@@ -582,7 +597,7 @@ ST_FUNC void gfunc_epilog(void) · 6 unmodified lines
582 && func_bound_offset != lbounds_section->data_offset) {597 && func_bound_offset != lbounds_section->data_offset) {
583 int saved_ind;598 int saved_ind;
584 int *bounds_ptr;599 int *bounds_ptr;
585 Sym *sym, *sym_data;600 Sym *sym_data;
586 /* add end of table info */601 /* add end of table info */
587 bounds_ptr = section_ptr_add(lbounds_section, sizeof(int));602 bounds_ptr = section_ptr_add(lbounds_section, sizeof(int));
588 *bounds_ptr = 0;603 *bounds_ptr = 0;
@@ -594,20 +609,16 @@ ST_FUNC void gfunc_epilog(void) · 5 unmodified lines
594 greloc(cur_text_section, sym_data,609 greloc(cur_text_section, sym_data,
595 ind + 1, R_386_32);610 ind + 1, R_386_32);
596 oad(0xb8, 0); /* mov %eax, xxx */611 oad(0xb8, 0); /* mov %eax, xxx */
597 sym = external_global_sym(TOK___bound_local_new, &func_old_type, 0);612 gen_static_call(TOK___bound_local_new);
598 greloc(cur_text_section, sym, 613
599 ind + 1, R_386_PC32);
600 oad(0xe8, -4);
601 ind = saved_ind;614 ind = saved_ind;
602 /* generate bound check local freeing */615 /* generate bound check local freeing */
603 o(0x5250); /* save returned value, if any */616 o(0x5250); /* save returned value, if any */
604 greloc(cur_text_section, sym_data,617 greloc(cur_text_section, sym_data,
605 ind + 1, R_386_32);618 ind + 1, R_386_32);
606 oad(0xb8, 0); /* mov %eax, xxx */619 oad(0xb8, 0); /* mov %eax, xxx */
607 sym = external_global_sym(TOK___bound_local_delete, &func_old_type, 0);620 gen_static_call(TOK___bound_local_delete);
608 greloc(cur_text_section, sym, 621
609 ind + 1, R_386_PC32);
610 oad(0xe8, -4);
611 o(0x585a); /* restore returned value, if any */622 o(0x585a); /* restore returned value, if any */
612 }623 }
613#endif624#endif
@@ -626,10 +637,8 @@ ST_FUNC void gfunc_epilog(void) · 12 unmodified lines
626 ind = func_sub_sp_offset - FUNC_PROLOG_SIZE;637 ind = func_sub_sp_offset - FUNC_PROLOG_SIZE;
627#ifdef TCC_TARGET_PE638#ifdef TCC_TARGET_PE
628 if (v >= 4096) {639 if (v >= 4096) {
629 Sym *sym = external_global_sym(TOK___chkstk, &func_old_type, 0);
630 oad(0xb8, v); /* mov stacksize, %eax */640 oad(0xb8, v); /* mov stacksize, %eax */
631 oad(0xe8, -4); /* call __chkstk, (does the stackframe too) */641 gen_static_call(TOK___chkstk); /* call __chkstk, (does the stackframe too) */
632 greloc(cur_text_section, sym, ind-4, R_386_PC32);
633 } else642 } else
634#endif643#endif
635 {644 {
@@ -992,52 +1001,13 @@ ST_FUNC void gen_cvt_itof(int t) · 356 unmodified lines
992/* XXX: handle long long case */1001/* XXX: handle long long case */
993ST_FUNC void gen_cvt_ftoi(int t)1002ST_FUNC void gen_cvt_ftoi(int t)
994{1003{
995 int r, r2, size;
996 Sym *sym;
997 CType ushort_type;
998
999 ushort_type.t = VT_SHORT | VT_UNSIGNED;
1000 ushort_type.ref = 0;
1001
1002 gv(RC_FLOAT);1004 gv(RC_FLOAT);
1003 if (t != VT_INT)1005 save_reg(TREG_EAX);
1004 size = 8;1006 save_reg(TREG_EDX);
1005 else 1007 gen_static_call(TOK___tcc_cvt_ftol);
1006 size = 4;1008 vtop->r = TREG_EAX; /* mark reg as used */
1007 1009 if (t == VT_LLONG)
1008 o(0x2dd9); /* ldcw xxx */1010 vtop->r2 = TREG_EDX;
1009 sym = external_global_sym(TOK___tcc_int_fpu_control,
1010 &ushort_type, VT_LVAL);
1011 greloc(cur_text_section, sym,
1012 ind, R_386_32);
1013 gen_le32(0);
1014
1015 oad(0xec81, size); /* sub $xxx, %esp */
1016 if (size == 4)
1017 o(0x1cdb); /* fistpl */
1018 else
1019 o(0x3cdf); /* fistpll */
1020 o(0x24);
1021 o(0x2dd9); /* ldcw xxx */
1022 sym = external_global_sym(TOK___tcc_fpu_control,
1023 &ushort_type, VT_LVAL);
1024 greloc(cur_text_section, sym,
1025 ind, R_386_32);
1026 gen_le32(0);
1027
1028 r = get_reg(RC_INT);
1029 o(0x58 + r); /* pop r */
1030 if (size == 8) {
1031 if (t == VT_LLONG) {
1032 vtop->r = r; /* mark reg as used */
1033 r2 = get_reg(RC_INT);
1034 o(0x58 + r2); /* pop r2 */
1035 vtop->r2 = r2;
1036 } else {
1037 o(0x04c483); /* add $4, %esp */
1038 }
1039 }
1040 vtop->r = r;
1041}1011}
1042 1012
1043/* convert from one floating point type to another */1013/* convert from one floating point type to another */
@@ -1060,18 +1030,13 @@ ST_FUNC void ggoto(void) · 16 unmodified lines
1060/* generate a bounded pointer addition */1030/* generate a bounded pointer addition */
1061ST_FUNC void gen_bounded_ptr_add(void)1031ST_FUNC void gen_bounded_ptr_add(void)
1062{1032{
1063 Sym *sym;
1064
1065 /* prepare fast i386 function call (args in eax and edx) */1033 /* prepare fast i386 function call (args in eax and edx) */
1066 gv2(RC_EAX, RC_EDX);1034 gv2(RC_EAX, RC_EDX);
1067 /* save all temporary registers */1035 /* save all temporary registers */
1068 vtop -= 2;1036 vtop -= 2;
1069 save_regs(0);1037 save_regs(0);
1070 /* do a fast function call */1038 /* do a fast function call */
1071 sym = external_global_sym(TOK___bound_ptr_add, &func_old_type, 0);1039 gen_static_call(TOK___bound_ptr_add);
1072 greloc(cur_text_section, sym,
1073 ind + 1, R_386_PC32);
1074 oad(0xe8, -4);
1075 /* returned pointer is in eax */1040 /* returned pointer is in eax */
1076 vtop++;1041 vtop++;
1077 vtop->r = TREG_EAX | VT_BOUNDED;1042 vtop->r = TREG_EAX | VT_BOUNDED;
lib/libtcc1.c+17−6
@@ -478,13 +478,24 @@ long long __ashldi3(long long a, int b) · 477 unmodified lines
478#endif478#endif
479}479}
480 480
481#if defined(__i386__)481#ifndef _WIN32
482/* FPU control word for rounding to nearest mode */482void __tcc_fpinit(void)
483unsigned short __tcc_fpu_control = 0x137f;483{
484/* FPU control word for round to zero mode for int conversion */484 unsigned c = 0x137F;
485unsigned short __tcc_int_fpu_control = 0x137f | 0x0c00;485 __asm__ __volatile__ ("fldcw %0" : "=m" (c));
486}
486#endif487#endif
487 488long long __tcc_cvt_ftol(long double x)
489{
490 unsigned c0, c1;
491 long long ret;
492 __asm__ __volatile__ ("fnstcw %0" : "=m" (c0));
493 c1 = c0 | 0x0C00;
494 __asm__ __volatile__ ("fldcw %0" : "=m" (c1));
495 __asm__ __volatile__ ("fistpll %0" : "=m" (ret));
496 __asm__ __volatile__ ("fldcw %0" : "=m" (c0));
497 return ret;
498}
488#endif /* !__x86_64__ */499#endif /* !__x86_64__ */
489 500
490/* XXX: fix tcc's code generator to do this instead */501/* XXX: fix tcc's code generator to do this instead */
libtcc.c+4−11
@@ -78,21 +78,13 @@ ST_FUNC void asm_global_instr(void) · 77 unmodified lines
78#endif78#endif
79 79
80/********************************************************/80/********************************************************/
81
82#ifdef _WIN3281#ifdef _WIN32
83// GCC appears to use '/' for relative paths and '\\' for absolute paths on Windows
84static char *normalize_slashes(char *path)82static char *normalize_slashes(char *path)
85{83{
86 char *p;84 char *p;
87 if (path[1] == ':') {85 for (p = path; *p; ++p)
88 for (p = path+2; *p; ++p)86 if (*p == '\\')
89 if (*p == '/')87 *p = '/';
90 *p = '\\';
91 } else {
92 for (p = path; *p; ++p)
93 if (*p == '\\')
94 *p = '/';
95 }
96 return path;88 return path;
97}89}
98 90
@@ -1036,6 +1028,7 @@ LIBTCCAPI TCCState *tcc_new(void) · 937 unmodified lines
1036#ifdef TCC_TARGET_I3861028#ifdef TCC_TARGET_I386
1037 s->seg_size = 32;1029 s->seg_size = 32;
1038#endif1030#endif
1031 s->runtime_main = "main";
1039 return s;1032 return s;
1040}1033}
1041 1034
tcc.h+1−0
@@ -665,6 +665,7 @@ struct TCCState { · 664 unmodified lines
665#endif665#endif
666 666
667#ifdef TCC_IS_NATIVE667#ifdef TCC_IS_NATIVE
668 const char *runtime_main;
668 /* for tcc_relocate */669 /* for tcc_relocate */
669 void *runtime_mem;670 void *runtime_mem;
670# ifdef HAVE_SELINUX671# ifdef HAVE_SELINUX
tccpe.c+5−17
@@ -1726,7 +1726,6 @@ ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack) · 1725 unmodified lines
1726static void pe_add_runtime(TCCState *s1, struct pe_info *pe)1726static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
1727{1727{
1728 const char *start_symbol;1728 const char *start_symbol;
1729 ADDR3264 addr = 0;
1730 int pe_type = 0;1729 int pe_type = 0;
1731 1730
1732 if (find_elf_sym(symtab_section, PE_STDSYM("WinMain","@16")))1731 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) · 9 unmodified lines
1742 1741
1743 start_symbol =1742 start_symbol =
1744 TCC_OUTPUT_MEMORY == s1->output_type1743 TCC_OUTPUT_MEMORY == s1->output_type
1745 ? PE_GUI == pe_type ? "__runwinmain" : "_main"1744 ? PE_GUI == pe_type ? "__runwinmain" : "__runmain"
1746 : PE_DLL == pe_type ? PE_STDSYM("__dllstart","@12")1745 : PE_DLL == pe_type ? PE_STDSYM("__dllstart","@12")
1747 : PE_GUI == pe_type ? "__winstart" : "__start"1746 : PE_GUI == pe_type ? "__winstart" : "__start"
1748 ;1747 ;
1749 1748
1750 if (!s1->leading_underscore || strchr(start_symbol, '@')) {1749 if (!s1->leading_underscore || strchr(start_symbol, '@'))
1751 ++start_symbol;1750 ++start_symbol;
1752 if (start_symbol[0] != '_')
1753 start_symbol = NULL;
1754 }
1755 1751
1756 /* grab the startup code from libtcc1 */1752 /* grab the startup code from libtcc1 */
1757 if (start_symbol)1753 if (start_symbol)
@@ -1776,21 +1772,13 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe) · 18 unmodified lines
1776 }1772 }
1777 }1773 }
1778 1774
1779 if (TCC_OUTPUT_MEMORY == s1->output_type)1775 if (TCC_OUTPUT_MEMORY == s1->output_type) {
1780 pe_type = PE_RUN;1776 pe_type = PE_RUN;
1781 1777 s1->runtime_main = start_symbol;
1782 if (start_symbol) {
1783 addr = get_elf_sym_addr(s1, start_symbol, 1);
1784 if (PE_RUN == pe_type && addr)
1785 /* for -run GUI's, put '_runwinmain' instead of 'main' */
1786 add_elf_sym(symtab_section,
1787 addr, 0,
1788 ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
1789 text_section->sh_num, "main");
1790 }1778 }
1791 1779
1792 pe->type = pe_type;1780 pe->type = pe_type;
1793 pe->start_addr = addr;1781 pe->start_addr = (DWORD)tcc_get_symbol_err(s1, start_symbol);
1794}1782}
1795 1783
1796ST_FUNC int pe_output_file(TCCState * s1, const char *filename)1784ST_FUNC int pe_output_file(TCCState * s1, const char *filename)
tccrun.c+1−1
@@ -97,7 +97,7 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv) · 96 unmodified lines
97 if (tcc_relocate(s1, TCC_RELOCATE_AUTO) < 0)97 if (tcc_relocate(s1, TCC_RELOCATE_AUTO) < 0)
98 return -1;98 return -1;
99 99
100 prog_main = tcc_get_symbol_err(s1, "main");100 prog_main = tcc_get_symbol_err(s1, s1->runtime_main);
101 101
102#ifdef CONFIG_TCC_BACKTRACE102#ifdef CONFIG_TCC_BACKTRACE
103 if (s1->do_debug) {103 if (s1->do_debug) {
tcctok.h+2−2
@@ -194,8 +194,8 @@ · 193 unmodified lines
194 DEF(TOK__remu, "_remu")194 DEF(TOK__remu, "_remu")
195#endif195#endif
196#ifdef TCC_TARGET_I386196#ifdef TCC_TARGET_I386
197 DEF(TOK___tcc_int_fpu_control, "__tcc_int_fpu_control")197 DEF(TOK___tcc_fpinit, "__tcc_fpinit")
198 DEF(TOK___tcc_fpu_control, "__tcc_fpu_control")198 DEF(TOK___tcc_cvt_ftol, "__tcc_cvt_ftol")
199#endif199#endif
200#ifdef TCC_ARM_EABI200#ifdef TCC_ARM_EABI
201 DEF(TOK___ashrdi3, "__aeabi_lasr")201 DEF(TOK___ashrdi3, "__aeabi_lasr")
win32/include/winapi/winbase.h+6−6
@@ -968,15 +968,15 @@ extern "C" { · 967 unmodified lines
968 LONG64 InterlockedExchangeAdd64(LONG64 volatile *Addend,LONG64 Value);968 LONG64 InterlockedExchangeAdd64(LONG64 volatile *Addend,LONG64 Value);
969 LONG64 InterlockedCompareExchange64(LONG64 volatile *Destination,LONG64 ExChange,LONG64 Comperand);969 LONG64 InterlockedCompareExchange64(LONG64 volatile *Destination,LONG64 ExChange,LONG64 Comperand);
970#else970#else
971 LONG InterlockedIncrement(LONG volatile *lpAddend);971 LONG WINAPI InterlockedIncrement(LONG volatile *lpAddend);
972 LONG InterlockedDecrement(LONG volatile *lpAddend);972 LONG WINAPI InterlockedDecrement(LONG volatile *lpAddend);
973 LONG InterlockedExchange(LONG volatile *Target,LONG Value);973 LONG WINAPI InterlockedExchange(LONG volatile *Target,LONG Value);
974 974
975#define InterlockedExchangePointer(Target,Value) (PVOID)InterlockedExchange((PLONG)(Target),(LONG)(Value))975#define InterlockedExchangePointer(Target,Value) (PVOID)InterlockedExchange((PLONG)(Target),(LONG)(Value))
976 976
977 LONG InterlockedExchangeAdd(LONG volatile *Addend,LONG Value);977 LONG WINAPI InterlockedExchangeAdd(LONG volatile *Addend,LONG Value);
978 LONG InterlockedCompareExchange(LONG volatile *Destination,LONG Exchange,LONG Comperand);978 LONG WINAPI InterlockedCompareExchange(LONG volatile *Destination,LONG Exchange,LONG Comperand);
979 LONGLONG InterlockedCompareExchange64(LONGLONG volatile *Destination,LONGLONG Exchange,LONGLONG Comperand);979 LONGLONG WINAPI InterlockedCompareExchange64(LONGLONG volatile *Destination,LONGLONG Exchange,LONGLONG Comperand);
980 980
981 __CRT_INLINE LONGLONG InterlockedAnd64 (LONGLONG volatile *Destination,LONGLONG Value) {981 __CRT_INLINE LONGLONG InterlockedAnd64 (LONGLONG volatile *Destination,LONGLONG Value) {
982 LONGLONG Old;982 LONGLONG Old;
win32/lib/crt1.c+6−0
@@ -31,4 +31,10 @@ int _start(void) · 30 unmodified lines
31 exit(ret);31 exit(ret);
32}32}
33 33
34int _runmain(int argc, char **argv)
35{
36 _controlfp(0x10000, 0x30000);
37 return main(argc, argv, NULL);
38}
39
34// =============================================40// =============================================
win32/lib/wincrt1.c+1−1
@@ -59,6 +59,6 @@ int _runwinmain(int argc, char **argv) · 58 unmodified lines
59 szCmd = "";59 szCmd = "";
60 else if (szCmd > p && szCmd[-1] == '\"')60 else if (szCmd > p && szCmd[-1] == '\"')
61 --szCmd;61 --szCmd;
62 _controlfp(0x10000, 0x30000);
62 return WinMain(GetModuleHandle(NULL), NULL, szCmd, SW_SHOWDEFAULT);63 return WinMain(GetModuleHandle(NULL), NULL, szCmd, SW_SHOWDEFAULT);
63}64}
64
win32/tcc-win32.txt+6−0
@@ -18,6 +18,12 @@ · 17 unmodified lines
18 system PATH.18 system PATH.
19 19
20 20
21 Include and library search paths
22 --------------------------------
23 On windows, the standard "include" and "lib" directories are searched
24 relatively from the location of the executables (tcc.exe, libtcc.dll).
25
26
21 Examples:27 Examples:
22 ---------28 ---------
23 Open a console window (DOS box) and 'cd' to the examples directory.29 Open a console window (DOS box) and 'cd' to the examples directory.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t