aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorRoger Sayle <roger@eyesopen.com>2003-07-03 21:38:55 +0000
committerRoger Sayle <sayle@gcc.gnu.org>2003-07-03 21:38:55 +0000
commit0a9530a9d7cf389493916027f9980fcbf028b602 (patch)
tree6f8671ee7d010f3f877a3ed92690c0d270f47544 /gcc
parent7516d73631a96bcc28178f057bee4e713022b7d5 (diff)
downloadgcc-0a9530a9d7cf389493916027f9980fcbf028b602.zip
gcc-0a9530a9d7cf389493916027f9980fcbf028b602.tar.gz
gcc-0a9530a9d7cf389493916027f9980fcbf028b602.tar.bz2
real.c (real_trunc, [...]): New functions to implement trunc, floor and ceil respectively.
* real.c (real_trunc, real_floor, real_ceil): New functions to implement trunc, floor and ceil respectively. * real.h (real_trunc, real_floor, real_ceil): Prototype here. * builtins.c (integer_valued_real_p): New function to test if a floating point expression has an integer valued result. (fold_trunc_transparent_mathfn): Optimize foo(foo(x)) as foo(x) where foo is an integer rounding function. Similarly, optimize foo(bar(x)) as bar(x), and foo((double)(int)x) as (double)(int)x when both foo and bar are integer rounding functions and we don't need to honor errno. (fold_builtin_trunc, fold_builtin_floor, fold_builtin_ceil): New functions to fold trunc, floor and ceil. (fold_builtin): Use fold_builtin_trunc to fold BUILT_IN_TRUNC*, fold_builtin_floor to fold BUILT_IN_FLOOR* and fold_builtin_ceil to fold BUILT_IN_CEIL*. * fold-const.c (tree_expr_nonnegative_p): Handle FLOAT_EXPR and the remaining integer rounding functions. * gcc.dg/builtins-25.c: New testcase. * gcc.dg/builtins-26.c: New testcase. From-SVN: r68903
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog20
-rw-r--r--gcc/builtins.c206
-rw-r--r--gcc/fold-const.c11
-rw-r--r--gcc/real.c46
-rw-r--r--gcc/real.h11
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.dg/builtins-25.c188
-rw-r--r--gcc/testsuite/gcc.dg/builtins-26.c105
8 files changed, 589 insertions, 3 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 7e5ccb4..2d9c829 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,23 @@
+2003-07-03 Roger Sayle <roger@eyesopen.com>
+
+ * real.c (real_trunc, real_floor, real_ceil): New functions
+ to implement trunc, floor and ceil respectively.
+ * real.h (real_trunc, real_floor, real_ceil): Prototype here.
+ * builtins.c (integer_valued_real_p): New function to test if
+ a floating point expression has an integer valued result.
+ (fold_trunc_transparent_mathfn): Optimize foo(foo(x)) as
+ foo(x) where foo is an integer rounding function. Similarly,
+ optimize foo(bar(x)) as bar(x), and foo((double)(int)x) as
+ (double)(int)x when both foo and bar are integer rounding
+ functions and we don't need to honor errno.
+ (fold_builtin_trunc, fold_builtin_floor, fold_builtin_ceil):
+ New functions to fold trunc, floor and ceil.
+ (fold_builtin): Use fold_builtin_trunc to fold BUILT_IN_TRUNC*,
+ fold_builtin_floor to fold BUILT_IN_FLOOR* and fold_builtin_ceil
+ to fold BUILT_IN_CEIL*.
+ * fold-const.c (tree_expr_nonnegative_p): Handle FLOAT_EXPR and
+ the remaining integer rounding functions.
+
2003-07-03 Eric Botcazou <ebotcazou@libertysurf.fr>
* config/sparc/sparc.c (function_arg_partial_nregs): Use
diff --git a/gcc/builtins.c b/gcc/builtins.c
index e8ab4d574..9471215 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -149,12 +149,16 @@ static tree fold_builtin_classify_type (tree);
static tree fold_builtin_inf (tree, int);
static tree fold_builtin_nan (tree, tree, int);
static int validate_arglist (tree, ...);
+static bool integer_valued_real_p (tree);
static tree fold_trunc_transparent_mathfn (tree);
static bool readonly_data_expr (tree);
static rtx expand_builtin_fabs (tree, rtx, rtx);
static rtx expand_builtin_cabs (tree, rtx);
static void init_builtin_dconsts (void);
static tree fold_builtin_cabs (tree, tree, tree);
+static tree fold_builtin_trunc (tree);
+static tree fold_builtin_floor (tree);
+static tree fold_builtin_ceil (tree);
/* Initialize mathematical constants for constant folding builtins.
These constants need to be given to at least 160 bits precision. */
@@ -5347,19 +5351,118 @@ fold_builtin_nan (tree arglist, tree type, int quiet)
return build_real (type, real);
}
-/* EXP is assumed to me builtin call where truncation can be propagated
+/* Return true if the floating point expression T has an integer value.
+ We also allow +Inf, -Inf and NaN to be considered integer values. */
+
+static bool
+integer_valued_real_p (tree t)
+{
+ switch (TREE_CODE (t))
+ {
+ case FLOAT_EXPR:
+ return true;
+
+ case ABS_EXPR:
+ case SAVE_EXPR:
+ case NON_LVALUE_EXPR:
+ return integer_valued_real_p (TREE_OPERAND (t, 0));
+
+ case COMPOUND_EXPR:
+ case MODIFY_EXPR:
+ case BIND_EXPR:
+ return integer_valued_real_p (TREE_OPERAND (t, 1));
+
+ case PLUS_EXPR:
+ case MINUS_EXPR:
+ case MULT_EXPR:
+ case MIN_EXPR:
+ case MAX_EXPR:
+ return integer_valued_real_p (TREE_OPERAND (t, 0))
+ && integer_valued_real_p (TREE_OPERAND (t, 1));
+
+ case COND_EXPR:
+ return integer_valued_real_p (TREE_OPERAND (t, 1))
+ && integer_valued_real_p (TREE_OPERAND (t, 2));
+
+ case REAL_CST:
+ if (! TREE_CONSTANT_OVERFLOW (t))
+ {
+ REAL_VALUE_TYPE c, cint;
+
+ c = TREE_REAL_CST (t);
+ real_trunc (&cint, TYPE_MODE (TREE_TYPE (t)), &c);
+ return real_identical (&c, &cint);
+ }
+
+ case NOP_EXPR:
+ {
+ tree type = TREE_TYPE (TREE_OPERAND (t, 0));
+ if (TREE_CODE (type) == INTEGER_TYPE)
+ return true;
+ if (TREE_CODE (type) == REAL_TYPE)
+ return integer_valued_real_p (TREE_OPERAND (t, 0));
+ break;
+ }
+
+ case CALL_EXPR:
+ switch (builtin_mathfn_code (t))
+ {
+ case BUILT_IN_CEIL:
+ case BUILT_IN_CEILF:
+ case BUILT_IN_CEILL:
+ case BUILT_IN_FLOOR:
+ case BUILT_IN_FLOORF:
+ case BUILT_IN_FLOORL:
+ case BUILT_IN_NEARBYINT:
+ case BUILT_IN_NEARBYINTF:
+ case BUILT_IN_NEARBYINTL:
+ case BUILT_IN_ROUND:
+ case BUILT_IN_ROUNDF:
+ case BUILT_IN_ROUNDL:
+ case BUILT_IN_TRUNC:
+ case BUILT_IN_TRUNCF:
+ case BUILT_IN_TRUNCL:
+ return true;
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return false;
+}
+
+/* EXP is assumed to be builtin call where truncation can be propagated
across (for instance floor((double)f) == (double)floorf (f).
Do the transformation. */
+
static tree
fold_trunc_transparent_mathfn (tree exp)
{
tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
tree arglist = TREE_OPERAND (exp, 1);
enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
+ tree arg;
+
+ if (! validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+ return 0;
- if (optimize && validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+ arg = TREE_VALUE (arglist);
+ /* Integer rounding functions are idempotent. */
+ if (fcode == builtin_mathfn_code (arg))
+ return arg;
+
+ /* If argument is already integer valued, and we don't need to worry
+ about setting errno, there's no need to perform rounding. */
+ if (! flag_errno_math && integer_valued_real_p (arg))
+ return arg;
+
+ if (optimize)
{
- tree arg0 = strip_float_extensions (TREE_VALUE (arglist));
+ tree arg0 = strip_float_extensions (arg);
tree ftype = TREE_TYPE (exp);
tree newtype = TREE_TYPE (arg0);
tree decl;
@@ -5461,6 +5564,97 @@ fold_builtin_cabs (tree fndecl, tree arglist, tree type)
return NULL_TREE;
}
+/* Fold function call to builtin trunc, truncf or truncl. Return
+ NULL_TREE if no simplification can be made. */
+
+static tree
+fold_builtin_trunc (tree exp)
+{
+ tree arglist = TREE_OPERAND (exp, 1);
+ tree arg;
+
+ if (! validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+ return 0;
+
+ /* Optimize trunc of constant value. */
+ arg = TREE_VALUE (arglist);
+ if (TREE_CODE (arg) == REAL_CST && ! TREE_CONSTANT_OVERFLOW (arg))
+ {
+ REAL_VALUE_TYPE r, x;
+ tree type = TREE_TYPE (exp);
+
+ x = TREE_REAL_CST (arg);
+ real_trunc (&r, TYPE_MODE (type), &x);
+ return build_real (type, r);
+ }
+
+ return fold_trunc_transparent_mathfn (exp);
+}
+
+/* Fold function call to builtin floor, floorf or floorl. Return
+ NULL_TREE if no simplification can be made. */
+
+static tree
+fold_builtin_floor (tree exp)
+{
+ tree arglist = TREE_OPERAND (exp, 1);
+ tree arg;
+
+ if (! validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+ return 0;
+
+ /* Optimize floor of constant value. */
+ arg = TREE_VALUE (arglist);
+ if (TREE_CODE (arg) == REAL_CST && ! TREE_CONSTANT_OVERFLOW (arg))
+ {
+ REAL_VALUE_TYPE x;
+
+ x = TREE_REAL_CST (arg);
+ if (! REAL_VALUE_ISNAN (x) || ! flag_errno_math)
+ {
+ tree type = TREE_TYPE (exp);
+ REAL_VALUE_TYPE r;
+
+ real_floor (&r, TYPE_MODE (type), &x);
+ return build_real (type, r);
+ }
+ }
+
+ return fold_trunc_transparent_mathfn (exp);
+}
+
+/* Fold function call to builtin ceil, ceilf or ceill. Return
+ NULL_TREE if no simplification can be made. */
+
+static tree
+fold_builtin_ceil (tree exp)
+{
+ tree arglist = TREE_OPERAND (exp, 1);
+ tree arg;
+
+ if (! validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+ return 0;
+
+ /* Optimize ceil of constant value. */
+ arg = TREE_VALUE (arglist);
+ if (TREE_CODE (arg) == REAL_CST && ! TREE_CONSTANT_OVERFLOW (arg))
+ {
+ REAL_VALUE_TYPE x;
+
+ x = TREE_REAL_CST (arg);
+ if (! REAL_VALUE_ISNAN (x) || ! flag_errno_math)
+ {
+ tree type = TREE_TYPE (exp);
+ REAL_VALUE_TYPE r;
+
+ real_ceil (&r, TYPE_MODE (type), &x);
+ return build_real (type, r);
+ }
+ }
+
+ return fold_trunc_transparent_mathfn (exp);
+}
+
/* Used by constant folding to eliminate some builtin calls early. EXP is
the CALL_EXPR of a call to a builtin function. */
@@ -5918,12 +6112,18 @@ fold_builtin (tree exp)
case BUILT_IN_FLOOR:
case BUILT_IN_FLOORF:
case BUILT_IN_FLOORL:
+ return fold_builtin_floor (exp);
+
case BUILT_IN_CEIL:
case BUILT_IN_CEILF:
case BUILT_IN_CEILL:
+ return fold_builtin_ceil (exp);
+
case BUILT_IN_TRUNC:
case BUILT_IN_TRUNCF:
case BUILT_IN_TRUNCL:
+ return fold_builtin_trunc (exp);
+
case BUILT_IN_ROUND:
case BUILT_IN_ROUNDF:
case BUILT_IN_ROUNDL:
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index c4826c7..0524e1d 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -8105,6 +8105,8 @@ tree_expr_nonnegative_p (tree t)
return tree_expr_nonnegative_p (TREE_OPERAND (t, 0));
case NON_LVALUE_EXPR:
return tree_expr_nonnegative_p (TREE_OPERAND (t, 0));
+ case FLOAT_EXPR:
+ return tree_expr_nonnegative_p (TREE_OPERAND (t, 0));
case RTL_EXPR:
return rtl_expr_nonnegative_p (RTL_EXPR_RTL (t));
@@ -8141,6 +8143,15 @@ tree_expr_nonnegative_p (tree t)
case BUILT_IN_FLOOR:
case BUILT_IN_FLOORF:
case BUILT_IN_FLOORL:
+ case BUILT_IN_NEARBYINT:
+ case BUILT_IN_NEARBYINTF:
+ case BUILT_IN_NEARBYINTL:
+ case BUILT_IN_ROUND:
+ case BUILT_IN_ROUNDF:
+ case BUILT_IN_ROUNDL:
+ case BUILT_IN_TRUNC:
+ case BUILT_IN_TRUNCF:
+ case BUILT_IN_TRUNCL:
return tree_expr_nonnegative_p (TREE_VALUE (arglist));
case BUILT_IN_POW:
diff --git a/gcc/real.c b/gcc/real.c
index b491d88..6bc4d52 100644
--- a/gcc/real.c
+++ b/gcc/real.c
@@ -4748,3 +4748,49 @@ real_powi (r, mode, x, n)
return inexact;
}
+/* Round X to the nearest integer not larger in absolute value, i.e.
+ towards zero, placing the result in R in mode MODE. */
+
+void
+real_trunc (r, mode, x)
+ REAL_VALUE_TYPE *r;
+ enum machine_mode mode;
+ const REAL_VALUE_TYPE *x;
+{
+ do_fix_trunc (r, x);
+ if (mode != VOIDmode)
+ real_convert (r, mode, r);
+}
+
+/* Round X to the largest integer not greater in value, i.e. round
+ down, placing the result in R in mode MODE. */
+
+void
+real_floor (r, mode, x)
+ REAL_VALUE_TYPE *r;
+ enum machine_mode mode;
+ const REAL_VALUE_TYPE *x;
+{
+ do_fix_trunc (r, x);
+ if (! real_identical (r, x) && r->sign)
+ do_add (r, r, &dconstm1, 0);
+ if (mode != VOIDmode)
+ real_convert (r, mode, r);
+}
+
+/* Round X to the smallest integer not less then argument, i.e. round
+ up, placing the result in R in mode MODE. */
+
+void
+real_ceil (r, mode, x)
+ REAL_VALUE_TYPE *r;
+ enum machine_mode mode;
+ const REAL_VALUE_TYPE *x;
+{
+ do_fix_trunc (r, x);
+ if (! real_identical (r, x) && ! r->sign)
+ do_add (r, r, &dconst1, 0);
+ if (mode != VOIDmode)
+ real_convert (r, mode, r);
+}
+
diff --git a/gcc/real.h b/gcc/real.h
index 71e3cc4..fcd7ae7 100644
--- a/gcc/real.h
+++ b/gcc/real.h
@@ -375,4 +375,15 @@ extern bool real_powi PARAMS ((REAL_VALUE_TYPE *,
const REAL_VALUE_TYPE *,
HOST_WIDE_INT));
+/* Standard round to integer value functions. */
+extern void real_trunc PARAMS ((REAL_VALUE_TYPE *,
+ enum machine_mode,
+ const REAL_VALUE_TYPE *));
+extern void real_floor PARAMS ((REAL_VALUE_TYPE *,
+ enum machine_mode,
+ const REAL_VALUE_TYPE *));
+extern void real_ceil PARAMS ((REAL_VALUE_TYPE *,
+ enum machine_mode,
+ const REAL_VALUE_TYPE *));
+
#endif /* ! GCC_REAL_H */
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 7e4c0e6..b2db902 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2003-07-03 Roger Sayle <roger@eyesopen.com>
+
+ * gcc.dg/builtins-25.c: New testcase.
+ * gcc.dg/builtins-26.c: New testcase.
+
2003-07-03 Janis Johnson <janis187@us.ibm.com>
* gcc.dg/compat/vector-defs.h: New file.
diff --git a/gcc/testsuite/gcc.dg/builtins-25.c b/gcc/testsuite/gcc.dg/builtins-25.c
new file mode 100644
index 0000000..4950566
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtins-25.c
@@ -0,0 +1,188 @@
+/* Copyright (C) 2003 Free Software Foundation.
+
+ Check that constant folding of built-in math functions doesn't
+ break anything and produces the expected results.
+
+ Written by Roger Sayle, 28th June 2003. */
+
+/* { dg-do link } */
+/* { dg-options "-O2" } */
+
+extern void link_error(void);
+
+extern double trunc(double);
+extern double floor(double);
+extern double ceil(double);
+
+extern float truncf(float);
+extern float floorf(float);
+extern float ceilf(float);
+
+extern long double truncl(long double);
+extern long double floorl(long double);
+extern long double ceill(long double);
+
+void test()
+{
+ if (trunc (0.0) != 0.0)
+ link_error ();
+ if (floor (0.0) != 0.0)
+ link_error ();
+ if (ceil (0.0) != 0.0)
+ link_error ();
+
+ if (trunc (6.0) != 6.0)
+ link_error ();
+ if (floor (6.0) != 6.0)
+ link_error ();
+ if (ceil (6.0) != 6.0)
+ link_error ();
+
+ if (trunc (-8.0) != -8.0)
+ link_error ();
+ if (floor (-8.0) != -8.0)
+ link_error ();
+ if (ceil (-8.0) != -8.0)
+ link_error ();
+
+ if (trunc (3.2) != 3.0)
+ link_error ();
+ if (floor (3.2) != 3.0)
+ link_error ();
+ if (ceil (3.2) != 4.0)
+ link_error ();
+
+ if (trunc (-2.8) != -2.0)
+ link_error ();
+ if (floor (-2.8) != -3.0)
+ link_error ();
+ if (ceil (-2.8) != -2.0)
+ link_error ();
+
+ if (trunc (0.01) != 0.0)
+ link_error ();
+ if (floor (0.01) != 0.0)
+ link_error ();
+ if (ceil (0.01) != 1.0)
+ link_error ();
+
+ if (trunc (-0.7) != 0.0)
+ link_error ();
+ if (floor (-0.7) != -1.0)
+ link_error ();
+ if (ceil (-0.7) != 0.0)
+ link_error ();
+}
+
+void testf()
+{
+ if (truncf (0.0f) != 0.0f)
+ link_error ();
+ if (floorf (0.0f) != 0.0f)
+ link_error ();
+ if (ceilf (0.0f) != 0.0f)
+ link_error ();
+
+ if (truncf (6.0f) != 6.0f)
+ link_error ();
+ if (floorf (6.0f) != 6.0f)
+ link_error ();
+ if (ceilf (6.0f) != 6.0f)
+ link_error ();
+
+ if (truncf (-8.0f) != -8.0f)
+ link_error ();
+ if (floorf (-8.0f) != -8.0f)
+ link_error ();
+ if (ceilf (-8.0f) != -8.0f)
+ link_error ();
+
+ if (truncf (3.2f) != 3.0f)
+ link_error ();
+ if (floorf (3.2f) != 3.0f)
+ link_error ();
+ if (ceilf (3.2f) != 4.0f)
+ link_error ();
+
+ if (truncf (-2.8f) != -2.0f)
+ link_error ();
+ if (floorf (-2.8f) != -3.0f)
+ link_error ();
+ if (ceilf (-2.8f) != -2.0f)
+ link_error ();
+
+ if (truncf (0.01f) != 0.0f)
+ link_error ();
+ if (floorf (0.01f) != 0.0f)
+ link_error ();
+ if (ceilf (0.01f) != 1.0f)
+ link_error ();
+
+ if (truncf (-0.7f) != 0.0f)
+ link_error ();
+ if (floorf (-0.7f) != -1.0f)
+ link_error ();
+ if (ceilf (-0.7f) != 0.0f)
+ link_error ();
+}
+
+void testl()
+{
+ if (truncl (0.0l) != 0.0l)
+ link_error ();
+ if (floorl (0.0l) != 0.0l)
+ link_error ();
+ if (ceill (0.0l) != 0.0l)
+ link_error ();
+
+ if (truncl (6.0l) != 6.0l)
+ link_error ();
+ if (floorl (6.0l) != 6.0l)
+ link_error ();
+ if (ceill (6.0l) != 6.0l)
+ link_error ();
+
+ if (truncl (-8.0l) != -8.0l)
+ link_error ();
+ if (floorl (-8.0l) != -8.0l)
+ link_error ();
+ if (ceill (-8.0l) != -8.0l)
+ link_error ();
+
+ if (truncl (3.2l) != 3.0l)
+ link_error ();
+ if (floorl (3.2l) != 3.0l)
+ link_error ();
+ if (ceill (3.2l) != 4.0l)
+ link_error ();
+
+ if (truncl (-2.8l) != -2.0l)
+ link_error ();
+ if (floorl (-2.8l) != -3.0l)
+ link_error ();
+ if (ceill (-2.8l) != -2.0l)
+ link_error ();
+
+ if (truncl (0.01l) != 0.0l)
+ link_error ();
+ if (floorl (0.01l) != 0.0l)
+ link_error ();
+ if (ceill (0.01l) != 1.0l)
+ link_error ();
+
+ if (truncl (-0.7l) != 0.0l)
+ link_error ();
+ if (floorl (-0.7l) != -1.0l)
+ link_error ();
+ if (ceill (-0.7l) != 0.0l)
+ link_error ();
+}
+
+int main()
+{
+ test ();
+ testf ();
+ testl ();
+ return 0;
+}
+
diff --git a/gcc/testsuite/gcc.dg/builtins-26.c b/gcc/testsuite/gcc.dg/builtins-26.c
new file mode 100644
index 0000000..c4d03cd
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtins-26.c
@@ -0,0 +1,105 @@
+/* Copyright (C) 2003 Free Software Foundation.
+
+ Check that constant folding of built-in math functions doesn't
+ break anything and produces the expected results.
+
+ Written by Roger Sayle, 28th June 2003. */
+
+/* { dg-do link } */
+/* { dg-options "-O2 -ffast-math" } */
+
+extern void link_error(void);
+
+extern double trunc(double);
+extern double floor(double);
+extern double ceil(double);
+
+extern float truncf(float);
+extern float floorf(float);
+extern float ceilf(float);
+
+extern long double truncl(long double);
+extern long double floorl(long double);
+extern long double ceill(long double);
+
+void test(double x)
+{
+ if (trunc (trunc (x)) != trunc (x))
+ link_error ();
+ if (trunc (floor (x)) != floor (x))
+ link_error ();
+ if (trunc (ceil (x)) != ceil (x))
+ link_error ();
+
+ if (floor (trunc (x)) != trunc (x))
+ link_error ();
+ if (floor (floor (x)) != floor (x))
+ link_error ();
+ if (floor (ceil (x)) != ceil (x))
+ link_error ();
+
+ if (ceil (trunc (x)) != trunc (x))
+ link_error ();
+ if (ceil (floor (x)) != floor (x))
+ link_error ();
+ if (ceil (ceil (x)) != ceil (x))
+ link_error ();
+}
+
+void testf(float x)
+{
+ if (truncf (truncf (x)) != truncf (x))
+ link_error ();
+ if (truncf (floorf (x)) != floorf (x))
+ link_error ();
+ if (truncf (ceilf (x)) != ceilf (x))
+ link_error ();
+
+ if (floorf (truncf (x)) != truncf (x))
+ link_error ();
+ if (floorf (floorf (x)) != floorf (x))
+ link_error ();
+ if (floorf (ceilf (x)) != ceilf (x))
+ link_error ();
+
+ if (ceilf (truncf (x)) != truncf (x))
+ link_error ();
+ if (ceilf (floorf (x)) != floorf (x))
+ link_error ();
+ if (ceilf (ceilf (x)) != ceilf (x))
+ link_error ();
+}
+
+void testl(long double x)
+{
+ if (truncl (truncl (x)) != truncl (x))
+ link_error ();
+ if (truncl (floorl (x)) != floorl (x))
+ link_error ();
+ if (truncl (ceill (x)) != ceill (x))
+ link_error ();
+
+ if (floorl (truncl (x)) != truncl (x))
+ link_error ();
+ if (floorl (floorl (x)) != floorl (x))
+ link_error ();
+ if (floorl (ceill (x)) != ceill (x))
+ link_error ();
+
+ if (ceill (truncl (x)) != truncl (x))
+ link_error ();
+ if (ceill (floorl (x)) != floorl (x))
+ link_error ();
+ if (ceill (ceill (x)) != ceill (x))
+ link_error ();
+}
+
+
+int main()
+{
+ test (3.2);
+ testf (3.2f);
+ testl (3.2l);
+ return 0;
+}
+