(hypots @0 (copysigns @1 @2))
(hypots @0 @1))))
-/* copysign(x, CST) -> [-]abs (x). */
+/* copysign(x, CST) -> abs (x). */
(for copysigns (COPYSIGN_ALL)
(simplify
(copysigns @0 REAL_CST@1)
- (if (REAL_VALUE_NEGATIVE (TREE_REAL_CST (@1)))
- (negate (abs @0))
+ (if (!REAL_VALUE_NEGATIVE (TREE_REAL_CST (@1)))
(abs @0))))
+/* Transform fneg (fabs (X)) -> copysign (X, -1). */
+(simplify
+ (negate (abs @0))
+ (IFN_COPYSIGN @0 { build_minus_one_cst (type); }))
+
/* copysign(copysign(x, y), z) -> copysign(x, z). */
(for copysigns (COPYSIGN_ALL)
(simplify
return __builtin_copysign (x, minuszero);
}
-/* { dg-final { scan-tree-dump-times "= -" 1 "cddce1" } } */
-/* { dg-final { scan-tree-dump-times "= ABS_EXPR" 2 "cddce1" } } */
+/* { dg-final { scan-tree-dump-times "__builtin_copysign" 1 "cddce1" } } */
+/* { dg-final { scan-tree-dump-times "= ABS_EXPR" 1 "cddce1" } } */
return (a<-a)?a:-a;
}
-/* { dg-final { scan-tree-dump-times "ABS_EXPR" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "\.COPYSIGN" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "ABS_EXPR" 1 "optimized" } } */
/* __builtin_signbit(x) ? x : -x. Should be convert into - ABS_EXP<x> */
/* { dg-final { scan-tree-dump-not "signbit" "optimized"} } */
-/* { dg-final { scan-tree-dump-times "= ABS_EXPR" 3 "optimized"} } */
-/* { dg-final { scan-tree-dump-times "= -" 3 "optimized"} } */
+/* { dg-final { scan-tree-dump-times "= ABS_EXPR" 1 "optimized"} } */
+/* { dg-final { scan-tree-dump-times "= -" 1 "optimized"} } */
+/* { dg-final { scan-tree-dump-times "= \.COPYSIGN" 2 "optimized"} } */
TEST_FUNCTION (double, )
TEST_FUNCTION (long double, l)
-/* { dg-final { scan-tree-dump-times {Deleting[^\n]* = -} 6 "backprop" } } */
-/* { dg-final { scan-tree-dump-times {Deleting[^\n]* = ABS_EXPR <} 3 "backprop" } } */
+/* { dg-final { scan-tree-dump-times {Deleting[^\n]* = -} 4 "backprop" } } */
+/* { dg-final { scan-tree-dump-times {Deleting[^\n]* = \.COPYSIGN} 2 "backprop" } } */
+/* { dg-final { scan-tree-dump-times {Deleting[^\n]* = ABS_EXPR <} 1 "backprop" } } */
float t = __builtin_copysignf (1.0f, -x);
return x * t;
}
-/* { dg-final { scan-tree-dump-times "ABS" 2 "optimized"} } */
+/* { dg-final { scan-tree-dump-times "ABS" 1 "optimized"} } */
+/* { dg-final { scan-tree-dump-times ".COPYSIGN" 1 "optimized"} } */
{
return x * (x <= 0.f ? 1.f : -1.f);
}
-/* { dg-final { scan-tree-dump-times "ABS" 8 "gimple"} } */
+/* { dg-final { scan-tree-dump-times "ABS" 4 "gimple"} } */
+/* { dg-final { scan-tree-dump-times "\.COPYSIGN" 4 "gimple"} } */
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-O3" } */
+/* { dg-final { check-function-bodies "**" "" "" { target lp64 } } } */
+
+#pragma GCC target "+nosve"
+
+#include <arm_neon.h>
+
+/*
+** t1:
+** orr v[0-9]+.2s, #128, lsl #24
+** ret
+*/
+float32x2_t t1 (float32x2_t a)
+{
+ return vneg_f32 (vabs_f32 (a));
+}
+
+/*
+** t2:
+** orr v[0-9]+.4s, #128, lsl #24
+** ret
+*/
+float32x4_t t2 (float32x4_t a)
+{
+ return vnegq_f32 (vabsq_f32 (a));
+}
+
+/*
+** t3:
+** adrp x0, .LC[0-9]+
+** ldr q[0-9]+, \[x0, #:lo12:.LC0\]
+** orr v[0-9]+.16b, v[0-9]+.16b, v[0-9]+.16b
+** ret
+*/
+float64x2_t t3 (float64x2_t a)
+{
+ return vnegq_f64 (vabsq_f64 (a));
+}
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-O3" } */
+/* { dg-final { check-function-bodies "**" "" "" { target lp64 } } } */
+
+#pragma GCC target "+nosve"
+
+#include <arm_neon.h>
+#include <math.h>
+
+/*
+** f1:
+** movi v[0-9]+.2s, 0x80, lsl 24
+** orr v[0-9]+.8b, v[0-9]+.8b, v[0-9]+.8b
+** ret
+*/
+float32_t f1 (float32_t a)
+{
+ return -fabsf (a);
+}
+
+/*
+** f2:
+** mov x0, -9223372036854775808
+** fmov d[0-9]+, x0
+** orr v[0-9]+.8b, v[0-9]+.8b, v[0-9]+.8b
+** ret
+*/
+float64_t f2 (float64_t a)
+{
+ return -fabs (a);
+}
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-O3" } */
+/* { dg-final { check-function-bodies "**" "" "" { target lp64 } } } */
+
+#pragma GCC target "+nosve"
+
+#include <arm_neon.h>
+#include <math.h>
+
+/*
+** f1:
+** ...
+** ldr q[0-9]+, \[x0\]
+** orr v[0-9]+.4s, #128, lsl #24
+** str q[0-9]+, \[x0\], 16
+** ...
+*/
+void f1 (float32_t *a, int n)
+{
+ for (int i = 0; i < (n & -8); i++)
+ a[i] = -fabsf (a[i]);
+}
+
+/*
+** f2:
+** ...
+** ldr q[0-9]+, \[x0\]
+** orr v[0-9]+.16b, v[0-9]+.16b, v[0-9]+.16b
+** str q[0-9]+, \[x0\], 16
+** ...
+*/
+void f2 (float64_t *a, int n)
+{
+ for (int i = 0; i < (n & -8); i++)
+ a[i] = -fabs (a[i]);
+}
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-O3" } */
+/* { dg-final { check-function-bodies "**" "" "" { target lp64 } } } */
+
+#pragma GCC target "+nosve"
+
+#include <string.h>
+
+/*
+** negabs:
+** mov x0, -9223372036854775808
+** fmov d[0-9]+, x0
+** orr v[0-9]+.8b, v[0-9]+.8b, v[0-9]+.8b
+** ret
+*/
+double negabs (double x)
+{
+ unsigned long long y;
+ memcpy (&y, &x, sizeof(double));
+ y = y | (1UL << 63);
+ memcpy (&x, &y, sizeof(double));
+ return x;
+}
+
+/*
+** negabsf:
+** movi v[0-9]+.2s, 0x80, lsl 24
+** orr v[0-9]+.8b, v[0-9]+.8b, v[0-9]+.8b
+** ret
+*/
+float negabsf (float x)
+{
+ unsigned int y;
+ memcpy (&y, &x, sizeof(float));
+ y = y | (1U << 31);
+ memcpy (&x, &y, sizeof(float));
+ return x;
+}
+
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-O3" } */
+/* { dg-final { check-function-bodies "**" "" "" { target lp64 } } } */
+
+#include <arm_neon.h>
+
+/*
+** t1:
+** orr v[0-9]+.2s, #128, lsl #24
+** ret
+*/
+float32x2_t t1 (float32x2_t a)
+{
+ return vneg_f32 (vabs_f32 (a));
+}
+
+/*
+** t2:
+** orr v[0-9]+.4s, #128, lsl #24
+** ret
+*/
+float32x4_t t2 (float32x4_t a)
+{
+ return vnegq_f32 (vabsq_f32 (a));
+}
+
+/*
+** t3:
+** adrp x0, .LC[0-9]+
+** ldr q[0-9]+, \[x0, #:lo12:.LC0\]
+** orr v[0-9]+.16b, v[0-9]+.16b, v[0-9]+.16b
+** ret
+*/
+float64x2_t t3 (float64x2_t a)
+{
+ return vnegq_f64 (vabsq_f64 (a));
+}
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-O3" } */
+/* { dg-final { check-function-bodies "**" "" "" { target lp64 } } } */
+
+#include <arm_neon.h>
+#include <math.h>
+
+/*
+** f1:
+** movi v[0-9]+.2s, 0x80, lsl 24
+** orr v[0-9]+.8b, v[0-9]+.8b, v[0-9]+.8b
+** ret
+*/
+float32_t f1 (float32_t a)
+{
+ return -fabsf (a);
+}
+
+/*
+** f2:
+** mov x0, -9223372036854775808
+** fmov d[0-9]+, x0
+** orr v[0-9]+.8b, v[0-9]+.8b, v[0-9]+.8b
+** ret
+*/
+float64_t f2 (float64_t a)
+{
+ return -fabs (a);
+}
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-O3" } */
+/* { dg-final { check-function-bodies "**" "" "" { target lp64 } } } */
+
+#include <arm_neon.h>
+#include <math.h>
+
+/*
+** f1:
+** ...
+** ld1w z[0-9]+.s, p[0-9]+/z, \[x0, x2, lsl 2\]
+** orr z[0-9]+.s, z[0-9]+.s, #0x80000000
+** st1w z[0-9]+.s, p[0-9]+, \[x0, x2, lsl 2\]
+** ...
+*/
+void f1 (float32_t *a, int n)
+{
+ for (int i = 0; i < (n & -8); i++)
+ a[i] = -fabsf (a[i]);
+}
+
+/*
+** f2:
+** ...
+** ld1d z[0-9]+.d, p[0-9]+/z, \[x0, x2, lsl 3\]
+** orr z[0-9]+.d, z[0-9]+.d, #0x8000000000000000
+** st1d z[0-9]+.d, p[0-9]+, \[x0, x2, lsl 3\]
+** ...
+*/
+void f2 (float64_t *a, int n)
+{
+ for (int i = 0; i < (n & -8); i++)
+ a[i] = -fabs (a[i]);
+}
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-O3" } */
+/* { dg-final { check-function-bodies "**" "" "" { target lp64 } } } */
+
+#include <string.h>
+
+/*
+** negabs:
+** mov x0, -9223372036854775808
+** fmov d[0-9]+, x0
+** orr v[0-9]+.8b, v[0-9]+.8b, v[0-9]+.8b
+** ret
+*/
+double negabs (double x)
+{
+ unsigned long long y;
+ memcpy (&y, &x, sizeof(double));
+ y = y | (1UL << 63);
+ memcpy (&x, &y, sizeof(double));
+ return x;
+}
+
+/*
+** negabsf:
+** movi v[0-9]+.2s, 0x80, lsl 24
+** orr v[0-9]+.8b, v[0-9]+.8b, v[0-9]+.8b
+** ret
+*/
+float negabsf (float x)
+{
+ unsigned int y;
+ memcpy (&y, &x, sizeof(float));
+ y = y | (1U << 31);
+ memcpy (&x, &y, sizeof(float));
+ return x;
+}
+