diff options
Diffstat (limited to 'math')
-rw-r--r-- | math/Makefile | 71 | ||||
-rw-r--r-- | math/README.libm-test | 1 | ||||
-rw-r--r-- | math/gen-auto-libm-tests.c | 160 | ||||
-rwxr-xr-x | math/gen-libm-test.pl | 34 | ||||
-rw-r--r-- | math/libm-test-driver.c | 50 | ||||
-rw-r--r-- | math/libm-test-support.c | 25 | ||||
-rw-r--r-- | math/libm-test-support.h | 27 | ||||
-rw-r--r-- | math/test-arg-double.h | 25 | ||||
-rw-r--r-- | math/test-arg-float128.h | 32 | ||||
-rw-r--r-- | math/test-arg-float32x.h | 28 | ||||
-rw-r--r-- | math/test-arg-float64.h | 28 | ||||
-rw-r--r-- | math/test-arg-float64x.h | 32 | ||||
-rw-r--r-- | math/test-arg-ldouble.h | 31 | ||||
-rw-r--r-- | math/test-double.h | 1 | ||||
-rw-r--r-- | math/test-float.h | 1 | ||||
-rw-r--r-- | math/test-float128.h | 1 | ||||
-rw-r--r-- | math/test-float32.h | 1 | ||||
-rw-r--r-- | math/test-float32x.h | 1 | ||||
-rw-r--r-- | math/test-float64.h | 1 | ||||
-rw-r--r-- | math/test-float64x.h | 1 | ||||
-rw-r--r-- | math/test-math-narrow.h | 26 | ||||
-rw-r--r-- | math/test-math-scalar.h | 3 | ||||
-rw-r--r-- | math/test-math-vector.h | 1 | ||||
-rw-r--r-- | math/test-narrow-macros.c | 56 |
24 files changed, 580 insertions, 57 deletions
diff --git a/math/Makefile b/math/Makefile index ee0cd6f..42e540c 100644 --- a/math/Makefile +++ b/math/Makefile @@ -145,6 +145,21 @@ test-types = $(test-types-basic) $(type-float128-$(float128-fcts)) \ float32 float64 $(type-float128-$(float128-alias-fcts)) \ float32x $(type-float64x-$(float64x-alias-fcts)) +# Pairs of types for which narrowing functions should be tested (this +# variable has more entries than libm-narrow-types because it includes +# pairs for which the functions sometimes or always alias functions +# for other types). This definition embeds the assumption that if +# _Float64x is supported, so is _Float128, and vice versa (they may or +# may not have the same format). +test-type-pairs = float-double float-ldouble double-ldouble \ + float32-float64 float32-float32x float32x-float64 \ + $(test-type-pairs-f64xf128-$(float128-fcts)) \ + $(test-type-pairs-f64xf128-$(float128-alias-fcts)) +test-type-pairs-f64xf128-yes = float32-float64x float32-float128 \ + float64-float64x float64-float128 \ + float32x-float64x float32x-float128 \ + float64x-float128 + # For each of the basic types (float, double, long double), replace the # occurrences of 'F' in arg 1 with the appropriate suffix for the type. type-basic-foreach = $(foreach t, $(types-basic), \ @@ -219,7 +234,8 @@ tests = test-matherr-3 test-fenv basic-test \ test-femode-traps test-iszero-excess-precision \ test-iseqsig-excess-precision test-flt-eval-method \ test-fp-ilogb-constants test-fp-llogb-constants \ - test-fe-snans-always-signal test-finite-macros $(tests-static) + test-fe-snans-always-signal test-finite-macros test-narrow-macros \ + $(tests-static) tests-static = test-fpucw-static test-fpucw-ieee-static \ test-signgam-uchar-static test-signgam-uchar-init-static \ test-signgam-uint-static test-signgam-uint-init-static \ @@ -268,14 +284,19 @@ libm-test-funcs-noauto = canonicalize ceil cimag conj copysign cproj creal \ scalbln scalbn setpayload setpayloadsig signbit \ significand totalorder totalordermag trunc ufromfp \ ufromfpx +libm-test-funcs-narrow = libm-test-funcs-all = $(libm-test-funcs-auto) $(libm-test-funcs-noauto) libm-test-c-auto = $(foreach f,$(libm-test-funcs-auto),libm-test-$(f).c) libm-test-c-noauto = $(foreach f,$(libm-test-funcs-noauto),libm-test-$(f).c) -generated += libm-test-ulps.h $(libm-test-c-auto) $(libm-test-c-noauto) +libm-test-c-narrow = $(foreach f,$(libm-test-funcs-narrow),\ + libm-test-narrow-$(f).c) +generated += libm-test-ulps.h $(libm-test-c-auto) $(libm-test-c-noauto) \ + $(libm-test-c-narrow) libm-tests-base-normal = $(foreach t,$(test-types),test-$(t)) libm-tests-base-finite = $(foreach t,$(test-types),test-$(t)-finite) libm-tests-base-inline = $(foreach t,$(test-types),test-i$(t)) +libm-tests-base-narrow = $(foreach t,$(test-type-pairs),test-$(t)) libm-tests-base = $(libm-tests-base-normal) $(libm-tests-base-finite) \ $(libm-tests-base-inline) $(libm-vec-tests) libm-tests-normal = $(foreach t,$(libm-tests-base-normal),\ @@ -287,14 +308,18 @@ libm-tests-finite = $(foreach t,$(libm-tests-base-finite),\ libm-tests-inline = $(foreach t,$(libm-tests-base-inline),\ $(foreach f,$(libm-test-funcs-all),\ $(t)-$(f))) +libm-tests-narrow = $(foreach t,$(libm-tests-base-narrow),\ + $(foreach f,$(libm-test-funcs-narrow),\ + $(t)-$(f))) libm-tests-vector = $(foreach t,$(libmvec-tests),\ $(foreach f,$($(t)-funcs),test-$(t)-$(f))) libm-tests = $(libm-tests-normal) $(libm-tests-finite) $(libm-tests-inline) \ - $(libm-tests-vector) + $(libm-tests-narrow) $(libm-tests-vector) libm-tests-for-type = $(foreach f,$(libm-test-funcs-all),\ test-$(1)-$(f) test-$(1)-finite-$(f) \ test-i$(1)-$(f)) \ - $(filter test-$(1)-%,$(libm-tests-vector)) + $(filter test-$(1)-%,$(libm-tests-vector) \ + $(libm-tests-narrow)) libm-tests.o = $(addsuffix .o,$(libm-tests)) @@ -304,6 +329,7 @@ generated += $(addsuffix .c,$(libm-tests)) \ libm-test-c-auto-obj = $(addprefix $(objpfx),$(libm-test-c-auto)) libm-test-c-noauto-obj = $(addprefix $(objpfx),$(libm-test-c-noauto)) +libm-test-c-narrow-obj = $(addprefix $(objpfx),$(libm-test-c-narrow)) $(libm-test-c-noauto-obj): $(objpfx)libm-test%.c: libm-test%.inc \ gen-libm-test.pl @@ -315,6 +341,12 @@ $(libm-test-c-auto-obj): $(objpfx)libm-test%.c: libm-test%.inc \ auto-libm-test-out% $(make-target-directory) $(PERL) gen-libm-test.pl -c $< -a auto-libm-test-out$* -C $@ + +$(libm-test-c-narrow-obj): $(objpfx)libm-test%.c: libm-test%.inc \ + gen-libm-test.pl \ + auto-libm-test-out% + $(make-target-directory) + $(PERL) gen-libm-test.pl -c $< -a auto-libm-test-out$* -C $@ endif ifdef PYTHON @@ -457,6 +489,22 @@ $(foreach t,$(libm-tests-inline),$(objpfx)$(t).c): $(objpfx)test-i%.c: echo "#include <libm-test-$$func.c>"; \ ) > $@ +$(foreach t,$(libm-tests-narrow),$(objpfx)$(t).c): $(objpfx)test-%.c: + type_pair_func=$*; \ + type_pair=$${type_pair_func%-*}; \ + func=$${type_pair_func##*-}; \ + ret_type=$${type_pair%%-*}; \ + arg_type=$${type_pair#*-}; \ + ( \ + echo "#include <test-$$ret_type.h>"; \ + echo "#include <test-arg-$$arg_type.h>"; \ + echo "#include <test-math-no-finite.h>"; \ + echo "#include <test-math-no-inline.h>"; \ + echo "#include <test-math-errno.h>"; \ + echo "#include <test-math-narrow.h>"; \ + echo "#include <libm-test-narrow-$$func.c>"; \ + ) > $@ + $(foreach t,$(libm-tests-vector),$(objpfx)$(t).c): $(objpfx)test-%.c: type_func=$*; \ type=$${type_func%-*}; \ @@ -486,6 +534,14 @@ object-suffixes-left := $(libm-tests-base) include $(o-iterator) define o-iterator-doit +$(foreach f,$(libm-test-funcs-narrow),\ + $(objpfx)$(o)-$(f).o): $(objpfx)$(o)%.o: \ + $(objpfx)libm-test-narrow%.c +endef +object-suffixes-left := $(libm-tests-base-narrow) +include $(o-iterator) + +define o-iterator-doit $(foreach f,$(libm-test-funcs-all),\ $(objpfx)$(o)-$(f).o): CFLAGS += $(libm-test-no-inline-cflags) endef @@ -507,6 +563,13 @@ object-suffixes-left := $(libm-tests-base-inline) include $(o-iterator) define o-iterator-doit +$(foreach f,$(libm-test-funcs-narrow),\ + $(objpfx)$(o)-$(f).o): CFLAGS += $(libm-test-no-inline-cflags) +endef +object-suffixes-left := $(libm-tests-base-narrow) +include $(o-iterator) + +define o-iterator-doit $(foreach f,$($(o)-funcs),\ $(objpfx)test-$(o)-$(f).o): CFLAGS += $(libm-test-vec-cflags) endef diff --git a/math/README.libm-test b/math/README.libm-test index 0271f83..41702c6 100644 --- a/math/README.libm-test +++ b/math/README.libm-test @@ -120,6 +120,7 @@ parameter. The accepted parameter types are: - "f" for FLOAT - "j" for long double. +- "a" for ARG_FLOAT, the argument type for narrowing functions. - "b" for boolean - just tests if the output parameter evaluates to 0 or 1 (only for output). - "c" for complex. This parameter needs two values, first the real, diff --git a/math/gen-auto-libm-tests.c b/math/gen-auto-libm-tests.c index 934c64b..442a10d 100644 --- a/math/gen-auto-libm-tests.c +++ b/math/gen-auto-libm-tests.c @@ -25,6 +25,15 @@ gen-auto-libm-tests auto-libm-test-in <func> auto-libm-test-out-<func> + to generate results for normal libm functions, or + + gen-auto-libm-tests --narrow auto-libm-test-in <func> \ + auto-libm-test-out-narrow-<func> + + to generate results for a function rounding results to a narrower + type (in the case of fma and sqrt, both output files are generated + from the same test inputs). + The input file auto-libm-test-in contains three kinds of lines: Lines beginning with "#" are comments, and are ignored, as are @@ -120,7 +129,22 @@ missing or spurious, or because the calculation of correct results indicated it was optional). Conditions "before-rounding" and "after-rounding" indicate tests where expectations for underflow - exceptions depend on how the architecture detects tininess. */ + exceptions depend on how the architecture detects tininess. + + For functions rounding their results to a narrower type, the format + given on an output test line is the result format followed by + information about the requirements on the argument format to be + able to represent the argument values, in the form + "format:arg_fmt(MAX_EXP,NUM_ONES,MIN_EXP,MAX_PREC)". Instead of + separate lines for separate argument formats, an output test line + relates to all argument formats that can represent the values. + MAX_EXP is the maximum exponent of a nonzero bit in any argument, + or 0 if all arguments are zero; NUM_ONES is the maximum number of + leading bits with value 1 in an argument with exponent MAX_EXP, or + 0 if all arguments are zero; MIN_EXP is the minimum exponent of a + nonzero bit in any argument, or 0 if all arguments are zero; + MAX_PREC is the maximum precision required to represent all + arguments, or 0 if all arguments are zero. */ #define _GNU_SOURCE @@ -1718,12 +1742,13 @@ output_generic_value (FILE *fp, const char *filename, const generic_value *v, } } -/* Generate test output to FP (name FILENAME) for test function TF, - input test IT, choice of input values INPUTS. */ +/* Generate test output to FP (name FILENAME) for test function TF + (rounding results to a narrower type if NARROW), input test IT, + choice of input values INPUTS. */ static void output_for_one_input_case (FILE *fp, const char *filename, test_function *tf, - input_test *it, generic_value *inputs) + bool narrow, input_test *it, generic_value *inputs) { bool long_bits_matters = false; bool fits_long32 = true; @@ -1794,24 +1819,81 @@ output_for_one_input_case (FILE *fp, const char *filename, test_function *tf, mpfr_t res[rm_num_modes]; unsigned int exc_before[rm_num_modes]; unsigned int exc_after[rm_num_modes]; + bool have_fp_arg = false; + int max_exp = 0; + int num_ones = 0; + int min_exp = 0; + int max_prec = 0; for (size_t i = 0; i < tf->num_args; i++) { if (inputs[i].type == gtype_fp) { - round_real (res, exc_before, exc_after, inputs[i].value.f, - f); - if (!mpfr_equal_p (res[rm_tonearest], inputs[i].value.f)) - fits = false; - for (rounding_mode m = rm_first_mode; m < rm_num_modes; m++) - mpfr_clear (res[m]); - if (!fits) - break; + if (narrow) + { + if (mpfr_zero_p (inputs[i].value.f)) + continue; + assert (mpfr_regular_p (inputs[i].value.f)); + int this_exp, this_num_ones, this_min_exp, this_prec; + mpz_t tmp; + mpz_init (tmp); + mpfr_exp_t e = mpfr_get_z_2exp (tmp, inputs[i].value.f); + if (mpz_sgn (tmp) < 0) + mpz_neg (tmp, tmp); + size_t bits = mpz_sizeinbase (tmp, 2); + mp_bitcnt_t tz = mpz_scan1 (tmp, 0); + this_min_exp = e + tz; + this_prec = bits - tz; + assert (this_prec > 0); + this_exp = this_min_exp + this_prec - 1; + assert (this_exp + == mpfr_get_exp (inputs[i].value.f) - 1); + this_num_ones = 1; + while ((size_t) this_num_ones < bits + && mpz_tstbit (tmp, bits - 1 - this_num_ones)) + this_num_ones++; + mpz_clear (tmp); + if (have_fp_arg) + { + if (this_exp > max_exp + || (this_exp == max_exp + && this_num_ones > num_ones)) + { + max_exp = this_exp; + num_ones = this_num_ones; + } + if (this_min_exp < min_exp) + min_exp = this_min_exp; + if (this_prec > max_prec) + max_prec = this_prec; + } + else + { + max_exp = this_exp; + num_ones = this_num_ones; + min_exp = this_min_exp; + max_prec = this_prec; + } + have_fp_arg = true; + } + else + { + round_real (res, exc_before, exc_after, + inputs[i].value.f, f); + if (!mpfr_equal_p (res[rm_tonearest], inputs[i].value.f)) + fits = false; + for (rounding_mode m = rm_first_mode; + m < rm_num_modes; + m++) + mpfr_clear (res[m]); + if (!fits) + break; + } } } if (!fits) continue; - /* The inputs fit this type, so compute the ideal outputs - and exceptions. */ + /* The inputs fit this type if required to do so, so compute + the ideal outputs and exceptions. */ mpfr_t all_res[MAX_NRET][rm_num_modes]; unsigned int all_exc_before[MAX_NRET][rm_num_modes]; unsigned int all_exc_after[MAX_NRET][rm_num_modes]; @@ -1895,10 +1977,21 @@ output_for_one_input_case (FILE *fp, const char *filename, test_function *tf, assert ((merged_exc_before[m] & (1U << exc_underflow)) != 0); } unsigned int merged_exc = merged_exc_before[m]; - if (fprintf (fp, "= %s %s %s%s", tf->name, - rounding_modes[m].name, fp_formats[f].name, - long_cond) < 0) - error (EXIT_FAILURE, errno, "write to '%s'", filename); + if (narrow) + { + if (fprintf (fp, "= %s %s %s%s:arg_fmt(%d,%d,%d,%d)", + tf->name, rounding_modes[m].name, + fp_formats[f].name, long_cond, max_exp, + num_ones, min_exp, max_prec) < 0) + error (EXIT_FAILURE, errno, "write to '%s'", filename); + } + else + { + if (fprintf (fp, "= %s %s %s%s", tf->name, + rounding_modes[m].name, fp_formats[f].name, + long_cond) < 0) + error (EXIT_FAILURE, errno, "write to '%s'", filename); + } /* Print inputs. */ for (size_t i = 0; i < tf->num_args; i++) output_generic_value (fp, filename, &inputs[i], false, @@ -2158,10 +2251,12 @@ output_for_one_input_case (FILE *fp, const char *filename, test_function *tf, generic_value_free (&generic_outputs[i]); } -/* Generate test output data for FUNCTION to FILENAME. */ +/* Generate test output data for FUNCTION to FILENAME. The function + is interpreted as rounding its results to a narrower type if + NARROW. */ static void -generate_output (const char *function, const char *filename) +generate_output (const char *function, bool narrow, const char *filename) { FILE *fp = fopen (filename, "w"); if (fp == NULL) @@ -2177,7 +2272,8 @@ generate_output (const char *function, const char *filename) if (fputs (it->line, fp) < 0) error (EXIT_FAILURE, errno, "write to '%s'", filename); for (size_t k = 0; k < it->num_input_cases; k++) - output_for_one_input_case (fp, filename, tf, it, it->inputs[k]); + output_for_one_input_case (fp, filename, tf, narrow, + it, it->inputs[k]); } } if (fclose (fp) != 0) @@ -2187,14 +2283,30 @@ generate_output (const char *function, const char *filename) int main (int argc, char **argv) { - if (argc != 4) + if (argc != 4 + && !(argc == 5 && strcmp (argv[1], "--narrow") == 0)) error (EXIT_FAILURE, 0, - "usage: gen-auto-libm-tests <input> <func> <output>"); + "usage: gen-auto-libm-tests [--narrow] <input> <func> <output>"); + bool narrow; const char *input_filename = argv[1]; const char *function = argv[2]; const char *output_filename = argv[3]; + if (argc == 4) + { + narrow = false; + input_filename = argv[1]; + function = argv[2]; + output_filename = argv[3]; + } + else + { + narrow = true; + input_filename = argv[2]; + function = argv[3]; + output_filename = argv[4]; + } init_fp_formats (); read_input (input_filename); - generate_output (function, output_filename); + generate_output (function, narrow, output_filename); exit (EXIT_SUCCESS); } diff --git a/math/gen-libm-test.pl b/math/gen-libm-test.pl index 3556817..664fba5 100755 --- a/math/gen-libm-test.pl +++ b/math/gen-libm-test.pl @@ -165,10 +165,10 @@ sub show_exceptions { } } -# Apply the LIT(x) macro to a literal floating point constant +# Apply the LIT(x) or ARG_LIT(x) macro to a literal floating point constant # and strip any existing suffix. sub _apply_lit { - my ($lit) = @_; + my ($macro, $lit) = @_; my $exp_re = "([+-])?[[:digit:]]+"; # Don't wrap something that does not look like a: # * Hexadecimal FP value @@ -181,7 +181,7 @@ sub _apply_lit { # Strip any existing literal suffix. $lit =~ s/[lLfF]$//; - return "LIT (${lit})"; + return "$macro (${lit})"; } # Apply LIT macro to individual tokens within an expression. @@ -194,7 +194,17 @@ sub apply_lit { my ($lit) = @_; my @toks = split (/ /, $lit); foreach (@toks) { - $_ = _apply_lit ($_); + $_ = _apply_lit ("LIT", $_); + } + return join (' ', @toks); +} + +# Likewise, but apply ARG_LIT for arguments to narrowing functions. +sub apply_arglit { + my ($lit) = @_; + my @toks = split (/ /, $lit); + foreach (@toks) { + $_ = _apply_lit ("ARG_LIT", $_); } return join (' ', @toks); } @@ -228,8 +238,8 @@ sub parse_args { if ($current_arg > 1) { $comma = ', '; } - # FLOAT, long double, int, unsigned int, long int, long long int - if ($descr[$i] =~ /f|j|i|u|l|L/) { + # FLOAT, ARG_FLOAT, long double, int, unsigned int, long int, long long int + if ($descr[$i] =~ /f|a|j|i|u|l|L/) { $call_args .= $comma . &beautify ($args[$current_arg]); ++$current_arg; next; @@ -293,10 +303,12 @@ sub parse_args { $cline = "{ \"$call_args\""; @descr = split //,$descr_args; for ($i=0; $i <= $#descr; $i++) { - # FLOAT, int, long int, long long int - if ($descr[$i] =~ /f|j|i|u|l|L/) { + # FLOAT, ARG_FLOAT, long double, int, unsigned int, long int, long long int + if ($descr[$i] =~ /f|a|j|i|u|l|L/) { if ($descr[$i] eq "f") { $cline .= ", " . &apply_lit ($args[$current_arg]); + } elsif ($descr[$i] eq "a") { + $cline .= ", " . &apply_arglit ($args[$current_arg]); } else { $cline .= ", $args[$current_arg]"; } @@ -420,7 +432,9 @@ sub convert_condition { my (@conds, $ret); @conds = split /:/, $cond; foreach (@conds) { - s/-/_/g; + if ($_ !~ /^arg_fmt\(/) { + s/-/_/g; + } s/^/TEST_COND_/; } $ret = join " && ", @conds; @@ -822,7 +836,7 @@ sub parse_auto_input { chop; next if !/^= /; s/^= //; - if (/^(\S+) (\S+) ([^:]*) : (.*)$/) { + if (/^(\S+) (\S+) ([^: ][^ ]* [^:]*) : (.*)$/) { $auto_tests{$1}{$2}{$3} = $4; } else { die ("bad automatic test line: $_\n"); diff --git a/math/libm-test-driver.c b/math/libm-test-driver.c index b7c0343..3713e70 100644 --- a/math/libm-test-driver.c +++ b/math/libm-test-driver.c @@ -30,6 +30,7 @@ const int flag_test_mathvec = TEST_MATHVEC; #define STRX(x) #x #define STR(x) STRX (x) #define STR_FLOAT STR (FLOAT) +#define STR_ARG_FLOAT STR (ARG_FLOAT) #define STR_VEC_LEN STR (VEC_LEN) /* Informal description of the functions being tested. */ @@ -39,6 +40,8 @@ const int flag_test_mathvec = TEST_MATHVEC; # define TEST_MSG "testing " STR_FLOAT " (inline functions)\n" #elif TEST_FINITE # define TEST_MSG "testing " STR_FLOAT " (finite-math-only)\n" +#elif TEST_NARROW +# define TEST_MSG "testing " STR_FLOAT " (argument " STR_ARG_FLOAT ")\n" #else # define TEST_MSG "testing " STR_FLOAT " (without inline functions)\n" #endif @@ -108,6 +111,18 @@ const char qtype_str[] = TYPE_STR; #define min_value TYPE_MIN #define min_subnorm_value TYPE_TRUE_MIN +#define arg_plus_zero ARG_LIT (0.0) +#define arg_minus_zero ARG_LIT (-0.0) +#define arg_plus_infty ARG_FUNC (__builtin_inf) () +#define arg_minus_infty -(ARG_FUNC (__builtin_inf) ()) +#define arg_qnan_value_pl(S) ARG_FUNC (__builtin_nan) (S) +#define arg_qnan_value arg_qnan_value_pl ("") +#define arg_snan_value_pl(S) ARG_FUNC (__builtin_nans) (S) +#define arg_snan_value arg_snan_value_pl ("") +#define arg_max_value ARG_TYPE_MAX +#define arg_min_value ARG_TYPE_MIN +#define arg_min_subnorm_value ARG_TYPE_TRUE_MIN + /* For nexttoward tests. */ #define snan_value_ld __builtin_nansl ("") @@ -147,6 +162,18 @@ struct test_fj_f_data int exceptions; } rd, rn, rz, ru; }; +#ifdef ARG_FLOAT +struct test_aa_f_data +{ + const char *arg_str; + ARG_FLOAT arg1, arg2; + struct + { + FLOAT expected; + int exceptions; + } rd, rn, rz, ru; +}; +#endif struct test_fi_f_data { const char *arg_str; @@ -467,6 +494,7 @@ struct test_Ff_b1_data #define RUN_TEST_ff_f RUN_TEST_2_f #define RUN_TEST_LOOP_ff_f RUN_TEST_LOOP_2_f #define RUN_TEST_LOOP_fj_f RUN_TEST_LOOP_2_f +#define RUN_TEST_LOOP_aa_f RUN_TEST_LOOP_2_f #define RUN_TEST_fi_f RUN_TEST_2_f #define RUN_TEST_LOOP_fi_f RUN_TEST_LOOP_2_f #define RUN_TEST_fl_f RUN_TEST_2_f @@ -945,18 +973,32 @@ struct test_Ff_b1_data (ARRAY)[i].RM_##ROUNDING_MODE.extra2_expected); \ ROUND_RESTORE_ ## ROUNDING_MODE -#if !TEST_MATHVEC -# define VEC_SUFF +#if TEST_MATHVEC +# define TEST_SUFF VEC_SUFF +# define TEST_SUFF_STR +#elif TEST_NARROW +# define TEST_SUFF +# define TEST_SUFF_STR "_" ARG_TYPE_STR +#else +# define TEST_SUFF +# define TEST_SUFF_STR #endif #define STR_CONCAT(a, b, c) __STRING (a##b##c) #define STR_CON3(a, b, c) STR_CONCAT (a, b, c) +#if TEST_NARROW +# define TEST_COND_any_ibm128 (TEST_COND_ibm128 || TEST_COND_arg_ibm128) +#else +# define TEST_COND_any_ibm128 TEST_COND_ibm128 +#endif + /* Start and end the tests for a given function. */ #define START(FUN, SUFF, EXACT) \ CHECK_ARCH_EXT; \ - const char *this_func = STR_CON3 (FUN, SUFF, VEC_SUFF); \ - init_max_error (this_func, EXACT) + const char *this_func \ + = STR_CON3 (FUN, SUFF, TEST_SUFF) TEST_SUFF_STR; \ + init_max_error (this_func, EXACT, TEST_COND_any_ibm128) #define END \ print_max_error (this_func) #define END_COMPLEX \ diff --git a/math/libm-test-support.c b/math/libm-test-support.c index 2e4f9ef..e59f15b 100644 --- a/math/libm-test-support.c +++ b/math/libm-test-support.c @@ -135,6 +135,7 @@ static int verbose; static int output_max_error; /* Should the maximal errors printed? */ static int output_points; /* Should the single function results printed? */ static int ignore_max_ulp; /* Should we ignore max_ulp? */ +static int test_ibm128; /* Is argument or result IBM long double? */ static FLOAT max_error, real_max_error, imag_max_error; @@ -212,11 +213,12 @@ find_ulps (const char *name, const struct ulp_data *data, size_t nmemb) } void -init_max_error (const char *name, int exact) +init_max_error (const char *name, int exact, int testing_ibm128) { max_error = 0; real_max_error = 0; imag_max_error = 0; + test_ibm128 = testing_ibm128; prev_max_error = find_ulps (name, func_ulps, sizeof (func_ulps) / sizeof (func_ulps[0])); prev_real_max_error = find_ulps (name, func_real_ulps, @@ -225,15 +227,14 @@ init_max_error (const char *name, int exact) prev_imag_max_error = find_ulps (name, func_imag_ulps, (sizeof (func_imag_ulps) / sizeof (func_imag_ulps[0]))); -#if TEST_COND_ibm128 - /* The documented accuracy of IBM long double division is 3ulp (see - libgcc/config/rs6000/ibm-ldouble-format), so do not require - better accuracy for libm functions that are exactly defined for - other formats. */ - max_valid_error = exact ? 3 : 16; -#else - max_valid_error = exact ? 0 : 9; -#endif + if (testing_ibm128) + /* The documented accuracy of IBM long double division is 3ulp + (see libgcc/config/rs6000/ibm-ldouble-format), so do not + require better accuracy for libm functions that are exactly + defined for other formats. */ + max_valid_error = exact ? 3 : 16; + else + max_valid_error = exact ? 0 : 9; prev_max_error = (prev_max_error <= max_valid_error ? prev_max_error : max_valid_error); @@ -518,14 +519,14 @@ test_exceptions (const char *test_name, int exception) arithmetic. */ #ifdef FE_UNDERFLOW if ((exception & UNDERFLOW_EXCEPTION_OK) == 0 - && !(TEST_COND_ibm128 + && !(test_ibm128 && (exception & UNDERFLOW_EXCEPTION) == 0)) test_single_exception (test_name, exception, UNDERFLOW_EXCEPTION, FE_UNDERFLOW, "Underflow"); #endif #ifdef FE_INEXACT if ((exception & (INEXACT_EXCEPTION | NO_INEXACT_EXCEPTION)) != 0 - && !(TEST_COND_ibm128 + && !(test_ibm128 && (exception & NO_INEXACT_EXCEPTION) != 0)) test_single_exception (test_name, exception, INEXACT_EXCEPTION, FE_INEXACT, "Inexact"); diff --git a/math/libm-test-support.h b/math/libm-test-support.h index b86c227..64206ab 100644 --- a/math/libm-test-support.h +++ b/math/libm-test-support.h @@ -81,6 +81,13 @@ extern const char doc[]; #define MAX_EXP __CONCATX (PREFIX, _MAX_EXP) #define MANT_DIG __CONCATX (PREFIX, _MANT_DIG) +#define ARG_TYPE_MIN __CONCATX (ARG_PREFIX, _MIN) +#define ARG_TYPE_TRUE_MIN __CONCATX (ARG_PREFIX, _TRUE_MIN) +#define ARG_TYPE_MAX __CONCATX (ARG_PREFIX, _MAX) +#define ARG_MIN_EXP __CONCATX (ARG_PREFIX, _MIN_EXP) +#define ARG_MAX_EXP __CONCATX (ARG_PREFIX, _MAX_EXP) +#define ARG_MANT_DIG __CONCATX (ARG_PREFIX, _MANT_DIG) + /* Format specific test macros. */ #define TEST_COND_binary32 (MANT_DIG == 24 \ && MIN_EXP == -125 \ @@ -96,6 +103,8 @@ extern const char doc[]; #define TEST_COND_ibm128 (MANT_DIG == 106) +#define TEST_COND_arg_ibm128 (ARG_MANT_DIG == 106) + #define TEST_COND_intel96 (MANT_DIG == 64 \ && MIN_EXP == -16381 \ && MAX_EXP == 16384) @@ -108,7 +117,11 @@ extern const char doc[]; where in principle the glibc code is OK but the tests fail because of limitations of the libgcc support for that format (e.g. GCC bug 59666, in non-default rounding modes). */ -#define TEST_COND_ibm128_libgcc TEST_COND_ibm128 +#ifdef ARG_FLOAT +# define TEST_COND_ibm128_libgcc (TEST_COND_ibm128 || TEST_COND_arg_ibm128) +#else +# define TEST_COND_ibm128_libgcc TEST_COND_ibm128 +#endif /* Mark a test as expected to fail for ibm128-libgcc. This is used via XFAIL_ROUNDING_IBM128_LIBGCC, which gen-libm-test.pl transforms @@ -132,6 +145,16 @@ extern const char doc[]; # define PAYLOAD_DIG (MANT_DIG - 2) #endif +/* For narrowing functions, whether the argument format can represent + all the given argument values. */ +#define TEST_COND_arg_fmt(MAX_EXP, NUM_ONES, MIN_EXP, MAX_PREC) \ + (((MAX_EXP) < ARG_MAX_EXP) \ + && (!TEST_COND_arg_ibm128 \ + || (MAX_EXP) < ARG_MAX_EXP - 1 \ + || (NUM_ONES) <= 53) \ + && (MIN_EXP) >= ARG_MIN_EXP - ARG_MANT_DIG \ + && (MAX_PREC) <= ARG_MANT_DIG) + /* Values underflowing on architectures detecting tininess before rounding, but not on those detecting tininess after rounding. */ #define UNDERFLOW_EXCEPTION_BEFORE_ROUNDING (TININESS_AFTER_ROUNDING \ @@ -149,7 +172,7 @@ extern const char doc[]; #define TEST_COND_after_rounding TININESS_AFTER_ROUNDING int enable_test (int); -void init_max_error (const char *, int); +void init_max_error (const char *, int, int); void print_max_error (const char *); void print_complex_max_error (const char *); void check_float (const char *, FLOAT, FLOAT, int); diff --git a/math/test-arg-double.h b/math/test-arg-double.h new file mode 100644 index 0000000..4eec144 --- /dev/null +++ b/math/test-arg-double.h @@ -0,0 +1,25 @@ +/* Common definitions for libm tests for double arguments to narrowing + functions. + Copyright (C) 2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#define ARG_FUNC(function) function +#define ARG_FLOAT double +#define ARG_PREFIX DBL +#define ARG_LIT(x) (x) +#define ARG_TYPE_STR "double" +#define FUNC_NARROW_SUFFIX diff --git a/math/test-arg-float128.h b/math/test-arg-float128.h new file mode 100644 index 0000000..d2a7ef8 --- /dev/null +++ b/math/test-arg-float128.h @@ -0,0 +1,32 @@ +/* Common definitions for libm tests for _Float128 arguments to + narrowing functions. + Copyright (C) 2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <bits/floatn.h> +#include <float.h> + +#define ARG_FUNC(function) function ## f128 +#define ARG_FLOAT _Float128 +#define ARG_PREFIX FLT128 +#define ARG_LIT(x) __f128 (x) +#if FLT128_MANT_DIG == LDBL_MANT_DIG +# define ARG_TYPE_STR "ldouble" +#else +# define ARG_TYPE_STR "float128" +#endif +#define FUNC_NARROW_SUFFIX f128 diff --git a/math/test-arg-float32x.h b/math/test-arg-float32x.h new file mode 100644 index 0000000..d036f9c --- /dev/null +++ b/math/test-arg-float32x.h @@ -0,0 +1,28 @@ +/* Common definitions for libm tests for _Float32x arguments to + narrowing functions. + Copyright (C) 2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <bits/floatn.h> +#include <float.h> + +#define ARG_FUNC(function) function ## f32x +#define ARG_FLOAT _Float32x +#define ARG_PREFIX FLT32X +#define ARG_LIT(x) __f32x (x) +#define ARG_TYPE_STR "double" +#define FUNC_NARROW_SUFFIX f32x diff --git a/math/test-arg-float64.h b/math/test-arg-float64.h new file mode 100644 index 0000000..3467119 --- /dev/null +++ b/math/test-arg-float64.h @@ -0,0 +1,28 @@ +/* Common definitions for libm tests for _Float64 arguments to + narrowing functions. + Copyright (C) 2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <bits/floatn.h> +#include <float.h> + +#define ARG_FUNC(function) function ## f64 +#define ARG_FLOAT _Float64 +#define ARG_PREFIX FLT64 +#define ARG_LIT(x) __f64 (x) +#define ARG_TYPE_STR "double" +#define FUNC_NARROW_SUFFIX f64 diff --git a/math/test-arg-float64x.h b/math/test-arg-float64x.h new file mode 100644 index 0000000..c07d908 --- /dev/null +++ b/math/test-arg-float64x.h @@ -0,0 +1,32 @@ +/* Common definitions for libm tests for _Float64x arguments to + narrowing functions. + Copyright (C) 2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <bits/floatn.h> +#include <float.h> + +#define ARG_FUNC(function) function ## f64x +#define ARG_FLOAT _Float64x +#define ARG_PREFIX FLT64X +#define ARG_LIT(x) __f64x (x) +#if FLT64X_MANT_DIG == LDBL_MANT_DIG +# define ARG_TYPE_STR "ldouble" +#else +# define ARG_TYPE_STR "float128" +#endif +#define FUNC_NARROW_SUFFIX f64x diff --git a/math/test-arg-ldouble.h b/math/test-arg-ldouble.h new file mode 100644 index 0000000..41b475e --- /dev/null +++ b/math/test-arg-ldouble.h @@ -0,0 +1,31 @@ +/* Common definitions for libm tests for long double arguments to + narrowing functions. + Copyright (C) 2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <float.h> + +#define ARG_FUNC(function) function ## l +#define ARG_FLOAT long double +#define ARG_PREFIX LDBL +#define ARG_LIT(x) (x ## L) +#if LDBL_MANT_DIG == DBL_MANT_DIG +# define ARG_TYPE_STR "double" +#else +# define ARG_TYPE_STR "ldouble" +#endif +#define FUNC_NARROW_SUFFIX l diff --git a/math/test-double.h b/math/test-double.h index 238b086..0b0fc96 100644 --- a/math/test-double.h +++ b/math/test-double.h @@ -29,3 +29,4 @@ #define FTOSTR strfromd #define snan_value_MACRO SNAN #define TEST_FLOATN 0 +#define FUNC_NARROW_PREFIX d diff --git a/math/test-float.h b/math/test-float.h index 7e301c3..dc3646d 100644 --- a/math/test-float.h +++ b/math/test-float.h @@ -30,3 +30,4 @@ #define FTOSTR strfromf #define snan_value_MACRO SNANF #define TEST_FLOATN 0 +#define FUNC_NARROW_PREFIX f diff --git a/math/test-float128.h b/math/test-float128.h index 7678913..376d3da 100644 --- a/math/test-float128.h +++ b/math/test-float128.h @@ -41,3 +41,4 @@ #define LITM(x) x ## f128 #define FTOSTR strfromf128 #define snan_value_MACRO SNANF128 +#define FUNC_NARROW_PREFIX f128 diff --git a/math/test-float32.h b/math/test-float32.h index 2df9909..f319fe6 100644 --- a/math/test-float32.h +++ b/math/test-float32.h @@ -35,3 +35,4 @@ #define LITM(x) x ## f32 #define FTOSTR strfromf32 #define snan_value_MACRO SNANF32 +#define FUNC_NARROW_PREFIX f32 diff --git a/math/test-float32x.h b/math/test-float32x.h index ce02e28..2aadc4a 100644 --- a/math/test-float32x.h +++ b/math/test-float32x.h @@ -35,3 +35,4 @@ #define LITM(x) x ## f32x #define FTOSTR strfromf32x #define snan_value_MACRO SNANF32X +#define FUNC_NARROW_PREFIX f32x diff --git a/math/test-float64.h b/math/test-float64.h index d5c7c84..debdf5a 100644 --- a/math/test-float64.h +++ b/math/test-float64.h @@ -35,3 +35,4 @@ #define LITM(x) x ## f64 #define FTOSTR strfromf64 #define snan_value_MACRO SNANF64 +#define FUNC_NARROW_PREFIX f64 diff --git a/math/test-float64x.h b/math/test-float64x.h index 54c931f..bf1b934 100644 --- a/math/test-float64x.h +++ b/math/test-float64x.h @@ -41,3 +41,4 @@ #define LITM(x) x ## f64x #define FTOSTR strfromf64x #define snan_value_MACRO SNANF64X +#define FUNC_NARROW_PREFIX f64x diff --git a/math/test-math-narrow.h b/math/test-math-narrow.h new file mode 100644 index 0000000..1c7fa30 --- /dev/null +++ b/math/test-math-narrow.h @@ -0,0 +1,26 @@ +/* Common definitions for libm tests for narrowing scalar functions. + Copyright (C) 2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#define FUNC_TEST(function) \ + FUNC_TEST_CONCAT (FUNC_NARROW_PREFIX, function, FUNC_NARROW_SUFFIX) +#define FUNC_TEST_CONCAT(prefix, function, suffix) \ + _FUNC_TEST_CONCAT (prefix, function, suffix) +#define _FUNC_TEST_CONCAT(prefix, function, suffix) \ + prefix ## function ## suffix +#define TEST_MATHVEC 0 +#define TEST_NARROW 1 diff --git a/math/test-math-scalar.h b/math/test-math-scalar.h index 764db89..8df0d5d 100644 --- a/math/test-math-scalar.h +++ b/math/test-math-scalar.h @@ -1,4 +1,4 @@ -/* Common definitions for libm tests for scalar functions. +/* Common definitions for libm tests for scalar (non-narrowing) functions. Copyright (C) 1997-2018 Free Software Foundation, Inc. This file is part of the GNU C Library. @@ -18,3 +18,4 @@ #define FUNC_TEST(function) FUNC (function) #define TEST_MATHVEC 0 +#define TEST_NARROW 0 diff --git a/math/test-math-vector.h b/math/test-math-vector.h index 1592c4a..43d01d0 100644 --- a/math/test-math-vector.h +++ b/math/test-math-vector.h @@ -17,6 +17,7 @@ <http://www.gnu.org/licenses/>. */ #define TEST_MATHVEC 1 +#define TEST_NARROW 0 #define TEST_FINITE 0 #define TEST_ERRNO 0 #define TEST_EXCEPTIONS 0 diff --git a/math/test-narrow-macros.c b/math/test-narrow-macros.c new file mode 100644 index 0000000..f53c86a --- /dev/null +++ b/math/test-narrow-macros.c @@ -0,0 +1,56 @@ +/* Test code declaring narrowing functions does not conflict with user macros. + Copyright (C) 2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +/* The code generating declarations of narrowing functions involves + concatenations of fragments of function names that are not + themselves reserved; thus, it needs to be arranged so that those + fragments are not subject to macro expansion. Verify that + inclusion of <math.h> compiles with such fragments defined as + macros. */ + +#define f test macro +#define d test macro +#define l test macro +#define f16 test macro +#define f32 test macro +#define f64 test macro +#define f128 test macro +#define f32x test macro +#define f64x test macro +#define f128x test macro +#define add test macro +#define sub test macro +#define mul test macro +#define div test macro +#define dadd test macro +#define dsub test macro +#define dmul test macro +#define ddiv test macro +#define dsqrt test macro +#define dfma test macro + +#include <math.h> + +static int +do_test (void) +{ + /* This is a compilation test. */ + return 0; +} + +#include <support/test-driver.c> |