Skip to content

Commit 923fba8

Browse files
author
grischka
committed
general: long double issues
tccgen.c: - init_putv(): improve long double cross constants now in separate function including some basic conversions arm-gen.c: - switch to using TCC_USING_DOUBLE_FOR_LDOUBLE now it actually never will see VT_LDOUBLE lib/lib-arm64.c: - simplify by using unions tccpp.c: - reduce amounts of #ifdef TCC_USING_DOUBLE_FOR_LDOUBLE
1 parent 7e01b20 commit 923fba8

4 files changed

Lines changed: 93 additions & 108 deletions

File tree

arm-gen.c

Lines changed: 22 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,10 @@ enum {
124124
#define LDOUBLE_ALIGN 4
125125
#endif
126126

127+
#if LDOUBLE_SIZE == 8
128+
# define TCC_USING_DOUBLE_FOR_LDOUBLE 1
129+
#endif
130+
127131
/* maximum alignment (for aligned attribute support) */
128132
#define MAX_ALIGN 8
129133

@@ -635,12 +639,9 @@ void load(int r, SValue *sv)
635639
op=0xED100100;
636640
if(!sign)
637641
op|=0x800000;
638-
#if LDOUBLE_SIZE == 8
639-
if ((ft & VT_BTYPE) != VT_FLOAT)
640-
op|=0x8000;
641-
#else
642642
if ((ft & VT_BTYPE) == VT_DOUBLE)
643643
op|=0x8000;
644+
#if LDOUBLE_SIZE != 8
644645
else if ((ft & VT_BTYPE) == VT_LDOUBLE)
645646
op|=0x400000;
646647
#endif
@@ -760,13 +761,10 @@ void store(int r, SValue *sv)
760761
op=0xED000100;
761762
if(!sign)
762763
op|=0x800000;
763-
#if LDOUBLE_SIZE == 8
764-
if ((ft & VT_BTYPE) != VT_FLOAT)
765-
op|=0x8000;
766-
#else
767764
if ((ft & VT_BTYPE) == VT_DOUBLE)
768765
op|=0x8000;
769-
if ((ft & VT_BTYPE) == VT_LDOUBLE)
766+
#if LDOUBLE_SIZE != 8
767+
else if ((ft & VT_BTYPE) == VT_LDOUBLE)
770768
op|=0x400000;
771769
#endif
772770
o(op|(fpr(r)<<12)|(fc>>2)|(base<<16));
@@ -904,15 +902,6 @@ static void gen_bounds_epilog(void)
904902
}
905903
#endif
906904

907-
static int unalias_ldbl(int btype)
908-
{
909-
#if LDOUBLE_SIZE == 8
910-
if (btype == VT_LDOUBLE)
911-
btype = VT_DOUBLE;
912-
#endif
913-
return btype;
914-
}
915-
916905
/* Return whether a structure is an homogeneous float aggregate or not.
917906
The answer is true if all the elements of the structure are of the same
918907
primitive float type and there is less than 4 elements.
@@ -926,9 +915,10 @@ static int is_hgen_float_aggr(CType *type)
926915

927916
ref = type->ref->next;
928917
if (ref) {
929-
btype = unalias_ldbl(ref->type.t & VT_BTYPE);
918+
btype = ref->type.t & VT_BTYPE;
930919
if (btype == VT_FLOAT || btype == VT_DOUBLE) {
931-
for(; ref && btype == unalias_ldbl(ref->type.t & VT_BTYPE); ref = ref->next, nb_fields++);
920+
for(; ref && btype == (ref->type.t & VT_BTYPE); ref = ref->next, nb_fields++)
921+
;
932922
return !ref && nb_fields <= 4;
933923
}
934924
}
@@ -1254,7 +1244,6 @@ static int copy_params(int nb_args, struct plan *plan, int todo)
12541244
size = 8;
12551245
else
12561246
size = LDOUBLE_SIZE;
1257-
12581247
if (size == 12)
12591248
r |= 0x400000;
12601249
else if(size == 8)
@@ -1946,15 +1935,13 @@ void gen_opf(int op)
19461935
vswap();
19471936
c2 = is_fconst();
19481937
x=0xEE000100;
1949-
#if LDOUBLE_SIZE == 8
1950-
if ((vtop->type.t & VT_BTYPE) != VT_FLOAT)
1951-
x|=0x80;
1952-
#else
19531938
if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE)
19541939
x|=0x80;
1940+
#if LDOUBLE_SIZE != 8
19551941
else if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE)
19561942
x|=0x80000;
19571943
#endif
1944+
19581945
switch(op)
19591946
{
19601947
case '+':
@@ -2190,22 +2177,20 @@ ST_FUNC void gen_cvt_itof(int t)
21902177
func=TOK___floatundisf;
21912178
else
21922179
func=TOK___floatdisf;
2180+
} else if((t & VT_BTYPE) == VT_DOUBLE) {
2181+
func_type = &func_double_type;
2182+
if(vtop->type.t & VT_UNSIGNED)
2183+
func=TOK___floatundidf;
2184+
else
2185+
func=TOK___floatdidf;
21932186
#if LDOUBLE_SIZE != 8
21942187
} else if((t & VT_BTYPE) == VT_LDOUBLE) {
21952188
func_type = &func_ldouble_type;
21962189
if(vtop->type.t & VT_UNSIGNED)
21972190
func=TOK___floatundixf;
21982191
else
21992192
func=TOK___floatdixf;
2200-
} else if((t & VT_BTYPE) == VT_DOUBLE) {
2201-
#else
2202-
} else if((t & VT_BTYPE) == VT_DOUBLE || (t & VT_BTYPE) == VT_LDOUBLE) {
22032193
#endif
2204-
func_type = &func_double_type;
2205-
if(vtop->type.t & VT_UNSIGNED)
2206-
func=TOK___floatundidf;
2207-
else
2208-
func=TOK___floatdidf;
22092194
}
22102195
if(func_type) {
22112196
vpushsym(func_type, external_helper_sym(func));
@@ -2239,14 +2224,12 @@ void gen_cvt_ftoi(int t)
22392224
if(u) {
22402225
if(r2 == VT_FLOAT)
22412226
func=TOK___fixunssfsi;
2227+
else if(r2 == VT_DOUBLE)
2228+
func=TOK___fixunsdfsi;
22422229
#if LDOUBLE_SIZE != 8
22432230
else if(r2 == VT_LDOUBLE)
22442231
func=TOK___fixunsxfsi;
2245-
else if(r2 == VT_DOUBLE)
2246-
#else
2247-
else if(r2 == VT_LDOUBLE || r2 == VT_DOUBLE)
22482232
#endif
2249-
func=TOK___fixunsdfsi;
22502233
} else {
22512234
r=fpr(gv(RC_FLOAT));
22522235
r2=intr(vtop->r=get_reg(RC_INT));
@@ -2257,14 +2240,12 @@ void gen_cvt_ftoi(int t)
22572240
} else if(t == VT_LLONG) { // unsigned handled in gen_cvt_ftoi1
22582241
if(r2 == VT_FLOAT)
22592242
func=TOK___fixsfdi;
2243+
else if(r2 == VT_DOUBLE)
2244+
func=TOK___fixdfdi;
22602245
#if LDOUBLE_SIZE != 8
22612246
else if(r2 == VT_LDOUBLE)
22622247
func=TOK___fixxfdi;
2263-
else if(r2 == VT_DOUBLE)
2264-
#else
2265-
else if(r2 == VT_LDOUBLE || r2 == VT_DOUBLE)
22662248
#endif
2267-
func=TOK___fixdfdi;
22682249
}
22692250
if(func) {
22702251
vpush_helper_func(func);

tccgen.c

Lines changed: 67 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -323,12 +323,6 @@ ST_FUNC int ieee_finite(double d)
323323
return ((unsigned)((p[1] | 0x800fffff) + 1)) >> 31;
324324
}
325325

326-
/* compiling intel long double natively */
327-
#if (defined __i386__ || defined __x86_64__) \
328-
&& (defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64)
329-
# define TCC_IS_NATIVE_387
330-
#endif
331-
332326
ST_FUNC void test_lvalue(void)
333327
{
334328
if (!(vtop->r & VT_LVAL))
@@ -2524,9 +2518,7 @@ void gen_negf(int op)
25242518
operation. We implement this with bit manipulation and have
25252519
to do some type reinterpretation for this, which TCC can do
25262520
only via memory. */
2527-
25282521
int align, size, bt;
2529-
25302522
size = type_size(&vtop->type, &align);
25312523
bt = vtop->type.t & VT_BTYPE;
25322524
#if defined TCC_TARGET_X86_64 || defined TCC_TARGET_I386
@@ -3295,12 +3287,6 @@ static void gen_cast(CType *type)
32953287
}
32963288

32973289
c = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST;
3298-
#if !defined TCC_IS_NATIVE && !defined TCC_IS_NATIVE_387
3299-
/* don't try to convert to ldouble when cross-compiling
3300-
(except when it's '0' which is needed for arm:gen_negf()) */
3301-
if (dbt_bt == VT_LDOUBLE && !nocode_wanted && (sf || vtop->c.i != 0))
3302-
c = 0;
3303-
#endif
33043290
if (c) {
33053291
/* constant case: we can do it now */
33063292
/* XXX: in ISOC, cannot do it if error in convert */
@@ -5646,6 +5632,7 @@ ST_FUNC void unary(void)
56465632
case TOK_CLDOUBLE:
56475633
#ifdef TCC_USING_DOUBLE_FOR_LDOUBLE
56485634
t = VT_DOUBLE | VT_LONG;
5635+
tokc.d = tokc.ld;
56495636
#else
56505637
t = VT_LDOUBLE;
56515638
#endif
@@ -7781,6 +7768,71 @@ static int decl_designator(init_params *p, CType *type, unsigned long c,
77817768
return al;
77827769
}
77837770

7771+
static void write_ldouble(unsigned char *d, void *s)
7772+
{
7773+
//printf("long double %Lf\n", *(long double*)s);
7774+
#ifdef TCC_CROSS_TEST
7775+
if (LDOUBLE_SIZE >= 10) {
7776+
double b = *(long double*)s;
7777+
s = &b;
7778+
#else
7779+
if (sizeof (long double) == 8 && LDOUBLE_SIZE >= 10) {
7780+
#endif
7781+
/* our 'long double' is a double really (_WIN32, __APPLE__) */
7782+
uint64_t m = *(uint64_t*)s;
7783+
int e = m >> 48;
7784+
int f = e >> 4 & 0x7FF;
7785+
m <<= 11;
7786+
if (0 == f) {
7787+
if (0 == m)
7788+
goto set;
7789+
for (f = 1; !(m & 1ULL<<63); --f)
7790+
m <<= 1;
7791+
}
7792+
if (f == 0x7ff)
7793+
f = 0x43FF;
7794+
e = (e & 0x8000) | (f + 0x3C00);
7795+
m |= 1ULL<<63;
7796+
set:
7797+
#if (defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64)
7798+
/* double -> extended */
7799+
write64le(d, m);
7800+
write16le(d+8, e);
7801+
#elif LDOUBLE_SIZE == 16
7802+
/* double -> quad */
7803+
write64le(d+6, m << 1);
7804+
write16le(d+14, e);
7805+
#endif
7806+
;
7807+
} else {
7808+
#if LDOUBLE_SIZE == 8
7809+
/* long double -> double */
7810+
double b = *(long double*)s;
7811+
memcpy(d, &b, 8);
7812+
#elif (__i386__ || __x86_64__) && (defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64)
7813+
/* extended -> extended */
7814+
memcpy(d, s, 10);
7815+
#elif (__i386__ || __x86_64__) && (defined TCC_TARGET_ARM64 || defined TCC_TARGET_RISCV64)
7816+
/* extended -> quad */
7817+
uint64_t m = *(uint64_t*)s;
7818+
int e = *(uint16_t*)((char*)s + 8);
7819+
write64le(d+6, m << 1);
7820+
write16le(d+14, e);
7821+
#elif (__aarch64__ || __riscv) && (defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64)
7822+
/* quad -> extended */
7823+
uint64_t m = read64le((char*)s + 6);
7824+
int e = read16le((char*)s + 14);
7825+
(e & 0x7fff) && (m & 1) && 0 == ++m && ++e;
7826+
write64le(d, m >> 1 | ((e & 0x7fff) ? 1ULL<<63 : 0));
7827+
write16le(d+8, e);
7828+
#else
7829+
/* unknown */
7830+
if (sizeof (long double) == LDOUBLE_SIZE)
7831+
memcpy(d, s, LDOUBLE_SIZE);
7832+
#endif
7833+
}
7834+
}
7835+
77847836
/* store a value or an expression directly in global data or in local array */
77857837
static void init_putv(init_params *p, CType *type, unsigned long c)
77867838
{
@@ -7893,34 +7945,7 @@ static void init_putv(init_params *p, CType *type, unsigned long c)
78937945
write64le(ptr, val);
78947946
break;
78957947
case VT_LDOUBLE:
7896-
#if defined TCC_IS_NATIVE_387
7897-
/* Host and target platform may be different but both have x87.
7898-
On windows, tcc does not use VT_LDOUBLE, except when it is a
7899-
cross compiler. In this case a mingw gcc as host compiler
7900-
comes here with 10-byte long doubles, while msvc or tcc won't.
7901-
tcc itself can still translate by asm.
7902-
In any case we avoid possibly random bytes 11 and 12.
7903-
*/
7904-
if (sizeof (long double) >= 10)
7905-
memcpy(ptr, &vtop->c.ld, 10);
7906-
#ifdef __TINYC__
7907-
else if (sizeof (long double) == sizeof (double))
7908-
__asm__("fldl %1\nfstpt %0\n" : "=m" (*ptr) : "m" (vtop->c.ld));
7909-
#endif
7910-
else
7911-
#endif
7912-
/* For other platforms it should work natively, but may not work
7913-
for cross compilers */
7914-
if (sizeof(long double) == LDOUBLE_SIZE)
7915-
memcpy(ptr, &vtop->c.ld, LDOUBLE_SIZE);
7916-
else if (sizeof(double) == LDOUBLE_SIZE)
7917-
*(double*)ptr = (double)vtop->c.ld;
7918-
else if (0 == memcmp(ptr, &vtop->c.ld, LDOUBLE_SIZE))
7919-
; /* nothing to do for 0.0 */
7920-
#ifndef TCC_CROSS_TEST
7921-
else
7922-
tcc_error("can't cross compile long double constants");
7923-
#endif
7948+
write_ldouble(ptr, &vtop->c.ld);
79247949
break;
79257950

79267951
#if PTR_SIZE == 8

tccpp.c

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2212,13 +2212,8 @@ static void parse_string(const char *s, int len)
22122212
}
22132213
}
22142214

2215-
#ifdef TCC_USING_DOUBLE_FOR_LDOUBLE
2216-
/* we use 64 bit (52 needed) numbers */
2217-
#define BN_SIZE 2
2218-
#else
22192215
/* we use 128 bit (64/112 needed) numbers */
22202216
#define BN_SIZE 4
2221-
#endif
22222217

22232218
/* bn = (bn << shift) | or_val */
22242219
static int bn_lshift(unsigned int *bn, int shift, int or_val)
@@ -2250,11 +2245,7 @@ static void parse_number(const char *p)
22502245
int b, t, shift, frac_bits, s, exp_val, ch;
22512246
char *q;
22522247
unsigned int bn[BN_SIZE];
2253-
#ifdef TCC_USING_DOUBLE_FOR_LDOUBLE
2254-
double d;
2255-
#else
22562248
long double d;
2257-
#endif
22582249

22592250
/* number */
22602251
q = token_buf;
@@ -2366,19 +2357,14 @@ static void parse_number(const char *p)
23662357
ch = *p++;
23672358
}
23682359
exp_val = exp_val * s;
2369-
2360+
23702361
/* now we can generate the number */
23712362
/* XXX: should patch directly float number */
2372-
#ifdef TCC_USING_DOUBLE_FOR_LDOUBLE
2373-
d = (double)bn[1] * 4294967296.0 + (double)bn[0];
2374-
d = ldexp(d, exp_val - frac_bits);
2375-
#else
23762363
d = (long double)bn[3] * 79228162514264337593543950336.0L +
23772364
(long double)bn[2] * 18446744073709551616.0L +
23782365
(long double)bn[1] * 4294967296.0L +
23792366
(long double)bn[0];
23802367
d = ldexpl(d, exp_val - frac_bits);
2381-
#endif
23822368
t = toup(ch);
23832369
if (t == 'F') {
23842370
ch = *p++;
@@ -2388,11 +2374,7 @@ static void parse_number(const char *p)
23882374
} else if (t == 'L') {
23892375
ch = *p++;
23902376
tok = TOK_CLDOUBLE;
2391-
#ifdef TCC_USING_DOUBLE_FOR_LDOUBLE
2392-
tokc.d = d;
2393-
#else
23942377
tokc.ld = d;
2395-
#endif
23962378
} else {
23972379
tok = TOK_CDOUBLE;
23982380
tokc.d = (double)d;
@@ -2442,11 +2424,7 @@ static void parse_number(const char *p)
24422424
} else if (t == 'L') {
24432425
ch = *p++;
24442426
tok = TOK_CLDOUBLE;
2445-
#ifdef TCC_USING_DOUBLE_FOR_LDOUBLE
2446-
tokc.d = strtod(token_buf, NULL);
2447-
#else
24482427
tokc.ld = strtold(token_buf, NULL);
2449-
#endif
24502428
} else {
24512429
tok = TOK_CDOUBLE;
24522430
tokc.d = strtod(token_buf, NULL);

tests/tcctest.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,9 @@
3232
#define XLONG_LONG_FORMAT "%Lx"
3333
#endif
3434

35-
// MinGW has 80-bit rather than 64-bit long double which isn't compatible with TCC or MSVC
36-
#if defined(_WIN32) && defined(__GNUC__)
35+
/* MinGW has 80-bit rather than 64-bit long double which isn't
36+
compatible with printf in msvcrt */
37+
#if defined(_WIN32)
3738
#define LONG_DOUBLE double
3839
#define LONG_DOUBLE_LITERAL(x) x
3940
#else

0 commit comments

Comments
 (0)