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
338338 }
339339 }
340340
341+static 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+
341350 /* 'is_jmp' is '1' if it is a jump */
342351 static void gcall_or_jmp(int is_jmp)
343352 {
@@ -570,6 +579,12 @@ ST_FUNC void gfunc_prolog(CType *func_type) · 226 unmodified lines
570579 func_bound_offset = lbounds_section->data_offset;
571580 }
572581 #endif
582+
583+#ifndef TCC_TARGET_PE
584+ if (0 == strcmp(funcname, "main"))
585+ gen_static_call(TOK___tcc_fpinit);
586+#endif
587+
573588 }
574589
575590 /* generate function epilog */
@@ -582,7 +597,7 @@ ST_FUNC void gfunc_epilog(void) · 6 unmodified lines
582597 && func_bound_offset != lbounds_section->data_offset) {
583598 int saved_ind;
584599 int *bounds_ptr;
585− Sym *sym, *sym_data;
600+ Sym *sym_data;
586601 /* add end of table info */
587602 bounds_ptr = section_ptr_add(lbounds_section, sizeof(int));
588603 *bounds_ptr = 0;
@@ -594,20 +609,16 @@ ST_FUNC void gfunc_epilog(void) · 5 unmodified lines
594609 greloc(cur_text_section, sym_data,
595610 ind + 1, R_386_32);
596611 oad(0xb8, 0); /* mov %eax, xxx */
597− sym = external_global_sym(TOK___bound_local_new, &func_old_type, 0);
598− greloc(cur_text_section, sym,
599− ind + 1, R_386_PC32);
600− oad(0xe8, -4);
612+ gen_static_call(TOK___bound_local_new);
613+
601614 ind = saved_ind;
602615 /* generate bound check local freeing */
603616 o(0x5250); /* save returned value, if any */
604617 greloc(cur_text_section, sym_data,
605618 ind + 1, R_386_32);
606619 oad(0xb8, 0); /* mov %eax, xxx */
607− sym = external_global_sym(TOK___bound_local_delete, &func_old_type, 0);
608− greloc(cur_text_section, sym,
609− ind + 1, R_386_PC32);
610− oad(0xe8, -4);
620+ gen_static_call(TOK___bound_local_delete);
621+
611622 o(0x585a); /* restore returned value, if any */
612623 }
613624 #endif
@@ -626,10 +637,8 @@ ST_FUNC void gfunc_epilog(void) · 12 unmodified lines
626637 ind = func_sub_sp_offset - FUNC_PROLOG_SIZE;
627638 #ifdef TCC_TARGET_PE
628639 if (v >= 4096) {
629− Sym *sym = external_global_sym(TOK___chkstk, &func_old_type, 0);
630640 oad(0xb8, v); /* mov stacksize, %eax */
631− oad(0xe8, -4); /* call __chkstk, (does the stackframe too) */
632− greloc(cur_text_section, sym, ind-4, R_386_PC32);
641+ gen_static_call(TOK___chkstk); /* call __chkstk, (does the stackframe too) */
633642 } else
634643 #endif
635644 {
@@ -992,52 +1001,13 @@ ST_FUNC void gen_cvt_itof(int t) · 356 unmodified lines
9921001 /* XXX: handle long long case */
9931002 ST_FUNC void gen_cvt_ftoi(int t)
9941003 {
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−
10021004 gv(RC_FLOAT);
1003− if (t != VT_INT)
1004− size = 8;
1005− else
1006− size = 4;
1007−
1008− o(0x2dd9); /* ldcw xxx */
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;
1005+ save_reg(TREG_EAX);
1006+ save_reg(TREG_EDX);
1007+ gen_static_call(TOK___tcc_cvt_ftol);
1008+ vtop->r = TREG_EAX; /* mark reg as used */
1009+ if (t == VT_LLONG)
1010+ vtop->r2 = TREG_EDX;
10411011 }
10421012
10431013 /* convert from one floating point type to another */
@@ -1060,18 +1030,13 @@ ST_FUNC void ggoto(void) · 16 unmodified lines
10601030 /* generate a bounded pointer addition */
10611031 ST_FUNC void gen_bounded_ptr_add(void)
10621032 {
1063− Sym *sym;
1064−
10651033 /* prepare fast i386 function call (args in eax and edx) */
10661034 gv2(RC_EAX, RC_EDX);
10671035 /* save all temporary registers */
10681036 vtop -= 2;
10691037 save_regs(0);
10701038 /* do a fast function call */
1071− sym = external_global_sym(TOK___bound_ptr_add, &func_old_type, 0);
1072− greloc(cur_text_section, sym,
1073− ind + 1, R_386_PC32);
1074− oad(0xe8, -4);
1039+ gen_static_call(TOK___bound_ptr_add);
10751040 /* returned pointer is in eax */
10761041 vtop++;
10771042 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
478478 #endif
479479 }
480480
481−#if defined(__i386__)
482−/* FPU control word for rounding to nearest mode */
483−unsigned short __tcc_fpu_control = 0x137f;
484−/* FPU control word for round to zero mode for int conversion */
485−unsigned short __tcc_int_fpu_control = 0x137f | 0x0c00;
481+#ifndef _WIN32
482+void __tcc_fpinit(void)
483+{
484+ unsigned c = 0x137F;
485+ __asm__ __volatile__ ("fldcw %0" : "=m" (c));
486+}
486487 #endif
487−
488+long 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+}
488499 #endif /* !__x86_64__ */
489500
490501 /* 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
7878 #endif
7979
8080 /********************************************************/
81−
8281 #ifdef _WIN32
83−// GCC appears to use '/' for relative paths and '\\' for absolute paths on Windows
8482 static char *normalize_slashes(char *path)
8583 {
8684 char *p;
87− if (path[1] == ':') {
88− for (p = path+2; *p; ++p)
89− if (*p == '/')
90− *p = '\\';
91− } else {
92− for (p = path; *p; ++p)
93− if (*p == '\\')
94− *p = '/';
95− }
85+ for (p = path; *p; ++p)
86+ if (*p == '\\')
87+ *p = '/';
9688 return path;
9789 }
9890
@@ -1036,6 +1028,7 @@ LIBTCCAPI TCCState *tcc_new(void) · 937 unmodified lines
10361028 #ifdef TCC_TARGET_I386
10371029 s->seg_size = 32;
10381030 #endif
1031+ s->runtime_main = "main";
10391032 return s;
10401033 }
10411034
tcc.h+1−0
@@ -665,6 +665,7 @@ struct TCCState { · 664 unmodified lines
665665 #endif
666666
667667 #ifdef TCC_IS_NATIVE
668+ const char *runtime_main;
668669 /* for tcc_relocate */
669670 void *runtime_mem;
670671 # 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
17261726 static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
17271727 {
17281728 const char *start_symbol;
1729− ADDR3264 addr = 0;
17301729 int pe_type = 0;
17311730
17321731 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
17421741
17431742 start_symbol =
17441743 TCC_OUTPUT_MEMORY == s1->output_type
1745− ? PE_GUI == pe_type ? "__runwinmain" : "_main"
1744+ ? PE_GUI == pe_type ? "__runwinmain" : "__runmain"
17461745 : PE_DLL == pe_type ? PE_STDSYM("__dllstart","@12")
17471746 : PE_GUI == pe_type ? "__winstart" : "__start"
17481747 ;
17491748
1750− if (!s1->leading_underscore || strchr(start_symbol, '@')) {
1749+ if (!s1->leading_underscore || strchr(start_symbol, '@'))
17511750 ++start_symbol;
1752− if (start_symbol[0] != '_')
1753− start_symbol = NULL;
1754− }
17551751
17561752 /* grab the startup code from libtcc1 */
17571753 if (start_symbol)
@@ -1776,21 +1772,13 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe) · 18 unmodified lines
17761772 }
17771773 }
17781774
1779− if (TCC_OUTPUT_MEMORY == s1->output_type)
1775+ if (TCC_OUTPUT_MEMORY == s1->output_type) {
17801776 pe_type = PE_RUN;
1781−
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");
1777+ s1->runtime_main = start_symbol;
17901778 }
17911779
17921780 pe->type = pe_type;
1793− pe->start_addr = addr;
1781+ pe->start_addr = (DWORD)tcc_get_symbol_err(s1, start_symbol);
17941782 }
17951783
17961784 ST_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
9797 if (tcc_relocate(s1, TCC_RELOCATE_AUTO) < 0)
9898 return -1;
9999
100− prog_main = tcc_get_symbol_err(s1, "main");
100+ prog_main = tcc_get_symbol_err(s1, s1->runtime_main);
101101
102102 #ifdef CONFIG_TCC_BACKTRACE
103103 if (s1->do_debug) {
tcctok.h+2−2
@@ -194,8 +194,8 @@ · 193 unmodified lines
194194 DEF(TOK__remu, "_remu")
195195 #endif
196196 #ifdef TCC_TARGET_I386
197− DEF(TOK___tcc_int_fpu_control, "__tcc_int_fpu_control")
198− DEF(TOK___tcc_fpu_control, "__tcc_fpu_control")
197+ DEF(TOK___tcc_fpinit, "__tcc_fpinit")
198+ DEF(TOK___tcc_cvt_ftol, "__tcc_cvt_ftol")
199199 #endif
200200 #ifdef TCC_ARM_EABI
201201 DEF(TOK___ashrdi3, "__aeabi_lasr")
win32/include/winapi/winbase.h+6−6
@@ -968,15 +968,15 @@ extern "C" { · 967 unmodified lines
968968 LONG64 InterlockedExchangeAdd64(LONG64 volatile *Addend,LONG64 Value);
969969 LONG64 InterlockedCompareExchange64(LONG64 volatile *Destination,LONG64 ExChange,LONG64 Comperand);
970970 #else
971− LONG InterlockedIncrement(LONG volatile *lpAddend);
972− LONG InterlockedDecrement(LONG volatile *lpAddend);
973− LONG InterlockedExchange(LONG volatile *Target,LONG Value);
971+ LONG WINAPI InterlockedIncrement(LONG volatile *lpAddend);
972+ LONG WINAPI InterlockedDecrement(LONG volatile *lpAddend);
973+ LONG WINAPI InterlockedExchange(LONG volatile *Target,LONG Value);
974974
975975 #define InterlockedExchangePointer(Target,Value) (PVOID)InterlockedExchange((PLONG)(Target),(LONG)(Value))
976976
977− LONG InterlockedExchangeAdd(LONG volatile *Addend,LONG Value);
978− LONG InterlockedCompareExchange(LONG volatile *Destination,LONG Exchange,LONG Comperand);
979− LONGLONG InterlockedCompareExchange64(LONGLONG volatile *Destination,LONGLONG Exchange,LONGLONG Comperand);
977+ LONG WINAPI InterlockedExchangeAdd(LONG volatile *Addend,LONG Value);
978+ LONG WINAPI InterlockedCompareExchange(LONG volatile *Destination,LONG Exchange,LONG Comperand);
979+ LONGLONG WINAPI InterlockedCompareExchange64(LONGLONG volatile *Destination,LONGLONG Exchange,LONGLONG Comperand);
980980
981981 __CRT_INLINE LONGLONG InterlockedAnd64 (LONGLONG volatile *Destination,LONGLONG Value) {
982982 LONGLONG Old;
win32/lib/crt1.c+6−0
@@ -31,4 +31,10 @@ int _start(void) · 30 unmodified lines
3131 exit(ret);
3232 }
3333
34+int _runmain(int argc, char **argv)
35+{
36+ _controlfp(0x10000, 0x30000);
37+ return main(argc, argv, NULL);
38+}
39+
3440 // =============================================
win32/lib/wincrt1.c+1−1
@@ -59,6 +59,6 @@ int _runwinmain(int argc, char **argv) · 58 unmodified lines
5959 szCmd = "";
6060 else if (szCmd > p && szCmd[-1] == '\"')
6161 --szCmd;
62+ _controlfp(0x10000, 0x30000);
6263 return WinMain(GetModuleHandle(NULL), NULL, szCmd, SW_SHOWDEFAULT);
6364 }
64−
win32/tcc-win32.txt+6−0
@@ -18,6 +18,12 @@ · 17 unmodified lines
1818 system PATH.
1919
2020
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+
2127 Examples:
2228 ---------
2329 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