diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/config/i386/i386-expand.c | 37 | ||||
-rw-r--r-- | gcc/config/i386/i386.md | 18 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/pr102224.c | 49 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/i386/avx-pr102224.c | 23 |
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 (); +} |