diff --git a/hawk/lib/fmt.c b/hawk/lib/fmt.c index 636c759b..bbac54dc 100644 --- a/hawk/lib/fmt.c +++ b/hawk/lib/fmt.c @@ -97,13 +97,62 @@ enum /* long double */ LF_LD = (1 << 7), /* __float128 */ - LF_QD = (1 << 8) + LF_QD = (1 << 8), + + /* intmax or fltmax passed as a pointer - introduced to work around the issue where + * __float128 value is not passed properly via va_list. for example, the following clode + * compiled with clang -O1, -O2, -O3, etc produced a wrong value instead of 9.200000 + +#include +#include +void bbb (const char* fmt, va_list ap) +{ + __float128 x; + x = va_arg(ap, __float128); + printf ("%Lf\n", (long double)x); +} +void aaa (const char* fmt, ...) +{ + va_list ap; + va_start (ap, fmt); + bbb (fmt, ap); + va_end (ap); +} +int main () +{ + __float128 t = 9.2; + aaa ("aaaa\n", t); + return 0; +} + + +$ clang --version +clang version 7.0.1-8+deb10u2 (tags/RELEASE_701/final) +Target: x86_64-pc-linux-gnu +Thread model: posix +InstalledDir: /usr/bin +$ clang -O2 -o a a.c +$ ./a +0.000000 +$ clang -O0 -o a a.c +$ ./a +9.200000 + + * the same code printed a correct value without compiler optimization. + * + * passing a large value via a pointer is a safe way to work around this problem. + * hawk_rtx_format() and hawk_rtx_formatmbs() pass 'jj' for a floating-pointer number + * when built with HAWK_USE_FLTMAX on. + * + * 'jj' is allowed for 'c' and 's' but it works like 'j' for them. + */ + LF_JJ = (1 << 9) }; static struct { - hawk_uint8_t flag; /* for single occurrence */ - hawk_uint8_t dflag; /* for double occurrence */ + hawk_uint16_t flag; /* for single occurrence */ + hawk_uint16_t dflag; /* for double occurrence */ } lm_tab[26] = { { 0, 0 }, /* a */ @@ -115,7 +164,7 @@ static struct { 0, 0 }, /* g */ { LF_H, LF_C }, /* h */ { 0, 0 }, /* i */ - { LF_J, 0 }, /* j */ + { LF_J, LF_JJ }, /* j */ { 0, 0 }, /* k */ { LF_L, LF_Q }, /* l */ { 0, 0 }, /* m */ @@ -129,7 +178,7 @@ static struct { 0, 0 }, /* u */ { 0, 0 }, /* v */ { 0, 0 }, /* w */ - { 0, 0 }, /* z */ + { 0, 0 }, /* x */ { 0, 0 }, /* y */ { LF_Z, 0 }, /* z */ }; @@ -704,7 +753,7 @@ static int fmt_outv (hawk_fmtout_t* fmtout, va_list ap) /* end of length modifiers */ case 'n': /* number of characters printed so far */ - if (lm_flag & LF_J) /* j */ + if (lm_flag & (LF_J | LF_JJ)) /* j, jj */ *(va_arg(ap, hawk_intmax_t*)) = fmtout->count; else if (lm_flag & LF_Z) /* z */ *(va_arg(ap, hawk_ooi_t*)) = fmtout->count; @@ -764,7 +813,7 @@ static int fmt_outv (hawk_fmtout_t* fmtout, va_list ap) if (flagc & FLAGC_ZEROPAD) padc = ' '; if (lm_flag & LF_L) goto uppercase_c; #if defined(HAWK_OOCH_IS_UCH) - if (lm_flag & LF_J) goto uppercase_c; + if (lm_flag & (LF_J | LF_JJ)) goto uppercase_c; #endif lowercase_c: bch = HAWK_SIZEOF(hawk_bch_t) < HAWK_SIZEOF(int)? va_arg(ap, int): va_arg(ap, hawk_bch_t); @@ -784,7 +833,7 @@ static int fmt_outv (hawk_fmtout_t* fmtout, va_list ap) if (flagc & FLAGC_ZEROPAD) padc = ' '; if (lm_flag & LF_H) goto lowercase_c; #if defined(HAWK_OOCH_IS_BCH) - if (lm_flag & LF_J) goto lowercase_c; + if (lm_flag & (LF_J | LF_JJ)) goto lowercase_c; #endif uppercase_c: uch = HAWK_SIZEOF(hawk_uch_t) < HAWK_SIZEOF(int)? va_arg(ap, int): va_arg(ap, hawk_uch_t); @@ -805,7 +854,7 @@ static int fmt_outv (hawk_fmtout_t* fmtout, va_list ap) if (flagc & FLAGC_ZEROPAD) padc = ' '; if (lm_flag & LF_L) goto uppercase_s; #if defined(HAWK_OOCH_IS_UCH) - if (lm_flag & LF_J) goto uppercase_s; + if (lm_flag & (LF_J | LF_JJ)) goto uppercase_s; #endif lowercase_s: bsp = va_arg(ap, hawk_bch_t*); @@ -837,7 +886,7 @@ static int fmt_outv (hawk_fmtout_t* fmtout, va_list ap) if (flagc & FLAGC_ZEROPAD) padc = ' '; if (lm_flag & LF_H) goto lowercase_s; #if defined(HAWK_OOCH_IS_UCH) - if (lm_flag & LF_J) goto lowercase_s; + if (lm_flag & (LF_J | LF_JJ)) goto lowercase_s; #endif uppercase_s: usp = va_arg(ap, hawk_uch_t*); @@ -1054,21 +1103,35 @@ static int fmt_outv (hawk_fmtout_t* fmtout, va_list ap) #error Unsupported hawk_flt_t #endif } + else if (lm_flag & LF_JJ) + { + #if (HAWK_SIZEOF___FLOAT128 > 0) && defined(HAVE_QUADMATH_SNPRINTF) && (HAWK_SIZEOF_FLTMAX_T == HAWK_SIZEOF___FLOAT128) + v.qd = *(hawk_fltmax_t*)va_arg(ap, hawk_fltmax_t*); + dtype = LF_QD; + #elif HAWK_SIZEOF_FLTMAX_T == HAWK_SIZEOF_DOUBLE + v.d = *(hawk_fltmax_t*)va_arg(ap, hawk_fltmax_t*); + #elif HAWK_SIZEOF_FLTMAX_T == HAWK_SIZEOF_LONG_DOUBLE + v.ld = *(hawk_fltmax_t*)va_arg(ap, hawk_fltmax_t*); + dtype = LF_LD; + #else + #error Unsupported hawk_fltmax_t + #endif + } else if (lm_flag & LF_Z) { - /* hawk_flt_t is limited to double or long double */ + /* limited to double or long double. use hawk_fltbas_t */ /* precedence goes to double if sizeof(double) == sizeof(long double) * for example, %Lf didn't work on some old platforms. * so i prefer the format specifier with no modifier. */ - #if HAWK_SIZEOF_FLT_T == HAWK_SIZEOF_DOUBLE - v.d = va_arg(ap, hawk_flt_t); - #elif HAWK_SIZEOF_FLT_T == HAWK_SIZEOF_LONG_DOUBLE - v.ld = va_arg(ap, hawk_flt_t); + #if HAWK_SIZEOF_FLTBAS_T == HAWK_SIZEOF_DOUBLE + v.d = va_arg(ap, hawk_fltbas_t); + #elif HAWK_SIZEOF_FLTBAS_T == HAWK_SIZEOF_LONG_DOUBLE + v.ld = va_arg(ap, hawk_fltbas_t); dtype = LF_LD; #else - #error Unsupported hawk_flt_t + #error Unsupported hawk_fltbas_t #endif } else if (lm_flag & (LF_LD | LF_L)) @@ -1248,6 +1311,10 @@ static int fmt_outv (hawk_fmtout_t* fmtout, va_list ap) num = va_arg(ap, hawk_uintmax_t); #endif } + else if (lm_flag & LF_JJ) + { + num = *(hawk_uintmax_t*)va_arg(ap, hawk_uintmax_t*); + } else if (lm_flag & LF_T) num = va_arg(ap, hawk_intptr_t/*hawk_ptrdiff_t*/); else if (lm_flag & LF_Z) @@ -1290,6 +1357,8 @@ static int fmt_outv (hawk_fmtout_t* fmtout, va_list ap) num = va_arg(ap, hawk_intmax_t); #endif } + else if (lm_flag & LF_JJ) + num = *(hawk_intmax_t*)va_arg(ap, hawk_intmax_t*); else if (lm_flag & LF_T) num = va_arg(ap, hawk_intptr_t/*hawk_ptrdiff_t*/); diff --git a/hawk/lib/run.c b/hawk/lib/run.c index 64dc3cbc..3c93137a 100644 --- a/hawk/lib/run.c +++ b/hawk/lib/run.c @@ -8121,7 +8121,8 @@ wp_mod_main: int n; #if defined(HAWK_USE_FLTMAX) - FMT_CHAR (HAWK_T('j')); + /*FMT_CHAR (HAWK_T('j'));*/ + FMT_STR (HAWK_T("jj"), 2); /* see fmt.c for info on jj */ #else FMT_CHAR (HAWK_T('z')); #endif @@ -8159,7 +8160,12 @@ wp_mod_main: hawk_rtx_refdownval (rtx, v); if (n <= -1) return HAWK_NULL; + #if defined(HAWK_USE_FLTMAX) + /*if (hawk_ooecs_fcat(out, HAWK_OOECS_PTR(fbu), r) == (hawk_oow_t)-1) return HAWK_NULL;*/ + if (hawk_ooecs_fcat(out, HAWK_OOECS_PTR(fbu), &r) == (hawk_oow_t)-1) return HAWK_NULL; + #else if (hawk_ooecs_fcat(out, HAWK_OOECS_PTR(fbu), r) == (hawk_oow_t)-1) return HAWK_NULL; + #endif } else if (fmt[i] == HAWK_T('c')) { @@ -8932,7 +8938,8 @@ wp_mod_main: int n; #if defined(HAWK_USE_FLTMAX) - FMT_MCHAR (HAWK_BT('j')); + /*FMT_MCHAR (HAWK_BT('j'));*/ + FMT_MBS (HAWK_BT("jj"), 2); /* see fmt.c for info on jj */ #else FMT_MCHAR (HAWK_BT('z')); #endif @@ -8970,7 +8977,12 @@ wp_mod_main: hawk_rtx_refdownval (rtx, v); if (n <= -1) return HAWK_NULL; + #if defined(HAWK_USE_FLTMAX) + /*if (hawk_becs_fcat(out, HAWK_BECS_PTR(fbu), r) == (hawk_oow_t)-1) return HAWK_NULL;*/ + if (hawk_becs_fcat(out, HAWK_BECS_PTR(fbu), &r) == (hawk_oow_t)-1) return HAWK_NULL; + #else if (hawk_becs_fcat(out, HAWK_BECS_PTR(fbu), r) == (hawk_oow_t)-1) return HAWK_NULL; + #endif } else if (fmt[i] == HAWK_BT('c')) { diff --git a/hawk/lib/tree.c b/hawk/lib/tree.c index a8deb5be..c4720e7c 100644 --- a/hawk/lib/tree.c +++ b/hawk/lib/tree.c @@ -350,16 +350,12 @@ static int print_expr (hawk_t* hawk, hawk_nde_t* nde) { hawk_ooch_t buf[96]; - hawk_fmttooocstr (hawk, - buf, HAWK_COUNTOF(buf), - #if defined(HAWK_USE_FLTMAX) - HAWK_T("%jf"), - #else - HAWK_T("%zf"), - #endif - ((hawk_nde_flt_t*)nde)->val - ); - + #if defined(HAWK_USE_FLTMAX) + /*hawk_fmttooocstr (hawk, buf, HAWK_COUNTOF(buf), HAWK_T("%jf"), ((hawk_nde_flt_t*)nde)->val);*/ + hawk_fmttooocstr (hawk, buf, HAWK_COUNTOF(buf), HAWK_T("%jjf"), &((hawk_nde_flt_t*)nde)->val); + #else + hawk_fmttooocstr (hawk, buf, HAWK_COUNTOF(buf), HAWK_T("%zf"), ((hawk_nde_flt_t*)nde)->val); + #endif PUT_SRCSTR (hawk, buf); } break; diff --git a/hawk/lib/val.c b/hawk/lib/val.c index 91c39fd9..703de92b 100644 --- a/hawk/lib/val.c +++ b/hawk/lib/val.c @@ -2864,13 +2864,16 @@ void hawk_dprintval (hawk_rtx_t* run, hawk_val_t* val) break; case HAWK_VAL_INT: - hawk_errputstrf (HAWK_T("%jd"), - (hawk_intmax_t)((hawk_val_int_t*)val)->val); + hawk_errputstrf (HAWK_T("%jd"), (hawk_intmax_t)((hawk_val_int_t*)val)->val); break; case HAWK_VAL_FLT: - hawk_errputstrf (HAWK_T("%jf"), - (hawk_fltmax_t)((hawk_val_flt_t*)val)->val); + #if defined(HAWK_USE_FLTMAX) + /*hawk_errputstrf (HAWK_T("%jf"), ((hawk_val_flt_t*)val)->val);*/ + hawk_errputstrf (HAWK_T("%jjf"), &((hawk_val_flt_t*)val)->val); + #else + hawk_errputstrf (HAWK_T("%zf"), ((hawk_val_flt_t*)val)->val); + #endif break; case HAWK_VAL_STR: