aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/config/i386/i386-expand.c37
-rw-r--r--gcc/config/i386/i386.md18
-rw-r--r--gcc/testsuite/gcc.dg/pr102224.c49
-rw-r--r--gcc/testsuite/gcc.target/i386/avx-pr102224.c23
4 files changed, 116 insertions, 11 deletions
diff --git a/gcc/config/i386/i386-expand.c b/gcc/config/i386/i386-expand.c
index dfffbe5..0cc572c 100644
--- a/gcc/config/i386/i386-expand.c
+++ b/gcc/config/i386/i386-expand.c
@@ -2306,12 +2306,39 @@ ix86_split_xorsign (rtx operands[])
mode = GET_MODE (dest);
vmode = GET_MODE (mask);
- op1 = lowpart_subreg (vmode, op1, mode);
- x = gen_rtx_AND (vmode, op1, mask);
- emit_insn (gen_rtx_SET (op1, x));
+ /* The constraints ensure that for non-AVX dest == op1 is
+ different from op0, and for AVX that at most two of
+ dest, op0 and op1 are the same register but the third one
+ is different. */
+ if (rtx_equal_p (op0, op1))
+ {
+ gcc_assert (TARGET_AVX && !rtx_equal_p (op0, dest));
+ if (vmode == V4SFmode)
+ vmode = V4SImode;
+ else
+ {
+ gcc_assert (vmode == V2DFmode);
+ vmode = V2DImode;
+ }
+ mask = lowpart_subreg (vmode, mask, GET_MODE (mask));
+ if (MEM_P (mask))
+ {
+ rtx msk = lowpart_subreg (vmode, dest, mode);
+ emit_insn (gen_rtx_SET (msk, mask));
+ mask = msk;
+ }
+ op0 = lowpart_subreg (vmode, op0, mode);
+ x = gen_rtx_AND (vmode, gen_rtx_NOT (vmode, mask), op0);
+ }
+ else
+ {
+ op1 = lowpart_subreg (vmode, op1, mode);
+ x = gen_rtx_AND (vmode, op1, mask);
+ emit_insn (gen_rtx_SET (op1, x));
- op0 = lowpart_subreg (vmode, op0, mode);
- x = gen_rtx_XOR (vmode, op1, op0);
+ op0 = lowpart_subreg (vmode, op0, mode);
+ x = gen_rtx_XOR (vmode, op1, op0);
+ }
dest = lowpart_subreg (vmode, dest, mode);
emit_insn (gen_rtx_SET (dest, x));
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index fe36d7e..0414f24 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -10910,21 +10910,27 @@
(match_operand:MODEF 1 "register_operand")
(match_operand:MODEF 2 "register_operand")]
"SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH"
- "ix86_expand_xorsign (operands); DONE;")
+{
+ if (rtx_equal_p (operands[1], operands[2]))
+ emit_insn (gen_abs<mode>2 (operands[0], operands[1]));
+ else
+ ix86_expand_xorsign (operands);
+ DONE;
+})
(define_insn_and_split "@xorsign<mode>3_1"
- [(set (match_operand:MODEF 0 "register_operand" "=Yv,Yv")
+ [(set (match_operand:MODEF 0 "register_operand" "=&Yv,&Yv,&Yv")
(unspec:MODEF
- [(match_operand:MODEF 1 "register_operand" "Yv,Yv")
- (match_operand:MODEF 2 "register_operand" "0,Yv")
- (match_operand:<ssevecmode> 3 "nonimmediate_operand" "Yvm,Yvm")]
+ [(match_operand:MODEF 1 "register_operand" "Yv,0,Yv")
+ (match_operand:MODEF 2 "register_operand" "0,Yv,Yv")
+ (match_operand:<ssevecmode> 3 "nonimmediate_operand" "Yvm,Yvm,Yvm")]
UNSPEC_XORSIGN))]
"SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH"
"#"
"&& reload_completed"
[(const_int 0)]
"ix86_split_xorsign (operands); DONE;"
- [(set_attr "isa" "noavx,avx")])
+ [(set_attr "isa" "*,avx,avx")])
;; One complement instructions
diff --git a/gcc/testsuite/gcc.dg/pr102224.c b/gcc/testsuite/gcc.dg/pr102224.c
new file mode 100644
index 0000000..9f09ba5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr102224.c
@@ -0,0 +1,49 @@
+/* PR target/102224 */
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+__attribute__((noipa)) float
+foo (float x)
+{
+ return x * __builtin_copysignf (1.0f, x);
+}
+
+__attribute__((noipa)) float
+bar (float x, float y)
+{
+ return x * __builtin_copysignf (1.0f, y);
+}
+
+__attribute__((noipa)) float
+baz (float z, float x)
+{
+ return x * __builtin_copysignf (1.0f, x);
+}
+
+__attribute__((noipa)) float
+qux (float z, float x, float y)
+{
+ return x * __builtin_copysignf (1.0f, y);
+}
+
+int
+main ()
+{
+ if (foo (1.0f) != 1.0f
+ || foo (-4.0f) != 4.0f)
+ __builtin_abort ();
+ if (bar (1.25f, 7.25f) != 1.25f
+ || bar (1.75f, -3.25f) != -1.75f
+ || bar (-2.25f, 7.5f) != -2.25f
+ || bar (-3.0f, -4.0f) != 3.0f)
+ __builtin_abort ();
+ if (baz (5.5f, 1.0f) != 1.0f
+ || baz (4.25f, -4.0f) != 4.0f)
+ __builtin_abort ();
+ if (qux (1.0f, 1.25f, 7.25f) != 1.25f
+ || qux (2.0f, 1.75f, -3.25f) != -1.75f
+ || qux (3.0f, -2.25f, 7.5f) != -2.25f
+ || qux (4.0f, -3.0f, -4.0f) != 3.0f)
+ __builtin_abort ();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/avx-pr102224.c b/gcc/testsuite/gcc.target/i386/avx-pr102224.c
new file mode 100644
index 0000000..be6b88c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/avx-pr102224.c
@@ -0,0 +1,23 @@
+/* PR tree-optimization/51581 */
+/* { dg-do run } */
+/* { dg-options "-O2 -mavx" } */
+/* { dg-require-effective-target avx } */
+
+#ifndef CHECK_H
+#define CHECK_H "avx-check.h"
+#endif
+#ifndef TEST
+#define TEST avx_test
+#endif
+
+#define main main1
+#include "../../gcc.dg/pr102224.c"
+#undef main
+
+#include CHECK_H
+
+static void
+TEST (void)
+{
+ main1 ();
+}