for floats (currently only). On x86_64 uses built-in fp constants (in libtcc1.c) to avoid multiple anonymous instances. Also: win32/i386: use __alloca for big struct stack store - use new function int tok_alloc_const(const char*); - change alloca86.S to preserve EDX tccelf.c: fix a warning with 'roinf_use'
Unified · Split
| @@ -1207,7 +1207,7 @@ ST_FUNC int asm_parse_regvar (int t) · 1206 unmodified lines | |||
| 1207 | s = table_ident[t - TOK_IDENT]->str; | 1207 | s = table_ident[t - TOK_IDENT]->str; |
| 1208 | if (s[0] != '%') | 1208 | if (s[0] != '%') |
| 1209 | return -1; | 1209 | return -1; |
| 1210 | t = tok_alloc(s+1, strlen(s)-1)->tok; | 1210 | t = tok_alloc_const(s + 1); |
| 1211 | unget_tok(t); | 1211 | unget_tok(t); |
| 1212 | unget_tok('%'); | 1212 | unget_tok('%'); |
| 1213 | parse_operand(tcc_state, &op); | 1213 | parse_operand(tcc_state, &op); |
| @@ -1488,7 +1488,7 @@ ST_FUNC void subst_asm_operand(CString *add_str, · 274 unmodified lines | |||
| 1488 | in the C symbol table when later looking up | 1488 | in the C symbol table when later looking up |
| 1489 | this name. So enter them now into the asm label | 1489 | this name. So enter them now into the asm label |
| 1490 | list when we still know the symbol. */ | 1490 | list when we still know the symbol. */ |
| 1491 | get_asm_sym(tok_alloc(name, strlen(name))->tok, sv->sym); | 1491 | get_asm_sym(tok_alloc_const(name), sv->sym); |
| 1492 | } | 1492 | } |
| 1493 | if (tcc_state->leading_underscore) | 1493 | if (tcc_state->leading_underscore) |
| 1494 | cstr_ccat(add_str, '_'); | 1494 | cstr_ccat(add_str, '_'); |
| @@ -1698,7 +1698,6 @@ ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands, · 203 unmodified lines | |||
| 1698 | ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str) | 1698 | ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str) |
| 1699 | { | 1699 | { |
| 1700 | int reg; | 1700 | int reg; |
| 1701 | TokenSym *ts; | ||
| 1702 | #ifdef TCC_TARGET_X86_64 | 1701 | #ifdef TCC_TARGET_X86_64 |
| 1703 | unsigned int type; | 1702 | unsigned int type; |
| 1704 | #endif | 1703 | #endif |
| @@ -1707,8 +1706,7 @@ ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str) · 2 unmodified lines | |||
| 1707 | !strcmp(str, "cc") || | 1706 | !strcmp(str, "cc") || |
| 1708 | !strcmp(str, "flags")) | 1707 | !strcmp(str, "flags")) |
| 1709 | return; | 1708 | return; |
| 1710 | ts = tok_alloc(str, strlen(str)); | 1709 | reg = tok_alloc_const(str); |
| 1711 | reg = ts->tok; | ||
| 1712 | if (reg >= TOK_ASM_eax && reg <= TOK_ASM_edi) { | 1710 | if (reg >= TOK_ASM_eax && reg <= TOK_ASM_edi) { |
| 1713 | reg -= TOK_ASM_eax; | 1711 | reg -= TOK_ASM_eax; |
| 1714 | } else if (reg >= TOK_ASM_ax && reg <= TOK_ASM_di) { | 1712 | } else if (reg >= TOK_ASM_ax && reg <= TOK_ASM_di) { |
| @@ -423,26 +423,20 @@ ST_FUNC void gfunc_call(int nb_args) · 422 unmodified lines | |||
| 423 | size = (size + 3) & ~3; | 423 | size = (size + 3) & ~3; |
| 424 | /* allocate the necessary size on stack */ | 424 | /* allocate the necessary size on stack */ |
| 425 | #ifdef TCC_TARGET_PE | 425 | #ifdef TCC_TARGET_PE |
| 426 | if (size >= 0x4096) { | 426 | if (size >= 4096) { |
| 427 | /* cannot call alloca with bound checking. Do stack probing. */ | 427 | r = get_reg(RC_EAX); |
| 428 | o(0x50); // push %eax | 428 | oad(0x68, size); // push size |
| 429 | oad(0xb8, size - 4); // mov size-4,%eax | 429 | /* cannot call normal 'alloca' with bound checking */ |
| 430 | oad(0x3d, 4096); // p1: cmp $4096,%eax | 430 | gen_static_call(tok_alloc_const("__alloca")); |
| 431 | o(0x1476); // jbe <p2> | 431 | gadd_sp(4); |
| 432 | oad(0x248485,-4096); // test %eax,-4096(%esp) | 432 | } else |
| 433 | oad(0xec81, 4096); // sub $4096,%esp | ||
| 434 | oad(0x2d, 4096); // sub $4096,%eax | ||
| 435 | o(0xe5eb); // jmp <p1> | ||
| 436 | o(0xc429); // p2: sub %eax,%esp | ||
| 437 | oad(0xc481, size - 4); // add size-4,%esp | ||
| 438 | o(0x58); // pop %eax | ||
| 439 | } | ||
| 440 | #endif | 433 | #endif |
| 441 | oad(0xec81, size); /* sub $xxx, %esp */ | 434 | { |
| 442 | /* generate structure store */ | 435 | oad(0xec81, size); /* sub $xxx, %esp */ |
| 443 | r = get_reg(RC_INT); | 436 | /* generate structure store */ |
| 444 | o(0x89); /* mov %esp, r */ | 437 | r = get_reg(RC_INT); |
| 445 | o(0xe0 + r); | 438 | o(0xe089 + (r << 8)); /* mov %esp, r */ |
| 439 | } | ||
| 446 | vset(&vtop->type, r | VT_LVAL, 0); | 440 | vset(&vtop->type, r | VT_LVAL, 0); |
| 447 | vswap(); | 441 | vswap(); |
| 448 | vstore(); | 442 | vstore(); |
| @@ -844,6 +838,12 @@ ST_FUNC void gen_opf(int op) · 395 unmodified lines | |||
| 844 | { | 838 | { |
| 845 | int a, ft, fc, swapped, r; | 839 | int a, ft, fc, swapped, r; |
| 846 | 840 | ||
| 841 | if (op == TOK_NEG) { /* unary minus */ | ||
| 842 | gv(RC_FLOAT); | ||
| 843 | o(0xe0d9); /* fchs */ | ||
| 844 | return; | ||
| 845 | } | ||
| 846 | |||
| 847 | /* convert constants to memory references */ | 847 | /* convert constants to memory references */ |
| 848 | if ((vtop[-1].r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { | 848 | if ((vtop[-1].r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { |
| 849 | vswap(); | 849 | vswap(); |
| @@ -7,30 +7,30 @@ · 6 unmodified lines | |||
| 7 | # define _(s) s | 7 | # define _(s) s |
| 8 | #endif | 8 | #endif |
| 9 | 9 | ||
| 10 | .globl _(alloca) | 10 | .globl _(alloca), _(__alloca) |
| 11 | _(alloca): | 11 | _(alloca): |
| 12 | pop %edx | 12 | _(__alloca): |
| 13 | pop %eax | 13 | push %ebp |
| 14 | mov %esp,%ebp | ||
| 15 | mov 8(%ebp),%eax | ||
| 14 | add $3,%eax | 16 | add $3,%eax |
| 15 | and $-4,%eax | 17 | and $-4,%eax |
| 16 | jz p3 | ||
| 17 | |||
| 18 | #ifdef _WIN32 | 18 | #ifdef _WIN32 |
| 19 | jmp .+16 #p2 | ||
| 19 | p1: | 20 | p1: |
| 20 | cmp $4096,%eax | ||
| 21 | jbe p2 | ||
| 22 | test %eax,-4096(%esp) | ||
| 23 | sub $4096,%esp | 21 | sub $4096,%esp |
| 24 | sub $4096,%eax | 22 | sub $4096,%eax |
| 25 | jmp p1 | 23 | test %eax,(%esp) |
| 26 | p2: | 24 | p2: |
| 25 | cmp $4096,%eax | ||
| 26 | jae p1 | ||
| 27 | #endif | 27 | #endif |
| 28 | |||
| 29 | sub %eax,%esp | 28 | sub %eax,%esp |
| 30 | mov %esp,%eax | 29 | mov 4(%ebp),%eax |
| 31 | p3: | 30 | mov 0(%ebp),%ebp |
| 32 | push %edx | 31 | add $8,%esp |
| 33 | push %edx | 32 | push %eax |
| 33 | lea 8(%esp),%eax | ||
| 34 | ret | 34 | ret |
| 35 | 35 | ||
| 36 | /* ---------------------------------------------- */ | 36 | /* ---------------------------------------------- */ |
| @@ -625,3 +625,9 @@ long long __fixxfdi (long double a1) · 624 unmodified lines | |||
| 625 | return s ? ret : -ret; | 625 | return s ? ret : -ret; |
| 626 | } | 626 | } |
| 627 | #endif /* !ARM */ | 627 | #endif /* !ARM */ |
| 628 | |||
| 629 | #if defined __x86_64__ | ||
| 630 | /* float constants used for unary minus operation */ | ||
| 631 | const float __mzerosf = -0.0; | ||
| 632 | const double __mzerodf = -0.0; | ||
| 633 | #endif | ||
| @@ -1090,6 +1090,7 @@ struct filespec { · 1089 unmodified lines | |||
| 1090 | #define TOK_SHL '<' /* shift left */ | 1090 | #define TOK_SHL '<' /* shift left */ |
| 1091 | #define TOK_SAR '>' /* signed shift right */ | 1091 | #define TOK_SAR '>' /* signed shift right */ |
| 1092 | #define TOK_SHR 0x8b /* unsigned shift right */ | 1092 | #define TOK_SHR 0x8b /* unsigned shift right */ |
| 1093 | #define TOK_NEG TOK_MID /* unary minus operation (for floats) */ | ||
| 1093 | 1094 | ||
| 1094 | #define TOK_ARROW 0xa0 /* -> */ | 1095 | #define TOK_ARROW 0xa0 /* -> */ |
| 1095 | #define TOK_DOTS 0xa1 /* three dots */ | 1096 | #define TOK_DOTS 0xa1 /* three dots */ |
| @@ -1378,6 +1379,7 @@ ST_DATA TokenSym **table_ident; · 282 unmodified lines | |||
| 1378 | #define IS_NUM 4 | 1379 | #define IS_NUM 4 |
| 1379 | 1380 | ||
| 1380 | ST_FUNC TokenSym *tok_alloc(const char *str, int len); | 1381 | ST_FUNC TokenSym *tok_alloc(const char *str, int len); |
| 1382 | ST_FUNC int tok_alloc_const(const char *str); | ||
| 1381 | ST_FUNC const char *get_tok_str(int v, CValue *cv); | 1383 | ST_FUNC const char *get_tok_str(int v, CValue *cv); |
| 1382 | ST_FUNC void begin_macro(TokenString *str, int alloc); | 1384 | ST_FUNC void begin_macro(TokenString *str, int alloc); |
| 1383 | ST_FUNC void end_macro(void); | 1385 | ST_FUNC void end_macro(void); |
| @@ -27,11 +27,8 @@ static Section *last_text_section; /* to handle .previous asm directive */ · 26 unmodified lines | |||
| 27 | ST_FUNC int asm_get_local_label_name(TCCState *s1, unsigned int n) | 27 | ST_FUNC int asm_get_local_label_name(TCCState *s1, unsigned int n) |
| 28 | { | 28 | { |
| 29 | char buf[64]; | 29 | char buf[64]; |
| 30 | TokenSym *ts; | ||
| 31 | |||
| 32 | snprintf(buf, sizeof(buf), "L..%u", n); | 30 | snprintf(buf, sizeof(buf), "L..%u", n); |
| 33 | ts = tok_alloc(buf, strlen(buf)); | 31 | return tok_alloc_const(buf); |
| 34 | return ts->tok; | ||
| 35 | } | 32 | } |
| 36 | 33 | ||
| 37 | static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global); | 34 | static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global); |
| @@ -54,12 +51,11 @@ static int asm2cname(int v, int *addeddot) · 16 unmodified lines | |||
| 54 | if (!name) | 51 | if (!name) |
| 55 | return v; | 52 | return v; |
| 56 | if (name[0] == '_') { | 53 | if (name[0] == '_') { |
| 57 | v = tok_alloc(name + 1, strlen(name) - 1)->tok; | 54 | v = tok_alloc_const(name + 1); |
| 58 | } else if (!strchr(name, '.')) { | 55 | } else if (!strchr(name, '.')) { |
| 59 | int n = strlen(name) + 2; | ||
| 60 | char newname[256]; | 56 | char newname[256]; |
| 61 | snprintf(newname, sizeof newname, ".%s", name); | 57 | snprintf(newname, sizeof newname, ".%s", name); |
| 62 | v = tok_alloc(newname, n - 1)->tok; | 58 | v = tok_alloc_const(newname); |
| 63 | *addeddot = 1; | 59 | *addeddot = 1; |
| 64 | } | 60 | } |
| 65 | return v; | 61 | return v; |
| @@ -111,11 +107,10 @@ ST_FUNC Sym* get_asm_sym(int name, Sym *csym) · 45 unmodified lines | |||
| 111 | 107 | ||
| 112 | static Sym* asm_section_sym(TCCState *s1, Section *sec) | 108 | static Sym* asm_section_sym(TCCState *s1, Section *sec) |
| 113 | { | 109 | { |
| 114 | char buf[100]; | 110 | char buf[100]; int label; Sym *sym; |
| 115 | int label = tok_alloc(buf, | 111 | snprintf(buf, sizeof buf, "L.%s", sec->name); |
| 116 | snprintf(buf, sizeof buf, "L.%s", sec->name) | 112 | label = tok_alloc_const(buf); |
| 117 | )->tok; | 113 | sym = asm_label_find(label); |
| 118 | Sym *sym = asm_label_find(label); | ||
| 119 | return sym ? sym : asm_new_label1(s1, label, 1, sec->sh_num, 0); | 114 | return sym ? sym : asm_new_label1(s1, label, 1, sec->sh_num, 0); |
| 120 | } | 115 | } |
| 121 | 116 | ||
| @@ -2511,9 +2511,12 @@ static int elf_output_file(TCCState *s1, const char *filename) · 2510 unmodified lines | |||
| 2511 | { | 2511 | { |
| 2512 | int i, ret, phnum, phfill, shnum, file_type, file_offset, *sec_order; | 2512 | int i, ret, phnum, phfill, shnum, file_type, file_offset, *sec_order; |
| 2513 | struct dyn_inf dyninf = {0}; | 2513 | struct dyn_inf dyninf = {0}; |
| 2514 | struct ro_inf roinf, *roinf_use = &roinf; | 2514 | struct ro_inf roinf; |
| 2515 | ElfW(Phdr) *phdr; | 2515 | ElfW(Phdr) *phdr; |
| 2516 | Section *strsec, *interp, *dynamic, *dynstr, *note = NULL; | 2516 | Section *strsec, *interp, *dynamic, *dynstr, *note = NULL; |
| 2517 | #ifndef ELF_OBJ_ONLY | ||
| 2518 | struct ro_inf *roinf_use = NULL; | ||
| 2519 | #endif | ||
| 2517 | 2520 | ||
| 2518 | file_type = s1->output_type; | 2521 | file_type = s1->output_type; |
| 2519 | 2522 | ||
| @@ -2648,10 +2651,8 @@ static int elf_output_file(TCCState *s1, const char *filename) · 128 unmodified lines | |||
| 2648 | #if !TARGETOS_FreeBSD && !TARGETOS_NetBSD && !defined(__APPLE__) && !defined(_WIN32) | 2651 | #if !TARGETOS_FreeBSD && !TARGETOS_NetBSD && !defined(__APPLE__) && !defined(_WIN32) |
| 2649 | /* GNU_RELRO */ | 2652 | /* GNU_RELRO */ |
| 2650 | if (file_type != TCC_OUTPUT_OBJ) | 2653 | if (file_type != TCC_OUTPUT_OBJ) |
| 2651 | phnum++; | 2654 | phnum++, roinf_use = &roinf; |
| 2652 | else | ||
| 2653 | #endif | 2655 | #endif |
| 2654 | roinf_use = NULL; | ||
| 2655 | 2656 | ||
| 2656 | /* allocate program segment headers */ | 2657 | /* allocate program segment headers */ |
| 2657 | phdr = tcc_mallocz(phnum * sizeof(ElfW(Phdr))); | 2658 | phdr = tcc_mallocz(phnum * sizeof(ElfW(Phdr))); |
| @@ -2790,6 +2790,33 @@ static void gen_opic(int op) · 2789 unmodified lines | |||
| 2790 | } | 2790 | } |
| 2791 | } | 2791 | } |
| 2792 | 2792 | ||
| 2793 | #if defined TCC_TARGET_X86_64 || defined TCC_TARGET_I386 | ||
| 2794 | # define gen_negf gen_opf | ||
| 2795 | #else | ||
| 2796 | /* XXX: implement in gen_opf() for other backends too */ | ||
| 2797 | void gen_negf(int op) | ||
| 2798 | { | ||
| 2799 | /* In IEEE negate(x) isn't subtract(0,x). Without NaNs it's | ||
| 2800 | subtract(-0, x), but with them it's really a sign flip | ||
| 2801 | operation. We implement this with bit manipulation and have | ||
| 2802 | to do some type reinterpretation for this, which TCC can do | ||
| 2803 | only via memory. */ | ||
| 2804 | |||
| 2805 | int align, size, bt; | ||
| 2806 | |||
| 2807 | size = type_size(&vtop->type, &align); | ||
| 2808 | bt = vtop->type.t & VT_BTYPE; | ||
| 2809 | save_reg(gv(RC_TYPE(bt))); | ||
| 2810 | vdup(); | ||
| 2811 | incr_bf_adr(size - 1); | ||
| 2812 | vdup(); | ||
| 2813 | vpushi(0x80); /* flip sign */ | ||
| 2814 | gen_op('^'); | ||
| 2815 | vstore(); | ||
| 2816 | vpop(); | ||
| 2817 | } | ||
| 2818 | #endif | ||
| 2819 | |||
| 2793 | /* generate a floating point operation with constant propagation */ | 2820 | /* generate a floating point operation with constant propagation */ |
| 2794 | static void gen_opif(int op) | 2821 | static void gen_opif(int op) |
| 2795 | { | 2822 | { |
| @@ -2803,6 +2830,9 @@ static void gen_opif(int op) · 7 unmodified lines | |||
| 2803 | 2830 | ||
| 2804 | v1 = vtop - 1; | 2831 | v1 = vtop - 1; |
| 2805 | v2 = vtop; | 2832 | v2 = vtop; |
| 2833 | if (op == TOK_NEG) | ||
| 2834 | v1 = v2; | ||
| 2835 | |||
| 2806 | /* currently, we cannot do computations with forward symbols */ | 2836 | /* currently, we cannot do computations with forward symbols */ |
| 2807 | c1 = (v1->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; | 2837 | c1 = (v1->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
| 2808 | c2 = (v2->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; | 2838 | c2 = (v2->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
| @@ -2817,29 +2847,43 @@ static void gen_opif(int op) · 8 unmodified lines | |||
| 2817 | f1 = v1->c.ld; | 2847 | f1 = v1->c.ld; |
| 2818 | f2 = v2->c.ld; | 2848 | f2 = v2->c.ld; |
| 2819 | } | 2849 | } |
| 2820 | |||
| 2821 | /* NOTE: we only do constant propagation if finite number (not | 2850 | /* NOTE: we only do constant propagation if finite number (not |
| 2822 | NaN or infinity) (ANSI spec) */ | 2851 | NaN or infinity) (ANSI spec) */ |
| 2823 | if (!ieee_finite(f1) || !ieee_finite(f2)) | 2852 | if (!(ieee_finite(f1) || !ieee_finite(f2)) && !const_wanted) |
| 2824 | goto general_case; | 2853 | goto general_case; |
| 2825 | |||
| 2826 | switch(op) { | 2854 | switch(op) { |
| 2827 | case '+': f1 += f2; break; | 2855 | case '+': f1 += f2; break; |
| 2828 | case '-': f1 -= f2; break; | 2856 | case '-': f1 -= f2; break; |
| 2829 | case '*': f1 *= f2; break; | 2857 | case '*': f1 *= f2; break; |
| 2830 | case '/': | 2858 | case '/': |
| 2831 | if (f2 == 0.0) { | 2859 | if (f2 == 0.0) { |
| 2860 | union { float f; unsigned u; } x1, x2, y; | ||
| 2832 | /* If not in initializer we need to potentially generate | 2861 | /* If not in initializer we need to potentially generate |
| 2833 | FP exceptions at runtime, otherwise we want to fold. */ | 2862 | FP exceptions at runtime, otherwise we want to fold. */ |
| 2834 | if (!const_wanted) | 2863 | if (!const_wanted) |
| 2835 | goto general_case; | 2864 | goto general_case; |
| 2865 | /* the run-time result of 0.0/0.0 on x87, also of other compilers | ||
| 2866 | when used to compile the f1 /= f2 below, would be -nan */ | ||
| 2867 | x1.f = f1, x2.f = f2; | ||
| 2868 | if (f1 == 0.0) | ||
| 2869 | y.u = 0x7fc00000; /* nan */ | ||
| 2870 | else | ||
| 2871 | y.u = 0x7f800000; /* infinity */ | ||
| 2872 | y.u |= (x1.u ^ x2.u) & 0x80000000; /* set sign */ | ||
| 2873 | f1 = y.f; | ||
| 2874 | break; | ||
| 2836 | } | 2875 | } |
| 2837 | f1 /= f2; | 2876 | f1 /= f2; |
| 2838 | break; | 2877 | break; |
| 2878 | case TOK_NEG: | ||
| 2879 | f1 = -f1; | ||
| 2880 | goto unary_result; | ||
| 2839 | /* XXX: also handles tests ? */ | 2881 | /* XXX: also handles tests ? */ |
| 2840 | default: | 2882 | default: |
| 2841 | goto general_case; | 2883 | goto general_case; |
| 2842 | } | 2884 | } |
| 2885 | vtop--; | ||
| 2886 | unary_result: | ||
| 2843 | /* XXX: overflow test ? */ | 2887 | /* XXX: overflow test ? */ |
| 2844 | if (v1->type.t == VT_FLOAT) { | 2888 | if (v1->type.t == VT_FLOAT) { |
| 2845 | v1->c.f = f1; | 2889 | v1->c.f = f1; |
| @@ -2848,10 +2892,13 @@ static void gen_opif(int op) · 2 unmodified lines | |||
| 2848 | } else { | 2892 | } else { |
| 2849 | v1->c.ld = f1; | 2893 | v1->c.ld = f1; |
| 2850 | } | 2894 | } |
| 2851 | vtop--; | ||
| 2852 | } else { | 2895 | } else { |
| 2853 | general_case: | 2896 | general_case: |
| 2854 | gen_opf(op); | 2897 | if (op == TOK_NEG) { |
| 2898 | gen_negf(op); | ||
| 2899 | } else { | ||
| 2900 | gen_opf(op); | ||
| 2901 | } | ||
| 2855 | } | 2902 | } |
| 2856 | } | 2903 | } |
| 2857 | 2904 | ||
| @@ -5878,44 +5925,8 @@ ST_FUNC void unary(void) · 3020 unmodified lines | |||
| 5878 | case '-': | 5925 | case '-': |
| 5879 | next(); | 5926 | next(); |
| 5880 | unary(); | 5927 | unary(); |
| 5881 | t = vtop->type.t & VT_BTYPE; | 5928 | if (is_float(vtop->type.t)) { |
| 5882 | if (is_float(t)) { | 5929 | gen_opif(TOK_NEG); |
| 5883 | if ((vtop->r & VT_VALMASK) == VT_CONST) { | ||
| 5884 | /* This is what gen_opif would do if we had a NEG operation. */ | ||
| 5885 | if (t == VT_FLOAT) | ||
| 5886 | vtop->c.f = -vtop->c.f; | ||
| 5887 | else if (t == VT_DOUBLE) | ||
| 5888 | vtop->c.d = -vtop->c.d; | ||
| 5889 | else | ||
| 5890 | vtop->c.ld = -vtop->c.ld; | ||
| 5891 | } else { | ||
| 5892 | /* In IEEE negate(x) isn't subtract(0,x). Without NaNs it's | ||
| 5893 | subtract(-0, x), but with them it's really a sign flip | ||
| 5894 | operation. We implement this with bit manipulation and have | ||
| 5895 | to do some type reinterpretation for this, which TCC can do | ||
| 5896 | only via memory. */ | ||
| 5897 | int align, size = type_size(&vtop->type, &align); | ||
| 5898 | save_reg(gv(RC_TYPE(t))); | ||
| 5899 | vdup(); | ||
| 5900 | gaddrof(); | ||
| 5901 | vtop->type = char_pointer_type; | ||
| 5902 | /* Byte of sign bit. For big endian, this would have to | ||
| 5903 | add zero always. */ | ||
| 5904 | #if defined(TCC_TARGET_X86_64) || defined(TCC_TARGET_I386) | ||
| 5905 | /* sizeof long double is 12 or 16 here, but it's | ||
| 5906 | really the 80bit extended float format. */ | ||
| 5907 | if (t == VT_LDOUBLE) | ||
| 5908 | size = 10; | ||
| 5909 | #endif | ||
| 5910 | vpushi(size - 1); | ||
| 5911 | gen_op('+'); | ||
| 5912 | indir(); | ||
| 5913 | vdup(); | ||
| 5914 | vpushi(0x80); /* flip sign */ | ||
| 5915 | gen_op('^'); | ||
| 5916 | vstore(); | ||
| 5917 | vpop(); | ||
| 5918 | } | ||
| 5919 | } else { | 5930 | } else { |
| 5920 | vpushi(0); | 5931 | vpushi(0); |
| 5921 | vswap(); | 5932 | vswap(); |
| @@ -487,6 +487,12 @@ ST_FUNC TokenSym *tok_alloc(const char *str, int len) · 486 unmodified lines | |||
| 487 | return tok_alloc_new(pts, str, len); | 487 | return tok_alloc_new(pts, str, len); |
| 488 | } | 488 | } |
| 489 | 489 | ||
| 490 | ST_FUNC int tok_alloc_const(const char *str) | ||
| 491 | { | ||
| 492 | return tok_alloc(str, strlen(str))->tok; | ||
| 493 | } | ||
| 494 | |||
| 495 | |||
| 490 | /* XXX: buffer overflow */ | 496 | /* XXX: buffer overflow */ |
| 491 | /* XXX: float tokens */ | 497 | /* XXX: float tokens */ |
| 492 | ST_FUNC const char *get_tok_str(int v, CValue *cv) | 498 | ST_FUNC const char *get_tok_str(int v, CValue *cv) |
| @@ -100,6 +100,8 @@ · 99 unmodified lines | |||
| 100 | DEF(TOK___NAN__, "__nan__") | 100 | DEF(TOK___NAN__, "__nan__") |
| 101 | DEF(TOK___SNAN__, "__snan__") | 101 | DEF(TOK___SNAN__, "__snan__") |
| 102 | DEF(TOK___INF__, "__inf__") | 102 | DEF(TOK___INF__, "__inf__") |
| 103 | DEF(TOK___mzerosf, "__mzerosf") | ||
| 104 | DEF(TOK___mzerodf, "__mzerodf") | ||
| 103 | 105 | ||
| 104 | /* attribute identifiers */ | 106 | /* attribute identifiers */ |
| 105 | /* XXX: handle all tokens generically since speed is not critical */ | 107 | /* XXX: handle all tokens generically since speed is not critical */ |
| @@ -1813,14 +1813,38 @@ void gen_opl(int op) · 1812 unmodified lines | |||
| 1813 | gen_opi(op); | 1813 | gen_opi(op); |
| 1814 | } | 1814 | } |
| 1815 | 1815 | ||
| 1816 | void vpush_const(int t, int v) | ||
| 1817 | { | ||
| 1818 | CType ctype = { t | VT_CONSTANT, 0 }; | ||
| 1819 | vpushsym(&ctype, external_global_sym(v, &ctype)); | ||
| 1820 | vtop->r |= VT_LVAL; | ||
| 1821 | } | ||
| 1822 | |||
| 1816 | /* generate a floating point operation 'v = t1 op t2' instruction. The | 1823 | /* generate a floating point operation 'v = t1 op t2' instruction. The |
| 1817 | two operands are guaranteed to have the same floating point type */ | 1824 | two operands are guaranteed to have the same floating point type */ |
| 1818 | /* XXX: need to use ST1 too */ | 1825 | /* XXX: need to use ST1 too */ |
| 1819 | void gen_opf(int op) | 1826 | void gen_opf(int op) |
| 1820 | { | 1827 | { |
| 1821 | int a, ft, fc, swapped, r; | 1828 | int a, ft, fc, swapped, r; |
| 1822 | int float_type = | 1829 | int bt = vtop->type.t & VT_BTYPE; |
| 1823 | (vtop->type.t & VT_BTYPE) == VT_LDOUBLE ? RC_ST0 : RC_FLOAT; | 1830 | int float_type = bt == VT_LDOUBLE ? RC_ST0 : RC_FLOAT; |
| 1831 | |||
| 1832 | if (op == TOK_NEG) { /* unary minus */ | ||
| 1833 | gv(float_type); | ||
| 1834 | if (float_type == RC_ST0) { | ||
| 1835 | o(0xe0d9); /* fchs */ | ||
| 1836 | } else { | ||
| 1837 | /* -0.0, in libtcc1.c */ | ||
| 1838 | vpush_const(bt, bt == VT_FLOAT ? TOK___mzerosf : TOK___mzerodf); | ||
| 1839 | gv(RC_FLOAT); | ||
| 1840 | if (bt == VT_DOUBLE) | ||
| 1841 | o(0x66); | ||
| 1842 | /* xorp[sd] %xmm1, %xmm0 */ | ||
| 1843 | o(0xc0570f | (REG_VALUE(vtop[0].r) + REG_VALUE(vtop[-1].r)*8) << 16); | ||
| 1844 | vtop--; | ||
| 1845 | } | ||
| 1846 | return; | ||
| 1847 | } | ||
| 1824 | 1848 | ||
| 1825 | /* convert constants to memory references */ | 1849 | /* convert constants to memory references */ |
| 1826 | if ((vtop[-1].r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { | 1850 | if ((vtop[-1].r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { |