]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
* builtin-types.def (BT_FN_INT_INT_INT_INT_INT_INT_VAR): New.
authorghazi <ghazi@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 23 May 2008 04:47:12 +0000 (04:47 +0000)
committerghazi <ghazi@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 23 May 2008 04:47:12 +0000 (04:47 +0000)
* builtins.c (fold_builtin_fpclassify): New.
(fold_builtin_varargs): Handle BUILT_IN_FPCLASSIFY.
* builtins.def (BUILT_IN_FPCLASSIFY): New.
* c-common.c (handle_type_generic_attribute): Adjust to accept
fixed arguments before an elipsis.
(check_builtin_function_arguments): Handle BUILT_IN_FPCLASSIFY.
* doc/extend.texi: Document __builtin_fpclassify.

testsuite:
* gcc.dg/builtins-error.c: Test __builtin_fpclassify.  Also
add tests for all previous type-generic builtins.
* gcc.dg/pr28796-2.c: Add -DUNSAFE flag.
* gcc.dg/tg-tests.h: Test __builtin_fpclassify.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@135789 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/builtin-types.def
gcc/builtins.c
gcc/builtins.def
gcc/c-common.c
gcc/doc/extend.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/builtins-error.c
gcc/testsuite/gcc.dg/pr28796-2.c
gcc/testsuite/gcc.dg/tg-tests.h

index 51712235ae0df504d4cf6aa4f3a22b9a08ff5217..a75c72ffcda22e362c7188fb72a7b36648c8d9cc 100644 (file)
@@ -1,3 +1,14 @@
+2008-05-23  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>
+
+       * builtin-types.def (BT_FN_INT_INT_INT_INT_INT_INT_VAR): New.
+       * builtins.c (fold_builtin_fpclassify): New.
+       (fold_builtin_varargs): Handle BUILT_IN_FPCLASSIFY.
+       * builtins.def (BUILT_IN_FPCLASSIFY): New.
+       * c-common.c (handle_type_generic_attribute): Adjust to accept
+       fixed arguments before an elipsis.
+       (check_builtin_function_arguments): Handle BUILT_IN_FPCLASSIFY.
+       * doc/extend.texi: Document __builtin_fpclassify.
+
 2008-05-22  Aldy Hernandez  <aldyh@redhat.com>
 
        * omp-low.c (gate_expand_omp_ssa): Remove.
index 081a33f04674d26f49021c08de1963a88d67ce7f..25b5a0964f5ca7f97b38415828f323f58d16310d 100644 (file)
@@ -449,6 +449,9 @@ DEF_FUNCTION_TYPE_VAR_5 (BT_FN_INT_STRING_SIZE_INT_SIZE_CONST_STRING_VAR,
                         BT_INT, BT_STRING, BT_SIZE, BT_INT, BT_SIZE,
                         BT_CONST_STRING)
 
+DEF_FUNCTION_TYPE_VAR_5 (BT_FN_INT_INT_INT_INT_INT_INT_VAR,
+                        BT_INT, BT_INT, BT_INT, BT_INT, BT_INT, BT_INT)
+
 DEF_POINTER_TYPE (BT_PTR_FN_VOID_VAR, BT_FN_VOID_VAR)
 DEF_FUNCTION_TYPE_3 (BT_FN_PTR_PTR_FN_VOID_VAR_PTR_SIZE,
                     BT_PTR, BT_PTR_FN_VOID_VAR, BT_PTR, BT_SIZE)
index 3060f80ae00e981829caeadf92efc0cb4ce6dd91..d442469b7eead388d6ad5f439d5ab91a5d6448de 100644 (file)
@@ -9744,6 +9744,70 @@ fold_builtin_classify (tree fndecl, tree arg, int builtin_index)
     }
 }
 
+/* Fold a call to __builtin_fpclassify(int, int, int, int, int, ...).
+   This builtin will generate code to return the appropriate floating
+   point classification depending on the value of the floating point
+   number passed in.  The possible return values must be supplied as
+   int arguments to the call in the following order: FP_NAN, FP_INF,
+   FP_NORMAL, FP_SUBNORMAL and FP_ZERO.  The ellipses is for exactly
+   one floating point argument which is "type generic".  */
+
+static tree
+fold_builtin_fpclassify (tree exp)
+{
+  tree fp_nan, fp_inf, fp_normal, fp_subnormal, fp_zero, arg, type, res, tmp;
+  enum machine_mode mode;
+  REAL_VALUE_TYPE r;
+  char buf[128];
+  
+  /* Verify the required arguments in the original call.  */
+  if (!validate_arglist (exp, INTEGER_TYPE, INTEGER_TYPE,
+                        INTEGER_TYPE, INTEGER_TYPE,
+                        INTEGER_TYPE, REAL_TYPE, VOID_TYPE))
+    return NULL_TREE;
+  
+  fp_nan = CALL_EXPR_ARG (exp, 0);
+  fp_inf = CALL_EXPR_ARG (exp, 1);
+  fp_normal = CALL_EXPR_ARG (exp, 2);
+  fp_subnormal = CALL_EXPR_ARG (exp, 3);
+  fp_zero = CALL_EXPR_ARG (exp, 4);
+  arg = CALL_EXPR_ARG (exp, 5);
+  type = TREE_TYPE (arg);
+  mode = TYPE_MODE (type);
+  arg = builtin_save_expr (fold_build1 (ABS_EXPR, type, arg));
+
+  /* fpclassify(x) -> 
+       isnan(x) ? FP_NAN :
+         (fabs(x) == Inf ? FP_INF :
+          (fabs(x) >= DBL_MIN ? FP_NORMAL :
+            (x == 0 ? FP_ZERO : FP_SUBNORMAL))).  */
+  
+  tmp = fold_build2 (EQ_EXPR, integer_type_node, arg,
+                    build_real (type, dconst0));
+  res = fold_build3 (COND_EXPR, integer_type_node, tmp, fp_zero, fp_subnormal);
+
+  sprintf (buf, "0x1p%d", REAL_MODE_FORMAT (mode)->emin - 1);
+  real_from_string (&r, buf);
+  tmp = fold_build2 (GE_EXPR, integer_type_node, arg, build_real (type, r));
+  res = fold_build3 (COND_EXPR, integer_type_node, tmp, fp_normal, res);
+  
+  if (HONOR_INFINITIES (mode))
+    {
+      real_inf (&r);
+      tmp = fold_build2 (EQ_EXPR, integer_type_node, arg,
+                        build_real (type, r));
+      res = fold_build3 (COND_EXPR, integer_type_node, tmp, fp_inf, res);
+    }
+
+  if (HONOR_NANS (mode))
+    {
+      tmp = fold_build2 (ORDERED_EXPR, integer_type_node, arg, arg);
+      res = fold_build3 (COND_EXPR, integer_type_node, tmp, res, fp_nan);
+    }
+  
+  return res;
+}
+
 /* Fold a call to an unordered comparison function such as
    __builtin_isgreater().  FNDECL is the FUNCTION_DECL for the function
    being called and ARG0 and ARG1 are the arguments for the call.
@@ -10528,6 +10592,11 @@ fold_builtin_varargs (tree fndecl, tree exp, bool ignore ATTRIBUTE_UNUSED)
     case BUILT_IN_SNPRINTF_CHK:
     case BUILT_IN_VSNPRINTF_CHK:
       ret = fold_builtin_snprintf_chk (exp, NULL_TREE, fcode);
+      break;
+
+    case BUILT_IN_FPCLASSIFY:
+      ret = fold_builtin_fpclassify (exp);
+      break;
 
     default:
       break;
index 8bae2bd467ca05a976fc5da80de18ff1e0e57f5c..310e5f456a798a086cfb29e11cd341432c065f67 100644 (file)
@@ -654,6 +654,7 @@ DEF_EXT_LIB_BUILTIN    (BUILT_IN_FINITEL, "finitel", BT_FN_INT_LONGDOUBLE, ATTR_
 DEF_EXT_LIB_BUILTIN    (BUILT_IN_FINITED32, "finited32", BT_FN_INT_DFLOAT32, ATTR_CONST_NOTHROW_LIST)
 DEF_EXT_LIB_BUILTIN    (BUILT_IN_FINITED64, "finited64", BT_FN_INT_DFLOAT64, ATTR_CONST_NOTHROW_LIST)
 DEF_EXT_LIB_BUILTIN    (BUILT_IN_FINITED128, "finited128", BT_FN_INT_DFLOAT128, ATTR_CONST_NOTHROW_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_FPCLASSIFY, "fpclassify", BT_FN_INT_INT_INT_INT_INT_INT_VAR, ATTR_CONST_NOTHROW_TYPEGENERIC)
 DEF_GCC_BUILTIN        (BUILT_IN_ISFINITE, "isfinite", BT_FN_INT_VAR, ATTR_CONST_NOTHROW_TYPEGENERIC)
 DEF_GCC_BUILTIN        (BUILT_IN_ISINF_SIGN, "isinf_sign", BT_FN_INT_VAR, ATTR_CONST_NOTHROW_TYPEGENERIC)
 DEF_C99_C90RES_BUILTIN (BUILT_IN_ISINF, "isinf", BT_FN_INT_VAR, ATTR_CONST_NOTHROW_TYPEGENERIC)
index 67c9c0b538febcbc68bbe72cc68c3a42ede8c5dd..70ba5cc485150a36f4a91f3e3bcab0bf2d207bf1 100644 (file)
@@ -6528,8 +6528,17 @@ handle_type_generic_attribute (tree *node, tree ARG_UNUSED (name),
                               tree ARG_UNUSED (args), int ARG_UNUSED (flags),
                               bool * ARG_UNUSED (no_add_attrs))
 {
-  /* Ensure we have a function type, with no arguments.  */
-  gcc_assert (TREE_CODE (*node) == FUNCTION_TYPE && ! TYPE_ARG_TYPES (*node));
+  tree params;
+  
+  /* Ensure we have a function type.  */
+  gcc_assert (TREE_CODE (*node) == FUNCTION_TYPE);
+  
+  params = TYPE_ARG_TYPES (*node);
+  while (params && ! VOID_TYPE_P (TREE_VALUE (params)))
+    params = TREE_CHAIN (params);
+
+  /* Ensure we have a variadic function.  */
+  gcc_assert (!params);
 
   return NULL_TREE;
 }
@@ -6712,6 +6721,29 @@ check_builtin_function_arguments (tree fndecl, int nargs, tree *args)
        }
       return false;
 
+    case BUILT_IN_FPCLASSIFY:
+      if (validate_nargs (fndecl, nargs, 6))
+       {
+         unsigned i;
+         
+         for (i=0; i<5; i++)
+           if (TREE_CODE (args[i]) != INTEGER_CST)
+             {
+               error ("non-const integer argument %u in call to function %qE",
+                      i+1, fndecl);
+               return false;
+             }
+
+         if (TREE_CODE (TREE_TYPE (args[5])) != REAL_TYPE)
+           {
+             error ("non-floating-point argument in call to function %qE",
+                    fndecl);
+             return false;
+           }
+         return true;
+       }
+      return false;
+
     default:
       return true;
     }
index 36e81ffe55c182ddf1f05f4f5af8c524fece62b5..78d581d62e6c362a75fe009aafcc62426bacee8f 100644 (file)
@@ -5764,6 +5764,7 @@ should be called and the @var{flag} argument passed to it.
 @node Other Builtins
 @section Other built-in functions provided by GCC
 @cindex built-in functions
+@findex __builtin_fpclassify
 @findex __builtin_isfinite
 @findex __builtin_isnormal
 @findex __builtin_isgreater
@@ -6295,10 +6296,10 @@ the same names as the standard macros ( @code{isgreater},
 @code{islessgreater}, and @code{isunordered}) , with @code{__builtin_}
 prefixed.  We intend for a library implementor to be able to simply
 @code{#define} each standard macro to its built-in equivalent.
-In the same fashion, GCC provides @code{isfinite}, @code{isinf_sign}
-and @code{isnormal} built-ins used with @code{__builtin_} prefixed.
-The @code{isinf} and @code{isnan} builtins appear both with and
-without the @code{__builtin_} prefix.
+In the same fashion, GCC provides @code{fpclassify}, @code{isfinite},
+@code{isinf_sign} and @code{isnormal} built-ins used with
+@code{__builtin_} prefixed.  The @code{isinf} and @code{isnan}
+builtins appear both with and without the @code{__builtin_} prefix.
 
 @deftypefn {Built-in Function} int __builtin_types_compatible_p (@var{type1}, @var{type2})
 
@@ -6555,6 +6556,17 @@ Similar to @code{__builtin_huge_val}, except the return
 type is @code{long double}.
 @end deftypefn
 
+@deftypefn {Built-in Function} int __builtin_fpclassify (int, int, int, int, int, ...)
+This built-in implements the C99 fpclassify functionality.  The first
+five int arguments should be the target library's notion of the
+possible FP classes and are used for return values.  They must be
+constant values and they must appear in this order: @code{FP_NAN},
+@code{FP_INF}, @code{FP_NORMAL}, @code{FP_SUBNORMAL} and
+@code{FP_ZERO}.  The ellipsis is for exactly one floating point value
+to classify.  GCC treats the last argument as type-generic, which
+means it does not do default promotion from float to double.
+@end deftypefn
+
 @deftypefn {Built-in Function} double __builtin_inf (void)
 Similar to @code{__builtin_huge_val}, except a warning is generated
 if the target floating-point format does not support infinities.
index af0260cff6f7eafb45b91d5b540ec3439aa61565..420a482832f4cc6d2428a8871b842f2bf8af336a 100644 (file)
@@ -1,3 +1,10 @@
+2008-05-23  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>
+
+       * gcc.dg/builtins-error.c: Test __builtin_fpclassify.  Also
+       add tests for all previous type-generic builtins.
+       * gcc.dg/pr28796-2.c: Add -DUNSAFE flag.
+       * gcc.dg/tg-tests.h: Test __builtin_fpclassify.
+
 2008-05-22  Thomas Koenig  <tkoenig@gcc.gnu.org>
 
        PR libgfortran/36302
index 2c0ece1934b40a59d593415835a2ab148676bd4c..0f41700ba1a081c5d4ef5ef051f89383a89a065f 100644 (file)
@@ -4,20 +4,62 @@ struct X { int x; };
 
 int test1(struct X x)
 {
-  return __builtin_isnormal(x); /* { dg-error "non-floating-point argument" } */
+  if (x.x ==  1) return __builtin_fpclassify(1,2,3,4,5,x); /* { dg-error "non-floating-point argument" } */
+  if (x.x ==  2) return __builtin_isfinite(x); /* { dg-error "non-floating-point argument" } */
+  if (x.x ==  3) return __builtin_isinf_sign(x); /* { dg-error "non-floating-point argument" } */
+  if (x.x ==  4) return __builtin_isinf(x); /* { dg-error "non-floating-point argument" } */
+  if (x.x ==  5) return __builtin_isnan(x); /* { dg-error "non-floating-point argument" } */
+  if (x.x ==  6) return __builtin_isnormal(x); /* { dg-error "non-floating-point argument" } */
+  if (x.x ==  7) return __builtin_isgreater(x, x); /* { dg-error "non-floating-point arguments" } */
+  if (x.x ==  8) return __builtin_isgreaterequal(x, x); /* { dg-error "non-floating-point arguments" } */
+  if (x.x ==  9) return __builtin_isless(x, x); /* { dg-error "non-floating-point arguments" } */
+  if (x.x == 10) return __builtin_islessequal(x, x); /* { dg-error "non-floating-point arguments" } */
+  if (x.x == 11) return __builtin_islessgreater(x, x); /* { dg-error "non-floating-point arguments" } */
+  if (x.x == 12) return __builtin_isunordered(x, x); /* { dg-error "non-floating-point arguments" } */
+
+  return 0;
 }
 
 int test2(double x)
 {
-  return __builtin_isgreater(x); /* { dg-error "not enough arguments" } */
+  if (x ==  1) return __builtin_fpclassify(1,2,3,4,5); /* { dg-error "not enough arguments" } */
+  if (x ==  2) return __builtin_isfinite(); /* { dg-error "not enough arguments" } */
+  if (x ==  3) return __builtin_isinf_sign(); /* { dg-error "not enough arguments" } */
+  if (x ==  4) return __builtin_isinf(); /* { dg-error "not enough arguments" } */
+  if (x ==  5) return __builtin_isnan(); /* { dg-error "not enough arguments" } */
+  if (x ==  6) return __builtin_isnormal(); /* { dg-error "not enough arguments" } */
+  if (x ==  7) return __builtin_isgreater(x); /* { dg-error "not enough arguments" } */
+  if (x ==  8) return __builtin_isgreaterequal(x); /* { dg-error "not enough arguments" } */
+  if (x ==  9) return __builtin_isless(x); /* { dg-error "not enough arguments" } */
+  if (x == 10) return __builtin_islessequal(x); /* { dg-error "not enough arguments" } */
+  if (x == 11) return __builtin_islessgreater(x); /* { dg-error "not enough arguments" } */
+  if (x == 12) return __builtin_isunordered(x); /* { dg-error "not enough arguments" } */
+  return 0;
 }
 
 int test3(double x)
 {
-  return __builtin_isinf(x, x); /* { dg-error "too many arguments" } */
+  if (x ==  1) return __builtin_fpclassify(1,2,3,4,5,x,x); /* { dg-error "too many arguments" } */
+  if (x ==  2) return __builtin_isfinite(x, x); /* { dg-error "too many arguments" } */
+  if (x ==  3) return __builtin_isinf_sign(x, x); /* { dg-error "too many arguments" } */
+  if (x ==  4) return __builtin_isinf(x, x); /* { dg-error "too many arguments" } */
+  if (x ==  5) return __builtin_isnan(x, x); /* { dg-error "too many arguments" } */
+  if (x ==  6) return __builtin_isnormal(x, x); /* { dg-error "too many arguments" } */
+  if (x ==  7) return __builtin_isgreater(x, x, x); /* { dg-error "too many arguments" } */
+  if (x ==  8) return __builtin_isgreaterequal(x, x, x); /* { dg-error "too many arguments" } */
+  if (x ==  9) return __builtin_isless(x, x, x); /* { dg-error "too many arguments" } */
+  if (x == 10) return __builtin_islessequal(x, x, x); /* { dg-error "too many arguments" } */
+  if (x == 11) return __builtin_islessgreater(x, x, x); /* { dg-error "too many arguments" } */
+  if (x == 12) return __builtin_isunordered(x, x, x); /* { dg-error "too many arguments" } */
+  return 0;
 }
 
-int test4(double x)
+int test4(int i, double x)
 {
-  return __builtin_isinf_sign(x, x); /* { dg-error "too many arguments" } */
+  if (x ==  1) return __builtin_fpclassify(i,2,3,4,5,x); /* { dg-error "non-const integer argument" } */
+  if (x ==  2) return __builtin_fpclassify(1,i,3,4,5,x); /* { dg-error "non-const integer argument" } */
+  if (x ==  3) return __builtin_fpclassify(1,2,i,4,5,x); /* { dg-error "non-const integer argument" } */
+  if (x ==  4) return __builtin_fpclassify(1,2,3,i,5,x); /* { dg-error "non-const integer argument" } */
+  if (x ==  5) return __builtin_fpclassify(1,2,3,4,i,x); /* { dg-error "non-const integer argument" } */
+  return 0;
 }
index 6a9eff827b76e1b611005736be224c36f55866e0..f4900817581c5aba8616beabafb5faba0839f37b 100644 (file)
@@ -1,6 +1,6 @@
 /* { dg-do run } */
-/* { dg-options "-O2 -funsafe-math-optimizations -fno-finite-math-only" } */
-/* { dg-options "-mieee -O2 -funsafe-math-optimizations -fno-finite-math-only" { target alpha*-*-* } } */
+/* { dg-options "-O2 -funsafe-math-optimizations -fno-finite-math-only -DUNSAFE" } */
+/* { dg-options "-mieee -O2 -funsafe-math-optimizations -fno-finite-math-only -DUNSAFE" { target alpha*-*-* } } */
 
 #include "tg-tests.h"
 
index c34e8888cfa394b6dfdcf07533cac9a954637398..dc95a2cde623811d888396454395a3106d24ac98 100644 (file)
@@ -1,9 +1,17 @@
 /* Test various type-generic builtins by calling "main_tests()".  */
 
+#define FP_NAN 1
+#define FP_INF 2
+#define FP_NORMAL 3
+#define FP_SUBNORMAL 4
+#define FP_ZERO 5
+#define fpclassify(X) __builtin_fpclassify(FP_NAN, FP_INF, FP_NORMAL, FP_SUBNORMAL, FP_ZERO, (X))
+
 void __attribute__ ((__noinline__))
 foo_1 (float f, double d, long double ld,
        int res_unord, int res_isnan, int res_isinf,
-       int res_isinf_sign, int res_isfin, int res_isnorm)
+       int res_isinf_sign, int res_isfin, int res_isnorm,
+       int classification)
 {
   if (__builtin_isunordered (f, 0) != res_unord)
     __builtin_abort ();
@@ -71,16 +79,30 @@ foo_1 (float f, double d, long double ld,
     __builtin_abort ();
   if (__builtin_finitel (ld) != res_isfin)
     __builtin_abort ();
+
+  /* Subnormals can abruptly underflow to zero in unsafe math
+     mode, so bypass testing these numbers if necessary.  */
+#ifdef UNSAFE
+  if (classification != FP_SUBNORMAL)
+#endif
+    {
+      if (fpclassify(f) != classification)
+       __builtin_abort ();
+      if (fpclassify(d) != classification)
+       __builtin_abort ();
+      if (fpclassify(ld) != classification)
+       __builtin_abort ();
+    }
 }
 
 void __attribute__ ((__noinline__))
 foo (float f, double d, long double ld,
      int res_unord, int res_isnan, int res_isinf,
-     int res_isfin, int res_isnorm)
+     int res_isfin, int res_isnorm, int classification)
 {
-  foo_1 (f, d, ld, res_unord, res_isnan, res_isinf, res_isinf, res_isfin, res_isnorm);
+  foo_1 (f, d, ld, res_unord, res_isnan, res_isinf, res_isinf, res_isfin, res_isnorm, classification);
   /* Try all the values negated as well.  */
-  foo_1 (-f, -d, -ld, res_unord, res_isnan, res_isinf, -res_isinf, res_isfin, res_isnorm);
+  foo_1 (-f, -d, -ld, res_unord, res_isnan, res_isinf, -res_isinf, res_isfin, res_isnorm, classification);
 }
 
 int __attribute__ ((__noinline__))
@@ -92,35 +114,35 @@ main_tests (void)
   
   /* Test NaN.  */
   f = __builtin_nanf(""); d = __builtin_nan(""); ld = __builtin_nanl("");
-  foo(f, d, ld, /*unord=*/ 1, /*isnan=*/ 1, /*isinf=*/ 0, /*isfin=*/ 0, /*isnorm=*/ 0);
+  foo(f, d, ld, /*unord=*/ 1, /*isnan=*/ 1, /*isinf=*/ 0, /*isfin=*/ 0, /*isnorm=*/ 0, FP_NAN);
 
   /* Test infinity.  */
   f = __builtin_inff(); d = __builtin_inf(); ld = __builtin_infl();
-  foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 1, /*isfin=*/ 0, /*isnorm=*/ 0);
+  foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 1, /*isfin=*/ 0, /*isnorm=*/ 0, FP_INF);
 
   /* Test zero.  */
   f = 0; d = 0; ld = 0;
-  foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 0, /*isfin=*/ 1, /*isnorm=*/ 0);
+  foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 0, /*isfin=*/ 1, /*isnorm=*/ 0, FP_ZERO);
 
   /* Test one.  */
   f = 1; d = 1; ld = 1;
-  foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 0, /*isfin=*/ 1, /*isnorm=*/ 1);
+  foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 0, /*isfin=*/ 1, /*isnorm=*/ 1, FP_NORMAL);
 
   /* Test minimum values.  */
   f = __FLT_MIN__; d = __DBL_MIN__; ld = __LDBL_MIN__;
-  foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 0, /*isfin=*/ 1, /*isnorm=*/ 1);
+  foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 0, /*isfin=*/ 1, /*isnorm=*/ 1, FP_NORMAL);
 
   /* Test subnormal values.  */
   f = __FLT_MIN__/2; d = __DBL_MIN__/2; ld = __LDBL_MIN__/2;
-  foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 0, /*isfin=*/ 1, /*isnorm=*/ 0);
+  foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 0, /*isfin=*/ 1, /*isnorm=*/ 0, FP_SUBNORMAL);
 
   /* Test maximum values.  */
   f = __FLT_MAX__; d = __DBL_MAX__; ld = __LDBL_MAX__;
-  foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 0, /*isfin=*/ 1, /*isnorm=*/ 1);
+  foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 0, /*isfin=*/ 1, /*isnorm=*/ 1, FP_NORMAL);
 
   /* Test overflow values.  */
   f = __FLT_MAX__*2; d = __DBL_MAX__*2; ld = __LDBL_MAX__*2;
-  foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 1, /*isfin=*/ 0, /*isnorm=*/ 0);
+  foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 1, /*isfin=*/ 0, /*isnorm=*/ 0, FP_INF);
 
   return 0;
 }