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 | 1207 | s = table_ident[t - TOK_IDENT]->str; |
| 1208 | 1208 | if (s[0] != '%') |
| 1209 | 1209 | return -1; |
| 1210 | − t = tok_alloc(s+1, strlen(s)-1)->tok; | |
| 1210 | + t = tok_alloc_const(s + 1); | |
| 1211 | 1211 | unget_tok(t); |
| 1212 | 1212 | unget_tok('%'); |
| 1213 | 1213 | parse_operand(tcc_state, &op); |
| @@ -1488,7 +1488,7 @@ ST_FUNC void subst_asm_operand(CString *add_str, · 274 unmodified lines | ||
| 1488 | 1488 | in the C symbol table when later looking up |
| 1489 | 1489 | this name. So enter them now into the asm label |
| 1490 | 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 | 1493 | if (tcc_state->leading_underscore) |
| 1494 | 1494 | cstr_ccat(add_str, '_'); |
| @@ -1698,7 +1698,6 @@ ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands, · 203 unmodified lines | ||
| 1698 | 1698 | ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str) |
| 1699 | 1699 | { |
| 1700 | 1700 | int reg; |
| 1701 | − TokenSym *ts; | |
| 1702 | 1701 | #ifdef TCC_TARGET_X86_64 |
| 1703 | 1702 | unsigned int type; |
| 1704 | 1703 | #endif |
| @@ -1707,8 +1706,7 @@ ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str) · 2 unmodified lines | ||
| 1707 | 1706 | !strcmp(str, "cc") || |
| 1708 | 1707 | !strcmp(str, "flags")) |
| 1709 | 1708 | return; |
| 1710 | − ts = tok_alloc(str, strlen(str)); | |
| 1711 | − reg = ts->tok; | |
| 1709 | + reg = tok_alloc_const(str); | |
| 1712 | 1710 | if (reg >= TOK_ASM_eax && reg <= TOK_ASM_edi) { |
| 1713 | 1711 | reg -= TOK_ASM_eax; |
| 1714 | 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 | 423 | size = (size + 3) & ~3; |
| 424 | 424 | /* allocate the necessary size on stack */ |
| 425 | 425 | #ifdef TCC_TARGET_PE |
| 426 | − if (size >= 0x4096) { | |
| 427 | − /* cannot call alloca with bound checking. Do stack probing. */ | |
| 428 | − o(0x50); // push %eax | |
| 429 | − oad(0xb8, size - 4); // mov size-4,%eax | |
| 430 | − oad(0x3d, 4096); // p1: cmp $4096,%eax | |
| 431 | − o(0x1476); // jbe <p2> | |
| 432 | − oad(0x248485,-4096); // test %eax,-4096(%esp) | |
| 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 | − } | |
| 426 | + if (size >= 4096) { | |
| 427 | + r = get_reg(RC_EAX); | |
| 428 | + oad(0x68, size); // push size | |
| 429 | + /* cannot call normal 'alloca' with bound checking */ | |
| 430 | + gen_static_call(tok_alloc_const("__alloca")); | |
| 431 | + gadd_sp(4); | |
| 432 | + } else | |
| 440 | 433 | #endif |
| 441 | − oad(0xec81, size); /* sub $xxx, %esp */ | |
| 442 | − /* generate structure store */ | |
| 443 | − r = get_reg(RC_INT); | |
| 444 | − o(0x89); /* mov %esp, r */ | |
| 445 | − o(0xe0 + r); | |
| 434 | + { | |
| 435 | + oad(0xec81, size); /* sub $xxx, %esp */ | |
| 436 | + /* generate structure store */ | |
| 437 | + r = get_reg(RC_INT); | |
| 438 | + o(0xe089 + (r << 8)); /* mov %esp, r */ | |
| 439 | + } | |
| 446 | 440 | vset(&vtop->type, r | VT_LVAL, 0); |
| 447 | 441 | vswap(); |
| 448 | 442 | vstore(); |
| @@ -844,6 +838,12 @@ ST_FUNC void gen_opf(int op) · 395 unmodified lines | ||
| 844 | 838 | { |
| 845 | 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 | 847 | /* convert constants to memory references */ |
| 848 | 848 | if ((vtop[-1].r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { |
| 849 | 849 | vswap(); |
| @@ -7,30 +7,30 @@ · 6 unmodified lines | ||
| 7 | 7 | # define _(s) s |
| 8 | 8 | #endif |
| 9 | 9 | |
| 10 | −.globl _(alloca) | |
| 10 | +.globl _(alloca), _(__alloca) | |
| 11 | 11 | _(alloca): |
| 12 | − pop %edx | |
| 13 | − pop %eax | |
| 12 | +_(__alloca): | |
| 13 | + push %ebp | |
| 14 | + mov %esp,%ebp | |
| 15 | + mov 8(%ebp),%eax | |
| 14 | 16 | add $3,%eax |
| 15 | 17 | and $-4,%eax |
| 16 | − jz p3 | |
| 17 | − | |
| 18 | 18 | #ifdef _WIN32 |
| 19 | + jmp .+16 #p2 | |
| 19 | 20 | p1: |
| 20 | − cmp $4096,%eax | |
| 21 | − jbe p2 | |
| 22 | − test %eax,-4096(%esp) | |
| 23 | 21 | sub $4096,%esp |
| 24 | 22 | sub $4096,%eax |
| 25 | − jmp p1 | |
| 23 | + test %eax,(%esp) | |
| 26 | 24 | p2: |
| 25 | + cmp $4096,%eax | |
| 26 | + jae p1 | |
| 27 | 27 | #endif |
| 28 | − | |
| 29 | 28 | sub %eax,%esp |
| 30 | − mov %esp,%eax | |
| 31 | −p3: | |
| 32 | − push %edx | |
| 33 | − push %edx | |
| 29 | + mov 4(%ebp),%eax | |
| 30 | + mov 0(%ebp),%ebp | |
| 31 | + add $8,%esp | |
| 32 | + push %eax | |
| 33 | + lea 8(%esp),%eax | |
| 34 | 34 | ret |
| 35 | 35 | |
| 36 | 36 | /* ---------------------------------------------- */ |
| @@ -625,3 +625,9 @@ long long __fixxfdi (long double a1) · 624 unmodified lines | ||
| 625 | 625 | return s ? ret : -ret; |
| 626 | 626 | } |
| 627 | 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 | 1090 | #define TOK_SHL '<' /* shift left */ |
| 1091 | 1091 | #define TOK_SAR '>' /* signed shift right */ |
| 1092 | 1092 | #define TOK_SHR 0x8b /* unsigned shift right */ |
| 1093 | +#define TOK_NEG TOK_MID /* unary minus operation (for floats) */ | |
| 1093 | 1094 | |
| 1094 | 1095 | #define TOK_ARROW 0xa0 /* -> */ |
| 1095 | 1096 | #define TOK_DOTS 0xa1 /* three dots */ |
| @@ -1378,6 +1379,7 @@ ST_DATA TokenSym **table_ident; · 282 unmodified lines | ||
| 1378 | 1379 | #define IS_NUM 4 |
| 1379 | 1380 | |
| 1380 | 1381 | ST_FUNC TokenSym *tok_alloc(const char *str, int len); |
| 1382 | +ST_FUNC int tok_alloc_const(const char *str); | |
| 1381 | 1383 | ST_FUNC const char *get_tok_str(int v, CValue *cv); |
| 1382 | 1384 | ST_FUNC void begin_macro(TokenString *str, int alloc); |
| 1383 | 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 | 27 | ST_FUNC int asm_get_local_label_name(TCCState *s1, unsigned int n) |
| 28 | 28 | { |
| 29 | 29 | char buf[64]; |
| 30 | − TokenSym *ts; | |
| 31 | − | |
| 32 | 30 | snprintf(buf, sizeof(buf), "L..%u", n); |
| 33 | − ts = tok_alloc(buf, strlen(buf)); | |
| 34 | − return ts->tok; | |
| 31 | + return tok_alloc_const(buf); | |
| 35 | 32 | } |
| 36 | 33 | |
| 37 | 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 | 51 | if (!name) |
| 55 | 52 | return v; |
| 56 | 53 | if (name[0] == '_') { |
| 57 | − v = tok_alloc(name + 1, strlen(name) - 1)->tok; | |
| 54 | + v = tok_alloc_const(name + 1); | |
| 58 | 55 | } else if (!strchr(name, '.')) { |
| 59 | − int n = strlen(name) + 2; | |
| 60 | 56 | char newname[256]; |
| 61 | 57 | snprintf(newname, sizeof newname, ".%s", name); |
| 62 | − v = tok_alloc(newname, n - 1)->tok; | |
| 58 | + v = tok_alloc_const(newname); | |
| 63 | 59 | *addeddot = 1; |
| 64 | 60 | } |
| 65 | 61 | return v; |
| @@ -111,11 +107,10 @@ ST_FUNC Sym* get_asm_sym(int name, Sym *csym) · 45 unmodified lines | ||
| 111 | 107 | |
| 112 | 108 | static Sym* asm_section_sym(TCCState *s1, Section *sec) |
| 113 | 109 | { |
| 114 | − char buf[100]; | |
| 115 | − int label = tok_alloc(buf, | |
| 116 | − snprintf(buf, sizeof buf, "L.%s", sec->name) | |
| 117 | − )->tok; | |
| 118 | − Sym *sym = asm_label_find(label); | |
| 110 | + char buf[100]; int label; Sym *sym; | |
| 111 | + snprintf(buf, sizeof buf, "L.%s", sec->name); | |
| 112 | + label = tok_alloc_const(buf); | |
| 113 | + sym = asm_label_find(label); | |
| 119 | 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 | 2512 | int i, ret, phnum, phfill, shnum, file_type, file_offset, *sec_order; |
| 2513 | 2513 | struct dyn_inf dyninf = {0}; |
| 2514 | − struct ro_inf roinf, *roinf_use = &roinf; | |
| 2514 | + struct ro_inf roinf; | |
| 2515 | 2515 | ElfW(Phdr) *phdr; |
| 2516 | 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 | 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 | 2651 | #if !TARGETOS_FreeBSD && !TARGETOS_NetBSD && !defined(__APPLE__) && !defined(_WIN32) |
| 2649 | 2652 | /* GNU_RELRO */ |
| 2650 | 2653 | if (file_type != TCC_OUTPUT_OBJ) |
| 2651 | − phnum++; | |
| 2652 | − else | |
| 2654 | + phnum++, roinf_use = &roinf; | |
| 2653 | 2655 | #endif |
| 2654 | − roinf_use = NULL; | |
| 2655 | 2656 | |
| 2656 | 2657 | /* allocate program segment headers */ |
| 2657 | 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 | 2820 | /* generate a floating point operation with constant propagation */ |
| 2794 | 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 | 2831 | v1 = vtop - 1; |
| 2805 | 2832 | v2 = vtop; |
| 2833 | + if (op == TOK_NEG) | |
| 2834 | + v1 = v2; | |
| 2835 | + | |
| 2806 | 2836 | /* currently, we cannot do computations with forward symbols */ |
| 2807 | 2837 | c1 = (v1->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
| 2808 | 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 | 2847 | f1 = v1->c.ld; |
| 2818 | 2848 | f2 = v2->c.ld; |
| 2819 | 2849 | } |
| 2820 | − | |
| 2821 | 2850 | /* NOTE: we only do constant propagation if finite number (not |
| 2822 | 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 | 2853 | goto general_case; |
| 2825 | − | |
| 2826 | 2854 | switch(op) { |
| 2827 | 2855 | case '+': f1 += f2; break; |
| 2828 | 2856 | case '-': f1 -= f2; break; |
| 2829 | 2857 | case '*': f1 *= f2; break; |
| 2830 | 2858 | case '/': |
| 2831 | 2859 | if (f2 == 0.0) { |
| 2860 | + union { float f; unsigned u; } x1, x2, y; | |
| 2832 | 2861 | /* If not in initializer we need to potentially generate |
| 2833 | 2862 | FP exceptions at runtime, otherwise we want to fold. */ |
| 2834 | 2863 | if (!const_wanted) |
| 2835 | 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 | 2877 | break; |
| 2878 | + case TOK_NEG: | |
| 2879 | + f1 = -f1; | |
| 2880 | + goto unary_result; | |
| 2839 | 2881 | /* XXX: also handles tests ? */ |
| 2840 | 2882 | default: |
| 2841 | 2883 | goto general_case; |
| 2842 | 2884 | } |
| 2885 | + vtop--; | |
| 2886 | + unary_result: | |
| 2843 | 2887 | /* XXX: overflow test ? */ |
| 2844 | 2888 | if (v1->type.t == VT_FLOAT) { |
| 2845 | 2889 | v1->c.f = f1; |
| @@ -2848,10 +2892,13 @@ static void gen_opif(int op) · 2 unmodified lines | ||
| 2848 | 2892 | } else { |
| 2849 | 2893 | v1->c.ld = f1; |
| 2850 | 2894 | } |
| 2851 | − vtop--; | |
| 2852 | 2895 | } else { |
| 2853 | 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 | 5925 | case '-': |
| 5879 | 5926 | next(); |
| 5880 | 5927 | unary(); |
| 5881 | − t = vtop->type.t & VT_BTYPE; | |
| 5882 | − if (is_float(t)) { | |
| 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 | − } | |
| 5928 | + if (is_float(vtop->type.t)) { | |
| 5929 | + gen_opif(TOK_NEG); | |
| 5919 | 5930 | } else { |
| 5920 | 5931 | vpushi(0); |
| 5921 | 5932 | vswap(); |
| @@ -487,6 +487,12 @@ ST_FUNC TokenSym *tok_alloc(const char *str, int len) · 486 unmodified lines | ||
| 487 | 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 | 496 | /* XXX: buffer overflow */ |
| 491 | 497 | /* XXX: float tokens */ |
| 492 | 498 | ST_FUNC const char *get_tok_str(int v, CValue *cv) |
| @@ -100,6 +100,8 @@ · 99 unmodified lines | ||
| 100 | 100 | DEF(TOK___NAN__, "__nan__") |
| 101 | 101 | DEF(TOK___SNAN__, "__snan__") |
| 102 | 102 | DEF(TOK___INF__, "__inf__") |
| 103 | + DEF(TOK___mzerosf, "__mzerosf") | |
| 104 | + DEF(TOK___mzerodf, "__mzerodf") | |
| 103 | 105 | |
| 104 | 106 | /* attribute identifiers */ |
| 105 | 107 | /* XXX: handle all tokens generically since speed is not critical */ |
| @@ -1813,14 +1813,38 @@ void gen_opl(int op) · 1812 unmodified lines | ||
| 1813 | 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 | 1823 | /* generate a floating point operation 'v = t1 op t2' instruction. The |
| 1817 | 1824 | two operands are guaranteed to have the same floating point type */ |
| 1818 | 1825 | /* XXX: need to use ST1 too */ |
| 1819 | 1826 | void gen_opf(int op) |
| 1820 | 1827 | { |
| 1821 | 1828 | int a, ft, fc, swapped, r; |
| 1822 | − int float_type = | |
| 1823 | − (vtop->type.t & VT_BTYPE) == VT_LDOUBLE ? RC_ST0 : RC_FLOAT; | |
| 1829 | + int bt = vtop->type.t & VT_BTYPE; | |
| 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 | 1849 | /* convert constants to memory references */ |
| 1826 | 1850 | if ((vtop[-1].r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { |