From 7e35fcb30ed8bebbdfc240ac25cb2190f8bdb526 Mon Sep 17 00:00:00 2001 From: Richard Guenther Date: Wed, 1 Nov 2006 11:38:06 +0000 Subject: [PATCH] i386.c (ix86_expand_rint): Fix issues with signed zeros. 2006-11-01 Richard Guenther * config/i386/i386.c (ix86_expand_rint): Fix issues with signed zeros. (ix86_expand_floorceildf_32): Likewise. (ix86_expand_floorceil): Likewise. (ix86_expand_trunc): Likewise. * testsuite/gcc.target/i386/fpprec-1.c: New testcase. From-SVN: r118373 --- gcc/ChangeLog | 8 +++ gcc/config/i386/i386.c | 45 ++++++++++------ gcc/testsuite/ChangeLog | 4 ++ gcc/testsuite/gcc.target/i386/fpprec-1.c | 90 ++++++++++++++++++++++++++++++++ 4 files changed, 132 insertions(+), 15 deletions(-) create mode 100644 gcc/testsuite/gcc.target/i386/fpprec-1.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e39026c..322bb4b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2006-11-01 Richard Guenther + + * config/i386/i386.c (ix86_expand_rint): Fix issues with + signed zeros. + (ix86_expand_floorceildf_32): Likewise. + (ix86_expand_floorceil): Likewise. + (ix86_expand_trunc): Likewise. + 2006-10-31 Andrew Pinski * doc/invoke.texi (-fkeep-inline-functions): Change "GNU C" diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index a7919dc..d2e19a0 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -19423,10 +19423,11 @@ void ix86_expand_rint (rtx operand0, rtx operand1) { /* C code for the stuff we're doing below: - if (!isless (fabs (operand1), 2**52)) + xa = fabs (operand1); + if (!isless (xa, 2**52)) return operand1; - tmp = copysign (2**52, operand1); - return operand1 + tmp - tmp; + xa = xa + 2**52 - 2**52; + return copysign (xa, operand1); */ enum machine_mode mode = GET_MODE (operand0); rtx res, xa, label, TWO52, mask; @@ -19441,10 +19442,10 @@ ix86_expand_rint (rtx operand0, rtx operand1) TWO52 = ix86_gen_TWO52 (mode); label = ix86_expand_sse_compare_and_jump (UNLE, TWO52, xa, false); - ix86_sse_copysign_to_positive (TWO52, TWO52, res, mask); + expand_simple_binop (mode, PLUS, xa, TWO52, xa, 0, OPTAB_DIRECT); + expand_simple_binop (mode, MINUS, xa, TWO52, xa, 0, OPTAB_DIRECT); - expand_simple_binop (mode, PLUS, res, TWO52, res, 0, OPTAB_DIRECT); - expand_simple_binop (mode, MINUS, res, TWO52, res, 0, OPTAB_DIRECT); + ix86_sse_copysign_to_positive (res, xa, res, mask); emit_label (label); LABEL_NUSES (label) = 1; @@ -19468,7 +19469,7 @@ ix86_expand_floorceildf_32 (rtx operand0, rtx operand1, bool do_floor) x2 -= 1; Compensate. Ceil: if (x2 < x) - x2 += 1; + x2 -= -1; return x2; */ enum machine_mode mode = GET_MODE (operand0); @@ -19494,14 +19495,17 @@ ix86_expand_floorceildf_32 (rtx operand0, rtx operand1, bool do_floor) /* xa = copysign (xa, operand1) */ ix86_sse_copysign_to_positive (xa, xa, res, mask); - /* generate 1.0 */ - one = force_reg (mode, const_double_from_real_value (dconst1, mode)); + /* generate 1.0 or -1.0 */ + one = force_reg (mode, + const_double_from_real_value (do_floor + ? dconst1 : dconstm1, mode)); /* Compensate: xa = xa - (xa > operand1 ? 1 : 0) */ tmp = ix86_expand_sse_compare_mask (UNGT, xa, res, !do_floor); emit_insn (gen_rtx_SET (VOIDmode, tmp, gen_rtx_AND (mode, one, tmp))); - expand_simple_binop (mode, do_floor ? MINUS : PLUS, + /* We always need to subtract here to preserve signed zero. */ + expand_simple_binop (mode, MINUS, xa, tmp, res, 0, OPTAB_DIRECT); emit_label (label); @@ -19526,10 +19530,12 @@ ix86_expand_floorceil (rtx operand0, rtx operand1, bool do_floor) Compensate. Ceil: if (x2 < x) x2 += 1; + if (HONOR_SIGNED_ZEROS (mode)) + return copysign (x2, x); return x2; */ enum machine_mode mode = GET_MODE (operand0); - rtx xa, xi, TWO52, tmp, label, one, res; + rtx xa, xi, TWO52, tmp, label, one, res, mask; TWO52 = ix86_gen_TWO52 (mode); @@ -19539,7 +19545,7 @@ ix86_expand_floorceil (rtx operand0, rtx operand1, bool do_floor) emit_move_insn (res, operand1); /* xa = abs (operand1) */ - xa = ix86_expand_sse_fabs (res, NULL); + xa = ix86_expand_sse_fabs (res, &mask); /* if (!isless (xa, TWO52)) goto label; */ label = ix86_expand_sse_compare_and_jump (UNLE, TWO52, xa, false); @@ -19559,6 +19565,9 @@ ix86_expand_floorceil (rtx operand0, rtx operand1, bool do_floor) expand_simple_binop (mode, do_floor ? MINUS : PLUS, xa, tmp, res, 0, OPTAB_DIRECT); + if (HONOR_SIGNED_ZEROS (mode)) + ix86_sse_copysign_to_positive (res, res, force_reg (mode, operand1), mask); + emit_label (label); LABEL_NUSES (label) = 1; @@ -19650,10 +19659,13 @@ ix86_expand_trunc (rtx operand0, rtx operand1) double xa = fabs (x), x2; if (!isless (xa, TWO52)) return x; - return (double)(long)x; + x2 = (double)(long)x; + if (HONOR_SIGNED_ZEROS (mode)) + return copysign (x2, x); + return x2; */ enum machine_mode mode = GET_MODE (operand0); - rtx xa, xi, TWO52, label, res; + rtx xa, xi, TWO52, label, res, mask; TWO52 = ix86_gen_TWO52 (mode); @@ -19663,7 +19675,7 @@ ix86_expand_trunc (rtx operand0, rtx operand1) emit_move_insn (res, operand1); /* xa = abs (operand1) */ - xa = ix86_expand_sse_fabs (res, NULL); + xa = ix86_expand_sse_fabs (res, &mask); /* if (!isless (xa, TWO52)) goto label; */ label = ix86_expand_sse_compare_and_jump (UNLE, TWO52, xa, false); @@ -19673,6 +19685,9 @@ ix86_expand_trunc (rtx operand0, rtx operand1) expand_fix (xi, res, 0); expand_float (res, xi, 0); + if (HONOR_SIGNED_ZEROS (mode)) + ix86_sse_copysign_to_positive (res, res, force_reg (mode, operand1), mask); + emit_label (label); LABEL_NUSES (label) = 1; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index c63a1d9..4ca24be 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2006-11-01 Richard Guenther + + * testsuite/gcc.target/i386/fpprec-1.c: New testcase. + 2006-11-01 Kaveh R. Ghazi * gcc.dg/torture/builtin-attr-1.c: Don't test gamma/lgamma. diff --git a/gcc/testsuite/gcc.target/i386/fpprec-1.c b/gcc/testsuite/gcc.target/i386/fpprec-1.c new file mode 100644 index 0000000..ff600b2 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/fpprec-1.c @@ -0,0 +1,90 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -fno-math-errno -fno-trapping-math -msse2 -mfpmath=sse" } */ + +#include "../../gcc.dg/i386-cpuid.h" + +extern void abort(void); +extern int printf(const char *format, ...); + +double x[] = { __builtin_nan(""), __builtin_inf(), -__builtin_inf(), + -0x1.fffffffffffffp+1023, 0x1.fffffffffffffp+1023, /* +-DBL_MAX */ + -0x1p-52, 0x1p-52, /* +-DBL_EPSILON */ + /* nextafter/before 0.5, 1.0 and 1.5 */ + 0x1.0000000000001p-1, 0x1.fffffffffffffp-2, + 0x1.0000000000001p+0, 0x1.fffffffffffffp-1, + 0x1.8000000000001p+0, 0x1.7ffffffffffffp+0, + -0.0, 0.0, -0.5, 0.5, -1.0, 1.0, -1.5, 1.5, -2.0, 2.0, + -2.5, 2.5 }; +#define NUM (sizeof(x)/sizeof(double)) + +double expect_round[] = { __builtin_nan(""), __builtin_inf(), -__builtin_inf(), + -0x1.fffffffffffffp+1023, 0x1.fffffffffffffp+1023, + -0.0, 0.0, + 1.0, 0.0, 1.0, 1.0, 2.0, 1.0, + -0.0, 0.0, -1.0, 1.0, -1.0, 1.0, -2.0, 2.0, -2.0, 2.0, + -3.0, 3.0 }; + +double expect_rint[] = { __builtin_nan(""), __builtin_inf(), -__builtin_inf(), + -0x1.fffffffffffffp+1023, 0x1.fffffffffffffp+1023, + -0.0, 0.0, + 1.0, 0.0, 1.0, 1.0, 2.0, 1.0, + -0.0, 0.0, -0.0, 0.0, -1.0, 1.0, -2.0, 2.0, -2.0, 2.0, + -2.0, 2.0 }; + +double expect_floor[] = { __builtin_nan(""), __builtin_inf(), -__builtin_inf(), + -0x1.fffffffffffffp+1023, 0x1.fffffffffffffp+1023, + -1.0, 0.0, + 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, + -0.0, 0.0, -1.0, 0.0, -1.0, 1.0, -2.0, 1.0, -2.0, 2.0, + -3.0, 2.0 }; + +double expect_ceil[] = { __builtin_nan(""), __builtin_inf(), -__builtin_inf(), + -0x1.fffffffffffffp+1023, 0x1.fffffffffffffp+1023, + -0.0, 1.0, + 1.0, 1.0, 2.0, 1.0, 2.0, 2.0, + -0.0, 0.0, -0.0, 1.0, -1.0, 1.0, -1.0, 2.0, -2.0, 2.0, + -2.0, 3.0 }; + +double expect_trunc[] = { __builtin_nan(""), __builtin_inf(), -__builtin_inf(), + -0x1.fffffffffffffp+1023, 0x1.fffffffffffffp+1023, + -0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, + -0.0, 0.0, -0.0, 0.0, -1.0, 1.0, -1.0, 1.0, -2.0, 2.0, + -2.0, 2.0 }; + + +#define CHECK(fn) \ +void check_ ## fn (void) \ +{ \ + int i; \ + for (i = 0; i < NUM; ++i) \ + { \ + double res = __builtin_ ## fn (x[i]); \ + if (__builtin_memcmp (&res, &expect_ ## fn [i], sizeof(double)) != 0) \ + printf( # fn " [%i]: %.18e %.18e\n", i, expect_ ## fn [i], res), abort (); \ + } \ +} + +CHECK(round) +CHECK(rint) +CHECK(floor) +CHECK(ceil) +CHECK(trunc) + +int main() +{ + unsigned long cpu_facilities; + + cpu_facilities = i386_cpuid (); + + if ((cpu_facilities & bit_SSE2) != bit_SSE2) + /* If host has no SSE2 support, pass. */ + return 0; + + check_round (); + check_rint (); + check_floor (); + check_ceil (); + check_trunc (); + return 0; +} -- 2.7.4