summary refs log tree commit diff
path: root/math
diff options
context:
space:
mode:
Diffstat (limited to 'math')
-rw-r--r--math/Makefile71
-rw-r--r--math/README.libm-test1
-rw-r--r--math/gen-auto-libm-tests.c160
-rwxr-xr-xmath/gen-libm-test.pl34
-rw-r--r--math/libm-test-driver.c50
-rw-r--r--math/libm-test-support.c25
-rw-r--r--math/libm-test-support.h27
-rw-r--r--math/test-arg-double.h25
-rw-r--r--math/test-arg-float128.h32
-rw-r--r--math/test-arg-float32x.h28
-rw-r--r--math/test-arg-float64.h28
-rw-r--r--math/test-arg-float64x.h32
-rw-r--r--math/test-arg-ldouble.h31
-rw-r--r--math/test-double.h1
-rw-r--r--math/test-float.h1
-rw-r--r--math/test-float128.h1
-rw-r--r--math/test-float32.h1
-rw-r--r--math/test-float32x.h1
-rw-r--r--math/test-float64.h1
-rw-r--r--math/test-float64x.h1
-rw-r--r--math/test-math-narrow.h26
-rw-r--r--math/test-math-scalar.h3
-rw-r--r--math/test-math-vector.h1
-rw-r--r--math/test-narrow-macros.c56
24 files changed, 580 insertions, 57 deletions
diff --git a/math/Makefile b/math/Makefile
index ee0cd6fce1..42e540cf0e 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 0271f83f3b..41702c6537 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 934c64bc76..442a10d5e6 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 3556817c1d..664fba5909 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 b7c0343062..3713e7074f 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 2e4f9ef926..e59f15b4d9 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 b86c22796a..64206ab7fa 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 0000000000..4eec144944
--- /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 0000000000..d2a7ef8e70
--- /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 0000000000..d036f9cce5
--- /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 0000000000..346711917c
--- /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 0000000000..c07d908b54
--- /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 0000000000..41b475eae3
--- /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 238b086496..0b0fc96bf1 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 7e301c3c74..dc3646d008 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 7678913ca9..376d3da11e 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 2df9909724..f319fe6268 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 ce02e28809..2aadc4a674 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 d5c7c84e7d..debdf5aaf6 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 54c931f2bb..bf1b934311 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 0000000000..1c7fa30e98
--- /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 764db89f35..8df0d5ddc5 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 1592c4a9c3..43d01d064a 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 0000000000..f53c86ae16
--- /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>