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;
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;
x2 -= 1;
Compensate. Ceil:
if (x2 < x)
- x2 += 1;
+ x2 -= -1;
return x2;
*/
enum machine_mode mode = GET_MODE (operand0);
/* 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);
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);
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);
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;
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);
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);
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;
--- /dev/null
+/* { 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;
+}