History

tccgen: introduce TOK_NEG for unary minus

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'

grischka committed 5 years ago

Commit aeb8f421 parent a5865fa11 files · +145 −100Browse files

Unified · Split

11 files
  1. i386-asm.c +3 −5
  2. i386-gen.c +19 −19
  3. lib/alloca86.S +14 −14
  4. lib/libtcc1.c +6 −0
  5. tcc.h +2 −0
  6. tccasm.c +7 −12
  7. tccelf.c +5 −4
  8. tccgen.c +55 −44
  9. tccpp.c +6 −0
  10. tcctok.h +2 −0
  11. x86_64-gen.c +26 −2
i386-asm.c+3−5
@@ -1207,7 +1207,7 @@ ST_FUNC int asm_parse_regvar (int t) · 1206 unmodified lines
12071207 s = table_ident[t - TOK_IDENT]->str;
12081208 if (s[0] != '%')
12091209 return -1;
1210− t = tok_alloc(s+1, strlen(s)-1)->tok;
1210+ t = tok_alloc_const(s + 1);
12111211 unget_tok(t);
12121212 unget_tok('%');
12131213 parse_operand(tcc_state, &op);
@@ -1488,7 +1488,7 @@ ST_FUNC void subst_asm_operand(CString *add_str, · 274 unmodified lines
14881488 in the C symbol table when later looking up
14891489 this name. So enter them now into the asm label
14901490 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);
14921492 }
14931493 if (tcc_state->leading_underscore)
14941494 cstr_ccat(add_str, '_');
@@ -1698,7 +1698,6 @@ ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands, · 203 unmodified lines
16981698 ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str)
16991699 {
17001700 int reg;
1701− TokenSym *ts;
17021701 #ifdef TCC_TARGET_X86_64
17031702 unsigned int type;
17041703 #endif
@@ -1707,8 +1706,7 @@ ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str) · 2 unmodified lines
17071706 !strcmp(str, "cc") ||
17081707 !strcmp(str, "flags"))
17091708 return;
1710− ts = tok_alloc(str, strlen(str));
1711− reg = ts->tok;
1709+ reg = tok_alloc_const(str);
17121710 if (reg >= TOK_ASM_eax && reg <= TOK_ASM_edi) {
17131711 reg -= TOK_ASM_eax;
17141712 } else if (reg >= TOK_ASM_ax && reg <= TOK_ASM_di) {
i386-gen.c+19−19
@@ -423,26 +423,20 @@ ST_FUNC void gfunc_call(int nb_args) · 422 unmodified lines
423423 size = (size + 3) & ~3;
424424 /* allocate the necessary size on stack */
425425 #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
440433 #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+ }
446440 vset(&vtop->type, r | VT_LVAL, 0);
447441 vswap();
448442 vstore();
@@ -844,6 +838,12 @@ ST_FUNC void gen_opf(int op) · 395 unmodified lines
844838 {
845839 int a, ft, fc, swapped, r;
846840
841+ if (op == TOK_NEG) { /* unary minus */
842+ gv(RC_FLOAT);
843+ o(0xe0d9); /* fchs */
844+ return;
845+ }
846+
847847 /* convert constants to memory references */
848848 if ((vtop[-1].r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
849849 vswap();
lib/alloca86.S+14−14
@@ -7,30 +7,30 @@ · 6 unmodified lines
77 # define _(s) s
88 #endif
99
10−.globl _(alloca)
10+.globl _(alloca), _(__alloca)
1111 _(alloca):
12− pop %edx
13− pop %eax
12+_(__alloca):
13+ push %ebp
14+ mov %esp,%ebp
15+ mov 8(%ebp),%eax
1416 add $3,%eax
1517 and $-4,%eax
16− jz p3
17−
1818 #ifdef _WIN32
19+ jmp .+16 #p2
1920 p1:
20− cmp $4096,%eax
21− jbe p2
22− test %eax,-4096(%esp)
2321 sub $4096,%esp
2422 sub $4096,%eax
25− jmp p1
23+ test %eax,(%esp)
2624 p2:
25+ cmp $4096,%eax
26+ jae p1
2727 #endif
28−
2928 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
3434 ret
3535
3636 /* ---------------------------------------------- */
lib/libtcc1.c+6−0
@@ -625,3 +625,9 @@ long long __fixxfdi (long double a1) · 624 unmodified lines
625625 return s ? ret : -ret;
626626 }
627627 #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
tcc.h+2−0
@@ -1090,6 +1090,7 @@ struct filespec { · 1089 unmodified lines
10901090 #define TOK_SHL '<' /* shift left */
10911091 #define TOK_SAR '>' /* signed shift right */
10921092 #define TOK_SHR 0x8b /* unsigned shift right */
1093+#define TOK_NEG TOK_MID /* unary minus operation (for floats) */
10931094
10941095 #define TOK_ARROW 0xa0 /* -> */
10951096 #define TOK_DOTS 0xa1 /* three dots */
@@ -1378,6 +1379,7 @@ ST_DATA TokenSym **table_ident; · 282 unmodified lines
13781379 #define IS_NUM 4
13791380
13801381 ST_FUNC TokenSym *tok_alloc(const char *str, int len);
1382+ST_FUNC int tok_alloc_const(const char *str);
13811383 ST_FUNC const char *get_tok_str(int v, CValue *cv);
13821384 ST_FUNC void begin_macro(TokenString *str, int alloc);
13831385 ST_FUNC void end_macro(void);
tccasm.c+7−12
@@ -27,11 +27,8 @@ static Section *last_text_section; /* to handle .previous asm directive */ · 26 unmodified lines
2727 ST_FUNC int asm_get_local_label_name(TCCState *s1, unsigned int n)
2828 {
2929 char buf[64];
30− TokenSym *ts;
31−
3230 snprintf(buf, sizeof(buf), "L..%u", n);
33− ts = tok_alloc(buf, strlen(buf));
34− return ts->tok;
31+ return tok_alloc_const(buf);
3532 }
3633
3734 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
5451 if (!name)
5552 return v;
5653 if (name[0] == '_') {
57− v = tok_alloc(name + 1, strlen(name) - 1)->tok;
54+ v = tok_alloc_const(name + 1);
5855 } else if (!strchr(name, '.')) {
59− int n = strlen(name) + 2;
6056 char newname[256];
6157 snprintf(newname, sizeof newname, ".%s", name);
62− v = tok_alloc(newname, n - 1)->tok;
58+ v = tok_alloc_const(newname);
6359 *addeddot = 1;
6460 }
6561 return v;
@@ -111,11 +107,10 @@ ST_FUNC Sym* get_asm_sym(int name, Sym *csym) · 45 unmodified lines
111107
112108 static Sym* asm_section_sym(TCCState *s1, Section *sec)
113109 {
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);
119114 return sym ? sym : asm_new_label1(s1, label, 1, sec->sh_num, 0);
120115 }
121116
tccelf.c+5−4
@@ -2511,9 +2511,12 @@ static int elf_output_file(TCCState *s1, const char *filename) · 2510 unmodified lines
25112511 {
25122512 int i, ret, phnum, phfill, shnum, file_type, file_offset, *sec_order;
25132513 struct dyn_inf dyninf = {0};
2514− struct ro_inf roinf, *roinf_use = &roinf;
2514+ struct ro_inf roinf;
25152515 ElfW(Phdr) *phdr;
25162516 Section *strsec, *interp, *dynamic, *dynstr, *note = NULL;
2517+#ifndef ELF_OBJ_ONLY
2518+ struct ro_inf *roinf_use = NULL;
2519+#endif
25172520
25182521 file_type = s1->output_type;
25192522
@@ -2648,10 +2651,8 @@ static int elf_output_file(TCCState *s1, const char *filename) · 128 unmodified lines
26482651 #if !TARGETOS_FreeBSD && !TARGETOS_NetBSD && !defined(__APPLE__) && !defined(_WIN32)
26492652 /* GNU_RELRO */
26502653 if (file_type != TCC_OUTPUT_OBJ)
2651− phnum++;
2652− else
2654+ phnum++, roinf_use = &roinf;
26532655 #endif
2654− roinf_use = NULL;
26552656
26562657 /* allocate program segment headers */
26572658 phdr = tcc_mallocz(phnum * sizeof(ElfW(Phdr)));
tccgen.c+55−44
@@ -2790,6 +2790,33 @@ static void gen_opic(int op) · 2789 unmodified lines
27902790 }
27912791 }
27922792
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+
27932820 /* generate a floating point operation with constant propagation */
27942821 static void gen_opif(int op)
27952822 {
@@ -2803,6 +2830,9 @@ static void gen_opif(int op) · 7 unmodified lines
28032830
28042831 v1 = vtop - 1;
28052832 v2 = vtop;
2833+ if (op == TOK_NEG)
2834+ v1 = v2;
2835+
28062836 /* currently, we cannot do computations with forward symbols */
28072837 c1 = (v1->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST;
28082838 c2 = (v2->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST;
@@ -2817,29 +2847,43 @@ static void gen_opif(int op) · 8 unmodified lines
28172847 f1 = v1->c.ld;
28182848 f2 = v2->c.ld;
28192849 }
2820−
28212850 /* NOTE: we only do constant propagation if finite number (not
28222851 NaN or infinity) (ANSI spec) */
2823− if (!ieee_finite(f1) || !ieee_finite(f2))
2852+ if (!(ieee_finite(f1) || !ieee_finite(f2)) && !const_wanted)
28242853 goto general_case;
2825−
28262854 switch(op) {
28272855 case '+': f1 += f2; break;
28282856 case '-': f1 -= f2; break;
28292857 case '*': f1 *= f2; break;
28302858 case '/':
28312859 if (f2 == 0.0) {
2860+ union { float f; unsigned u; } x1, x2, y;
28322861 /* If not in initializer we need to potentially generate
28332862 FP exceptions at runtime, otherwise we want to fold. */
28342863 if (!const_wanted)
28352864 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;
28362875 }
2837− f1 /= f2;
2876+ f1 /= f2;
28382877 break;
2878+ case TOK_NEG:
2879+ f1 = -f1;
2880+ goto unary_result;
28392881 /* XXX: also handles tests ? */
28402882 default:
28412883 goto general_case;
28422884 }
2885+ vtop--;
2886+ unary_result:
28432887 /* XXX: overflow test ? */
28442888 if (v1->type.t == VT_FLOAT) {
28452889 v1->c.f = f1;
@@ -2848,10 +2892,13 @@ static void gen_opif(int op) · 2 unmodified lines
28482892 } else {
28492893 v1->c.ld = f1;
28502894 }
2851− vtop--;
28522895 } else {
28532896 general_case:
2854− gen_opf(op);
2897+ if (op == TOK_NEG) {
2898+ gen_negf(op);
2899+ } else {
2900+ gen_opf(op);
2901+ }
28552902 }
28562903 }
28572904
@@ -5878,44 +5925,8 @@ ST_FUNC void unary(void) · 3020 unmodified lines
58785925 case '-':
58795926 next();
58805927 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);
59195930 } else {
59205931 vpushi(0);
59215932 vswap();
tccpp.c+6−0
@@ -487,6 +487,12 @@ ST_FUNC TokenSym *tok_alloc(const char *str, int len) · 486 unmodified lines
487487 return tok_alloc_new(pts, str, len);
488488 }
489489
490+ST_FUNC int tok_alloc_const(const char *str)
491+{
492+ return tok_alloc(str, strlen(str))->tok;
493+}
494+
495+
490496 /* XXX: buffer overflow */
491497 /* XXX: float tokens */
492498 ST_FUNC const char *get_tok_str(int v, CValue *cv)
tcctok.h+2−0
@@ -100,6 +100,8 @@ · 99 unmodified lines
100100 DEF(TOK___NAN__, "__nan__")
101101 DEF(TOK___SNAN__, "__snan__")
102102 DEF(TOK___INF__, "__inf__")
103+ DEF(TOK___mzerosf, "__mzerosf")
104+ DEF(TOK___mzerodf, "__mzerodf")
103105
104106 /* attribute identifiers */
105107 /* XXX: handle all tokens generically since speed is not critical */
x86_64-gen.c+26−2
@@ -1813,14 +1813,38 @@ void gen_opl(int op) · 1812 unmodified lines
18131813 gen_opi(op);
18141814 }
18151815
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+
18161823 /* generate a floating point operation 'v = t1 op t2' instruction. The
18171824 two operands are guaranteed to have the same floating point type */
18181825 /* XXX: need to use ST1 too */
18191826 void gen_opf(int op)
18201827 {
18211828 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+ }
18241848
18251849 /* convert constants to memory references */
18261850 if ((vtop[-1].r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {

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