- 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
Unified · Split
| @@ -338,6 +338,15 @@ static void gadd_sp(int val) · 337 unmodified lines | ||
| 338 | 338 | } |
| 339 | 339 | } |
| 340 | 340 | |
| 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 | + | |
| 341 | 350 | /* 'is_jmp' is '1' if it is a jump */ |
| 342 | 351 | static 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 | 579 | func_bound_offset = lbounds_section->data_offset; |
| 571 | 580 | } |
| 572 | 581 | #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 | 590 | /* generate function epilog */ |
| @@ -582,7 +597,7 @@ ST_FUNC void gfunc_epilog(void) · 6 unmodified lines | ||
| 582 | 597 | && func_bound_offset != lbounds_section->data_offset) { |
| 583 | 598 | int saved_ind; |
| 584 | 599 | int *bounds_ptr; |
| 585 | − Sym *sym, *sym_data; | |
| 600 | + Sym *sym_data; | |
| 586 | 601 | /* add end of table info */ |
| 587 | 602 | bounds_ptr = section_ptr_add(lbounds_section, sizeof(int)); |
| 588 | 603 | *bounds_ptr = 0; |
| @@ -594,20 +609,16 @@ ST_FUNC void gfunc_epilog(void) · 5 unmodified lines | ||
| 594 | 609 | greloc(cur_text_section, sym_data, |
| 595 | 610 | ind + 1, R_386_32); |
| 596 | 611 | 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 | + | |
| 601 | 614 | ind = saved_ind; |
| 602 | 615 | /* generate bound check local freeing */ |
| 603 | 616 | o(0x5250); /* save returned value, if any */ |
| 604 | 617 | greloc(cur_text_section, sym_data, |
| 605 | 618 | ind + 1, R_386_32); |
| 606 | 619 | 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 | + | |
| 611 | 622 | o(0x585a); /* restore returned value, if any */ |
| 612 | 623 | } |
| 613 | 624 | #endif |
| @@ -626,10 +637,8 @@ ST_FUNC void gfunc_epilog(void) · 12 unmodified lines | ||
| 626 | 637 | ind = func_sub_sp_offset - FUNC_PROLOG_SIZE; |
| 627 | 638 | #ifdef TCC_TARGET_PE |
| 628 | 639 | if (v >= 4096) { |
| 629 | − Sym *sym = external_global_sym(TOK___chkstk, &func_old_type, 0); | |
| 630 | 640 | 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) */ | |
| 633 | 642 | } else |
| 634 | 643 | #endif |
| 635 | 644 | { |
| @@ -992,52 +1001,13 @@ ST_FUNC void gen_cvt_itof(int t) · 356 unmodified lines | ||
| 992 | 1001 | /* XXX: handle long long case */ |
| 993 | 1002 | ST_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 | 1004 | 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; | |
| 1041 | 1011 | } |
| 1042 | 1012 | |
| 1043 | 1013 | /* convert from one floating point type to another */ |
| @@ -1060,18 +1030,13 @@ ST_FUNC void ggoto(void) · 16 unmodified lines | ||
| 1060 | 1030 | /* generate a bounded pointer addition */ |
| 1061 | 1031 | ST_FUNC void gen_bounded_ptr_add(void) |
| 1062 | 1032 | { |
| 1063 | − Sym *sym; | |
| 1064 | − | |
| 1065 | 1033 | /* prepare fast i386 function call (args in eax and edx) */ |
| 1066 | 1034 | gv2(RC_EAX, RC_EDX); |
| 1067 | 1035 | /* save all temporary registers */ |
| 1068 | 1036 | vtop -= 2; |
| 1069 | 1037 | save_regs(0); |
| 1070 | 1038 | /* 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); | |
| 1075 | 1040 | /* returned pointer is in eax */ |
| 1076 | 1041 | vtop++; |
| 1077 | 1042 | vtop->r = TREG_EAX | VT_BOUNDED; |
| @@ -478,13 +478,24 @@ long long __ashldi3(long long a, int b) · 477 unmodified lines | ||
| 478 | 478 | #endif |
| 479 | 479 | } |
| 480 | 480 | |
| 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 | +} | |
| 486 | 487 | #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 | +} | |
| 488 | 499 | #endif /* !__x86_64__ */ |
| 489 | 500 | |
| 490 | 501 | /* XXX: fix tcc's code generator to do this instead */ |
| @@ -78,21 +78,13 @@ ST_FUNC void asm_global_instr(void) · 77 unmodified lines | ||
| 78 | 78 | #endif |
| 79 | 79 | |
| 80 | 80 | /********************************************************/ |
| 81 | − | |
| 82 | 81 | #ifdef _WIN32 |
| 83 | −// GCC appears to use '/' for relative paths and '\\' for absolute paths on Windows | |
| 84 | 82 | static char *normalize_slashes(char *path) |
| 85 | 83 | { |
| 86 | 84 | 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 = '/'; | |
| 96 | 88 | return path; |
| 97 | 89 | } |
| 98 | 90 | |
| @@ -1036,6 +1028,7 @@ LIBTCCAPI TCCState *tcc_new(void) · 937 unmodified lines | ||
| 1036 | 1028 | #ifdef TCC_TARGET_I386 |
| 1037 | 1029 | s->seg_size = 32; |
| 1038 | 1030 | #endif |
| 1031 | + s->runtime_main = "main"; | |
| 1039 | 1032 | return s; |
| 1040 | 1033 | } |
| 1041 | 1034 | |
| @@ -665,6 +665,7 @@ struct TCCState { · 664 unmodified lines | ||
| 665 | 665 | #endif |
| 666 | 666 | |
| 667 | 667 | #ifdef TCC_IS_NATIVE |
| 668 | + const char *runtime_main; | |
| 668 | 669 | /* for tcc_relocate */ |
| 669 | 670 | void *runtime_mem; |
| 670 | 671 | # ifdef HAVE_SELINUX |
| @@ -1726,7 +1726,6 @@ ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack) · 1725 unmodified lines | ||
| 1726 | 1726 | static void pe_add_runtime(TCCState *s1, struct pe_info *pe) |
| 1727 | 1727 | { |
| 1728 | 1728 | const char *start_symbol; |
| 1729 | − ADDR3264 addr = 0; | |
| 1730 | 1729 | int pe_type = 0; |
| 1731 | 1730 | |
| 1732 | 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 | 1742 | start_symbol = |
| 1744 | 1743 | TCC_OUTPUT_MEMORY == s1->output_type |
| 1745 | − ? PE_GUI == pe_type ? "__runwinmain" : "_main" | |
| 1744 | + ? PE_GUI == pe_type ? "__runwinmain" : "__runmain" | |
| 1746 | 1745 | : PE_DLL == pe_type ? PE_STDSYM("__dllstart","@12") |
| 1747 | 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 | 1750 | ++start_symbol; |
| 1752 | − if (start_symbol[0] != '_') | |
| 1753 | − start_symbol = NULL; | |
| 1754 | − } | |
| 1755 | 1751 | |
| 1756 | 1752 | /* grab the startup code from libtcc1 */ |
| 1757 | 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 | 1776 | 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; | |
| 1790 | 1778 | } |
| 1791 | 1779 | |
| 1792 | 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 | |
| 1796 | 1784 | ST_FUNC int pe_output_file(TCCState * s1, const char *filename) |
| @@ -97,7 +97,7 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv) · 96 unmodified lines | ||
| 97 | 97 | if (tcc_relocate(s1, TCC_RELOCATE_AUTO) < 0) |
| 98 | 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 | 102 | #ifdef CONFIG_TCC_BACKTRACE |
| 103 | 103 | if (s1->do_debug) { |
| @@ -194,8 +194,8 @@ · 193 unmodified lines | ||
| 194 | 194 | DEF(TOK__remu, "_remu") |
| 195 | 195 | #endif |
| 196 | 196 | #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") | |
| 199 | 199 | #endif |
| 200 | 200 | #ifdef TCC_ARM_EABI |
| 201 | 201 | DEF(TOK___ashrdi3, "__aeabi_lasr") |
| @@ -968,15 +968,15 @@ extern "C" { · 967 unmodified lines | ||
| 968 | 968 | LONG64 InterlockedExchangeAdd64(LONG64 volatile *Addend,LONG64 Value); |
| 969 | 969 | LONG64 InterlockedCompareExchange64(LONG64 volatile *Destination,LONG64 ExChange,LONG64 Comperand); |
| 970 | 970 | #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); | |
| 974 | 974 | |
| 975 | 975 | #define InterlockedExchangePointer(Target,Value) (PVOID)InterlockedExchange((PLONG)(Target),(LONG)(Value)) |
| 976 | 976 | |
| 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); | |
| 980 | 980 | |
| 981 | 981 | __CRT_INLINE LONGLONG InterlockedAnd64 (LONGLONG volatile *Destination,LONGLONG Value) { |
| 982 | 982 | LONGLONG Old; |
| @@ -31,4 +31,10 @@ int _start(void) · 30 unmodified lines | ||
| 31 | 31 | exit(ret); |
| 32 | 32 | } |
| 33 | 33 | |
| 34 | +int _runmain(int argc, char **argv) | |
| 35 | +{ | |
| 36 | + _controlfp(0x10000, 0x30000); | |
| 37 | + return main(argc, argv, NULL); | |
| 38 | +} | |
| 39 | + | |
| 34 | 40 | // ============================================= |
| @@ -59,6 +59,6 @@ int _runwinmain(int argc, char **argv) · 58 unmodified lines | ||
| 59 | 59 | szCmd = ""; |
| 60 | 60 | else if (szCmd > p && szCmd[-1] == '\"') |
| 61 | 61 | --szCmd; |
| 62 | + _controlfp(0x10000, 0x30000); | |
| 62 | 63 | return WinMain(GetModuleHandle(NULL), NULL, szCmd, SW_SHOWDEFAULT); |
| 63 | 64 | } |
| 64 | − | |
| @@ -18,6 +18,12 @@ · 17 unmodified lines | ||
| 18 | 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 | 27 | Examples: |
| 22 | 28 | --------- |
| 23 | 29 | Open a console window (DOS box) and 'cd' to the examples directory. |