diff mbox series

[i386] : Improve and modernize ABS/NEG patterns

Message ID CAFULd4Za66W_BSSVasOH_6vyj2wUrUis0v3ZEd4_BQsPwPAqGA@mail.gmail.com
State New
Headers show
Series [i386] : Improve and modernize ABS/NEG patterns | expand

Commit Message

Uros Bizjak June 10, 2019, 7:22 p.m. UTC
Attached patch improves ABS/NEG expander to emit clobber that enables
ABS/NEG with integer registers also when SSE is disabled. The patch
modernizes ABS/NEG insn patterns and splitters to use absneg code
iterator and relevant mode iterators. Additionally, the patch enables
three operand AVX instructions with SSE registers.

2019-06-10  Uroš Bizjak  <ubizjak@gmail.com>

    * config/i386/i386-protos.h (ix86_split_fp_absneg_operator):
    New prototype.
    * config/i386/i386-expand.c (ix86_expand_fp_absneg_operator):
    Emit clobber also for non-sse operations.
    (ix86_split_fp_absneg_operator): New function.
    * config/i386/i386.md (SSEMODEF): New mode iterator.
    (ssevecmodef): New mode attribute.
    (<code>tf2): Use absneg code iterator.
    (*<code>tf2_1): Rename from *absnegtf3_sse. Use absneg code iterator.
    Add three-operand AVX alternatives.
    (*<code><mode>2_i387_1): Rename from *absnegxf2_i387.
    Use absneg code iterator and X87MODEF mode iterator.
    (absneg fp_reg non-sse splitter): Call absneg code iterator
    and X87MODEF mode iterator.
    (absneg general_reg non-sse splitter): Use absneg code iterator
    and X87MODEF mode iterator.  Use ix86_split_fp_absneg_operator.
    (*<code><mode>2_1): Rename from *absneg<mode>2.  Use absneg
    code iterator.  Add three-operand AVX alternative.
    (absneg sse_reg splitter): Use absneg code iterator
    and SSEMODEF mode iterator.  Handle AVX operands.
    (absneg fp_reg splitter): Use absneg code iterator
    and MODEF mode iterator.
    (absneg general_reg splitter): Merge splitters using MODEF mode
    iterator.  Use absneg code iterator.  Call
    ix86_split_fp_absneg_operator.
    (*<code><mode>2_i387): Rename from *<code><mode>2_1.
    Do not enable for non-sse modes before reload.
    (CSGNMODE): Remove.
    (CSGNVMODE): Ditto.
    (copysing<mode>3): Use SSEMODEF instead of CSGNMODE and
    ssevecmodef mode attribute instaed of CSGNVMODE.
    (copysign<mode>3_const): Ditto.
    (copysign<mode>3_var): Ditto.
    * config/i386/i386.md (*<code><mode>2): Rename from *absneg<mode>2.
    Use absneg code iterator.  Simplify code using std::swap.
    * config/i386/predicates.md (absneg_operator): Remove.

Bootstrapped and regression tested on x86_64-linux-gnu {,-m32}.

Committed to mainline SVN.

Uros.
diff mbox series

Patch

Index: config/i386/i386-expand.c
===================================================================
--- config/i386/i386-expand.c	(revision 272119)
+++ config/i386/i386-expand.c	(working copy)
@@ -1704,10 +1704,11 @@  void
 ix86_expand_fp_absneg_operator (enum rtx_code code, machine_mode mode,
 				rtx operands[])
 {
-  rtx mask, set, dst, src;
+  rtx set, dst, src;
   bool use_sse = false;
   bool vector_mode = VECTOR_MODE_P (mode);
   machine_mode vmode = mode;
+  rtvec par;
 
   if (vector_mode)
     use_sse = true;
@@ -1722,13 +1723,6 @@  ix86_expand_fp_absneg_operator (enum rtx_code code
 	vmode = V2DFmode;
     }
 
-  /* NEG and ABS performed with SSE use bitwise mask operations.
-     Create the appropriate mask now.  */
-  if (use_sse)
-    mask = ix86_build_signbit_mask (vmode, vector_mode, code == ABS);
-  else
-    mask = NULL_RTX;
-
   dst = operands[0];
   src = operands[1];
 
@@ -1735,11 +1729,13 @@  ix86_expand_fp_absneg_operator (enum rtx_code code
   set = gen_rtx_fmt_e (code, mode, src);
   set = gen_rtx_SET (dst, set);
 
-  if (mask)
+  if (use_sse)
     {
-      rtx use, clob;
-      rtvec par;
+      rtx mask, use, clob;
 
+      /* NEG and ABS performed with SSE use bitwise mask operations.
+	 Create the appropriate mask now.  */
+      mask = ix86_build_signbit_mask (vmode, vector_mode, code == ABS);
       use = gen_rtx_USE (VOIDmode, mask);
       if (vector_mode)
 	par = gen_rtvec (2, set, use);
@@ -1748,12 +1744,106 @@  ix86_expand_fp_absneg_operator (enum rtx_code code
           clob = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, FLAGS_REG));
 	  par = gen_rtvec (3, set, use, clob);
         }
-      emit_insn (gen_rtx_PARALLEL (VOIDmode, par));
     }
   else
-    emit_insn (set);
+    {
+      rtx clob;
+
+      /* Changing of sign for FP values is doable using integer unit too.  */
+      clob = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, FLAGS_REG));
+      par = gen_rtvec (2, set, clob);
+    }
+
+  emit_insn (gen_rtx_PARALLEL (VOIDmode, par));
 }
 
+/* Deconstruct a floating point ABS or NEG operation
+   with integer registers into integer operations.  */
+
+void
+ix86_split_fp_absneg_operator (enum rtx_code code, machine_mode mode,
+			       rtx operands[])
+{
+  enum rtx_code absneg_op;
+  rtx dst, set;
+
+  gcc_assert (operands_match_p (operands[0], operands[1]));
+
+  switch (mode)
+    {
+    case E_SFmode:
+      dst = gen_lowpart (SImode, operands[0]);
+
+      if (code == ABS)
+	{
+	  set = gen_int_mode (0x7fffffff, SImode);
+	  absneg_op = AND;
+	}
+      else
+	{
+	  set = gen_int_mode (0x80000000, SImode);
+	  absneg_op = XOR;
+	}
+      set = gen_rtx_fmt_ee (absneg_op, SImode, dst, set);
+      break;
+
+    case E_DFmode:
+      if (TARGET_64BIT)
+	{
+	  dst = gen_lowpart (DImode, operands[0]);
+	  dst = gen_rtx_ZERO_EXTRACT (DImode, dst, const1_rtx, GEN_INT (63));
+
+	  if (code == ABS)
+	    set = const0_rtx;
+	  else
+	    set = gen_rtx_NOT (DImode, dst);
+	}
+      else
+	{
+	  dst = gen_highpart (SImode, operands[0]);
+
+	  if (code == ABS)
+	    {
+	      set = gen_int_mode (0x7fffffff, SImode);
+	      absneg_op = AND;
+	    }
+	  else
+	    {
+	      set = gen_int_mode (0x80000000, SImode);
+	      absneg_op = XOR;
+	    }
+	  set = gen_rtx_fmt_ee (absneg_op, SImode, dst, set);
+	}
+      break;
+
+    case E_XFmode:
+      dst = gen_rtx_REG (SImode,
+			 REGNO (operands[0]) + (TARGET_64BIT ? 1 : 2));
+      if (code == ABS)
+	{
+	  set = GEN_INT (0x7fff);
+	  absneg_op = AND;
+	}
+      else
+	{
+	  set = GEN_INT (0x8000);
+	  absneg_op = XOR;
+	}
+      set = gen_rtx_fmt_ee (absneg_op, SImode, dst, set);
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  set = gen_rtx_SET (dst, set);
+
+  rtx clob = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, FLAGS_REG));
+  rtvec par = gen_rtvec (2, set, clob);
+
+  emit_insn (gen_rtx_PARALLEL (VOIDmode, par));
+}
+
 /* Expand a copysign operation.  Special case operand 0 being a constant.  */
 
 void
Index: config/i386/i386-protos.h
===================================================================
--- config/i386/i386-protos.h	(revision 272119)
+++ config/i386/i386-protos.h	(working copy)
@@ -121,6 +121,8 @@  extern rtx ix86_expand_adjust_ufix_to_sfix_si (rtx
 extern enum ix86_fpcmp_strategy ix86_fp_comparison_strategy (enum rtx_code);
 extern void ix86_expand_fp_absneg_operator (enum rtx_code, machine_mode,
 					    rtx[]);
+extern void ix86_split_fp_absneg_operator (enum rtx_code, machine_mode,
+					   rtx[]);
 extern void ix86_expand_copysign (rtx []);
 extern void ix86_split_copysign_const (rtx []);
 extern void ix86_split_copysign_var (rtx []);
Index: config/i386/i386.md
===================================================================
--- config/i386/i386.md	(revision 272119)
+++ config/i386/i386.md	(working copy)
@@ -1162,6 +1162,10 @@ 
 ;; All x87 floating point modes
 (define_mode_iterator X87MODEF [SF DF XF])
 
+;; All SSE floating point modes
+(define_mode_iterator SSEMODEF [SF DF TF])
+(define_mode_attr ssevecmodef [(SF "V4SF") (DF "V2DF") (TF "TF")])
+
 ;; SSE instruction suffix for various modes
 (define_mode_attr ssemodesuffix
   [(SF "ss") (DF "sd")
@@ -9488,8 +9492,22 @@ 
   [(set_attr "type" "negnot")
    (set_attr "mode" "<MODE>")])
 
-;; Changing of sign for FP values is doable using integer unit too.
+(define_expand "<code>tf2"
+  [(set (match_operand:TF 0 "register_operand")
+	(absneg:TF (match_operand:TF 1 "register_operand")))]
+  "TARGET_SSE"
+  "ix86_expand_fp_absneg_operator (<CODE>, TFmode, operands); DONE;")
 
+(define_insn "*<code>tf2_1"
+  [(set (match_operand:TF 0 "register_operand" "=x,x,Yv,Yv")
+	(absneg:TF
+	  (match_operand:TF 1 "vector_operand" "0,xBm,Yv,m")))
+   (use (match_operand:TF 2 "vector_operand" "xBm,0,Yvm,Yv"))
+   (clobber (reg:CC FLAGS_REG))]
+  "TARGET_SSE"
+  "#"
+  [(set_attr "isa" "noavx,noavx,avx,avx")])
+
 (define_expand "<code><mode>2"
   [(set (match_operand:X87MODEF 0 "register_operand")
 	(absneg:X87MODEF (match_operand:X87MODEF 1 "register_operand")))]
@@ -9496,180 +9514,108 @@ 
   "TARGET_80387 || (SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH)"
   "ix86_expand_fp_absneg_operator (<CODE>, <MODE>mode, operands); DONE;")
 
-(define_insn "*absneg<mode>2"
-  [(set (match_operand:MODEF 0 "register_operand" "=Yv,Yv,f,!r")
-	(match_operator:MODEF 3 "absneg_operator"
-	  [(match_operand:MODEF 1 "register_operand" "0,Yv,0,0")]))
-   (use (match_operand:<ssevecmode> 2 "nonimmediate_operand" "Yvm,0,X,X"))
+;; Changing of sign for FP values is doable using integer unit too.
+(define_insn "*<code><mode>2_i387_1"
+  [(set (match_operand:X87MODEF 0 "register_operand" "=f,!r")
+	(absneg:X87MODEF
+	  (match_operand:X87MODEF 1 "register_operand" "0,0")))
    (clobber (reg:CC FLAGS_REG))]
+  "TARGET_80387"
+  "#")
+
+(define_split
+  [(set (match_operand:X87MODEF 0 "fp_register_operand")
+	(absneg:X87MODEF (match_operand:X87MODEF 1 "fp_register_operand")))
+   (clobber (reg:CC FLAGS_REG))]
+  "TARGET_80387 && reload_completed"
+  [(set (match_dup 0) (absneg:X87MODEF (match_dup 1)))])
+
+(define_split
+  [(set (match_operand:X87MODEF 0 "general_reg_operand")
+	(absneg:X87MODEF (match_operand:X87MODEF 1 "general_reg_operand")))
+   (clobber (reg:CC FLAGS_REG))]
+  "TARGET_80387 && reload_completed"
+  [(const_int 0)]
+  "ix86_split_fp_absneg_operator (<CODE>, <MODE>mode, operands); DONE;")
+
+(define_insn "*<code><mode>2_1"
+  [(set (match_operand:MODEF 0 "register_operand" "=x,x,Yv,f,!r")
+	(absneg:MODEF
+	  (match_operand:MODEF 1 "register_operand" "0,x,Yv,0,0")))
+   (use (match_operand:<ssevecmode> 2 "vector_operand" "xBm,0,Yvm,X,X"))
+   (clobber (reg:CC FLAGS_REG))]
   "TARGET_80387 || (SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH)"
   "#"
-  [(set (attr "enabled")
+  [(set_attr "isa" "noavx,noavx,avx,*,*")
+   (set (attr "enabled")
      (if_then_else
        (match_test ("SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH"))
        (if_then_else
-	 (eq_attr "alternative" "2")
+	 (eq_attr "alternative" "3,4")
 	 (symbol_ref "TARGET_MIX_SSE_I387")
-	 (symbol_ref "true"))
+	 (const_string "*"))
        (if_then_else
-	 (eq_attr "alternative" "2,3")
+	 (eq_attr "alternative" "3,4")
 	 (symbol_ref "true")
 	 (symbol_ref "false"))))])
 
-(define_insn "*absnegxf2_i387"
-  [(set (match_operand:XF 0 "register_operand" "=f,!r")
-	(match_operator:XF 3 "absneg_operator"
-	  [(match_operand:XF 1 "register_operand" "0,0")]))
-   (use (match_operand 2))
-   (clobber (reg:CC FLAGS_REG))]
-  "TARGET_80387"
-  "#")
-
-(define_expand "<code>tf2"
-  [(set (match_operand:TF 0 "register_operand")
-	(absneg:TF (match_operand:TF 1 "register_operand")))]
-  "TARGET_SSE"
-  "ix86_expand_fp_absneg_operator (<CODE>, TFmode, operands); DONE;")
-
-(define_insn "*absnegtf2_sse"
-  [(set (match_operand:TF 0 "register_operand" "=Yv,Yv")
-	(match_operator:TF 3 "absneg_operator"
-	  [(match_operand:TF 1 "register_operand" "0,Yv")]))
-   (use (match_operand:TF 2 "nonimmediate_operand" "Yvm,0"))
-   (clobber (reg:CC FLAGS_REG))]
-  "TARGET_SSE"
-  "#")
-
-;; Splitters for fp abs and neg.
-
 (define_split
-  [(set (match_operand 0 "fp_register_operand")
-	(match_operator 1 "absneg_operator" [(match_dup 0)]))
-   (use (match_operand 2))
+  [(set (match_operand:SSEMODEF 0 "sse_reg_operand")
+	(absneg:SSEMODEF
+	  (match_operand:SSEMODEF 1 "vector_operand")))
+   (use (match_operand:<ssevecmodef> 2 "vector_operand"))
    (clobber (reg:CC FLAGS_REG))]
-  "reload_completed"
-  [(set (match_dup 0) (match_op_dup 1 [(match_dup 0)]))])
-
-(define_split
-  [(set (match_operand 0 "sse_reg_operand")
-	(match_operator 3 "absneg_operator"
-	  [(match_operand 1 "register_operand")]))
-   (use (match_operand 2 "nonimmediate_operand"))
-   (clobber (reg:CC FLAGS_REG))]
-  "reload_completed"
+  "((SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH)
+    || (TARGET_SSE && (<MODE>mode == TFmode)))
+   && reload_completed"
   [(set (match_dup 0) (match_dup 3))]
 {
-  machine_mode mode = GET_MODE (operands[0]);
-  machine_mode vmode = GET_MODE (operands[2]);
-  rtx tmp;
+  machine_mode mode = <MODE>mode;
+  machine_mode vmode = <ssevecmodef>mode;
+  enum rtx_code absneg_op = <CODE> == ABS ? AND : XOR;
 
   operands[0] = lowpart_subreg (vmode, operands[0], mode);
   operands[1] = lowpart_subreg (vmode, operands[1], mode);
-  if (operands_match_p (operands[0], operands[2]))
-    std::swap (operands[1], operands[2]);
-  if (GET_CODE (operands[3]) == ABS)
-    tmp = gen_rtx_AND (vmode, operands[1], operands[2]);
-  else
-    tmp = gen_rtx_XOR (vmode, operands[1], operands[2]);
-  operands[3] = tmp;
-})
 
-(define_split
-  [(set (match_operand:SF 0 "general_reg_operand")
-	(match_operator:SF 1 "absneg_operator" [(match_dup 0)]))
-   (use (match_operand:V4SF 2))
-   (clobber (reg:CC FLAGS_REG))]
-  "reload_completed"
-  [(parallel [(set (match_dup 0) (match_dup 1))
-	      (clobber (reg:CC FLAGS_REG))])]
-{
-  rtx tmp;
-  operands[0] = gen_lowpart (SImode, operands[0]);
-  if (GET_CODE (operands[1]) == ABS)
+  if (TARGET_AVX)
     {
-      tmp = gen_int_mode (0x7fffffff, SImode);
-      tmp = gen_rtx_AND (SImode, operands[0], tmp);
+      if (MEM_P (operands[1]))
+        std::swap (operands[1], operands[2]);
     }
   else
-    {
-      tmp = gen_int_mode (0x80000000, SImode);
-      tmp = gen_rtx_XOR (SImode, operands[0], tmp);
-    }
-  operands[1] = tmp;
+   {
+     if (operands_match_p (operands[0], operands[2]))
+       std::swap (operands[1], operands[2]);
+   }
+
+  operands[3]
+    = gen_rtx_fmt_ee (absneg_op, vmode, operands[1], operands[2]);
 })
 
 (define_split
-  [(set (match_operand:DF 0 "general_reg_operand")
-	(match_operator:DF 1 "absneg_operator" [(match_dup 0)]))
+  [(set (match_operand:MODEF 0 "fp_register_operand")
+	(absneg:MODEF (match_operand:MODEF 1 "fp_register_operand")))
    (use (match_operand 2))
    (clobber (reg:CC FLAGS_REG))]
-  "reload_completed"
-  [(parallel [(set (match_dup 0) (match_dup 1))
-	      (clobber (reg:CC FLAGS_REG))])]
-{
-  rtx tmp;
-  if (TARGET_64BIT)
-    {
-      tmp = gen_lowpart (DImode, operands[0]);
-      tmp = gen_rtx_ZERO_EXTRACT (DImode, tmp, const1_rtx, GEN_INT (63));
-      operands[0] = tmp;
+  "TARGET_80387 && reload_completed"
+  [(set (match_dup 0) (absneg:X87MODEF (match_dup 1)))])
 
-      if (GET_CODE (operands[1]) == ABS)
-	tmp = const0_rtx;
-      else
-	tmp = gen_rtx_NOT (DImode, tmp);
-    }
-  else
-    {
-      operands[0] = gen_highpart (SImode, operands[0]);
-      if (GET_CODE (operands[1]) == ABS)
-	{
-	  tmp = gen_int_mode (0x7fffffff, SImode);
-	  tmp = gen_rtx_AND (SImode, operands[0], tmp);
-	}
-      else
-	{
-	  tmp = gen_int_mode (0x80000000, SImode);
-	  tmp = gen_rtx_XOR (SImode, operands[0], tmp);
-	}
-    }
-  operands[1] = tmp;
-})
-
 (define_split
-  [(set (match_operand:XF 0 "general_reg_operand")
-	(match_operator:XF 1 "absneg_operator" [(match_dup 0)]))
+  [(set (match_operand:MODEF 0 "general_reg_operand")
+	(absneg:MODEF (match_operand:MODEF 1 "general_reg_operand")))
    (use (match_operand 2))
    (clobber (reg:CC FLAGS_REG))]
-  "reload_completed"
-  [(parallel [(set (match_dup 0) (match_dup 1))
-	      (clobber (reg:CC FLAGS_REG))])]
-{
-  rtx tmp;
-  operands[0] = gen_rtx_REG (SImode,
-			     REGNO (operands[0]) + (TARGET_64BIT ? 1 : 2));
-  if (GET_CODE (operands[1]) == ABS)
-    {
-      tmp = GEN_INT (0x7fff);
-      tmp = gen_rtx_AND (SImode, operands[0], tmp);
-    }
-  else
-    {
-      tmp = GEN_INT (0x8000);
-      tmp = gen_rtx_XOR (SImode, operands[0], tmp);
-    }
-  operands[1] = tmp;
-})
+  "TARGET_80387 && reload_completed"
+  [(const_int 0)]
+  "ix86_split_fp_absneg_operator (<CODE>, <MODE>mode, operands); DONE;")
 
 ;; Conditionalize these after reload. If they match before reload, we
 ;; lose the clobber and ability to use integer instructions.
 
-(define_insn "*<code><mode>2_1"
+(define_insn "*<code><mode>2_i387"
   [(set (match_operand:X87MODEF 0 "register_operand" "=f")
 	(absneg:X87MODEF (match_operand:X87MODEF 1 "register_operand" "0")))]
-  "TARGET_80387
-   && (reload_completed
-       || !(SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH))"
+  "TARGET_80387 && reload_completed"
   "<absneg_mnemonic>"
   [(set_attr "type" "fsgn")
    (set_attr "mode" "<MODE>")])
@@ -9676,23 +9622,20 @@ 
 
 ;; Copysign instructions
 
-(define_mode_iterator CSGNMODE [SF DF TF])
-(define_mode_attr CSGNVMODE [(SF "V4SF") (DF "V2DF") (TF "TF")])
-
 (define_expand "copysign<mode>3"
-  [(match_operand:CSGNMODE 0 "register_operand")
-   (match_operand:CSGNMODE 1 "nonmemory_operand")
-   (match_operand:CSGNMODE 2 "register_operand")]
+  [(match_operand:SSEMODEF 0 "register_operand")
+   (match_operand:SSEMODEF 1 "nonmemory_operand")
+   (match_operand:SSEMODEF 2 "register_operand")]
   "(SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH)
    || (TARGET_SSE && (<MODE>mode == TFmode))"
   "ix86_expand_copysign (operands); DONE;")
 
 (define_insn_and_split "copysign<mode>3_const"
-  [(set (match_operand:CSGNMODE 0 "register_operand" "=Yv")
-	(unspec:CSGNMODE
-	  [(match_operand:<CSGNVMODE> 1 "nonimm_or_0_operand" "YvmC")
-	   (match_operand:CSGNMODE 2 "register_operand" "0")
-	   (match_operand:<CSGNVMODE> 3 "nonimmediate_operand" "Yvm")]
+  [(set (match_operand:SSEMODEF 0 "register_operand" "=Yv")
+	(unspec:SSEMODEF
+	  [(match_operand:<ssevecmodef> 1 "nonimm_or_0_operand" "YvmC")
+	   (match_operand:SSEMODEF 2 "register_operand" "0")
+	   (match_operand:<ssevecmodef> 3 "nonimmediate_operand" "Yvm")]
 	  UNSPEC_COPYSIGN))]
   "(SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH)
    || (TARGET_SSE && (<MODE>mode == TFmode))"
@@ -9702,29 +9645,29 @@ 
   "ix86_split_copysign_const (operands); DONE;")
 
 (define_insn "copysign<mode>3_var"
-  [(set (match_operand:CSGNMODE 0 "register_operand" "=Yv,Yv,Yv,Yv,Yv")
-	(unspec:CSGNMODE
-	  [(match_operand:CSGNMODE 2 "register_operand"	"Yv,0,0,Yv,Yv")
-	   (match_operand:CSGNMODE 3 "register_operand"	"1,1,Yv,1,Yv")
-	   (match_operand:<CSGNVMODE> 4
+  [(set (match_operand:SSEMODEF 0 "register_operand" "=Yv,Yv,Yv,Yv,Yv")
+	(unspec:SSEMODEF
+	  [(match_operand:SSEMODEF 2 "register_operand"	"Yv,0,0,Yv,Yv")
+	   (match_operand:SSEMODEF 3 "register_operand"	"1,1,Yv,1,Yv")
+	   (match_operand:<ssevecmodef> 4
 	     "nonimmediate_operand" "X,Yvm,Yvm,0,0")
-	   (match_operand:<CSGNVMODE> 5
+	   (match_operand:<ssevecmodef> 5
 	     "nonimmediate_operand" "0,Yvm,1,Yvm,1")]
 	  UNSPEC_COPYSIGN))
-   (clobber (match_scratch:<CSGNVMODE> 1 "=Yv,Yv,Yv,Yv,Yv"))]
+   (clobber (match_scratch:<ssevecmodef> 1 "=Yv,Yv,Yv,Yv,Yv"))]
   "(SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH)
    || (TARGET_SSE && (<MODE>mode == TFmode))"
   "#")
 
 (define_split
-  [(set (match_operand:CSGNMODE 0 "register_operand")
-	(unspec:CSGNMODE
-	  [(match_operand:CSGNMODE 2 "register_operand")
-	   (match_operand:CSGNMODE 3 "register_operand")
-	   (match_operand:<CSGNVMODE> 4)
-	   (match_operand:<CSGNVMODE> 5)]
+  [(set (match_operand:SSEMODEF 0 "register_operand")
+	(unspec:SSEMODEF
+	  [(match_operand:SSEMODEF 2 "register_operand")
+	   (match_operand:SSEMODEF 3 "register_operand")
+	   (match_operand:<ssevecmodef> 4)
+	   (match_operand:<ssevecmodef> 5)]
 	  UNSPEC_COPYSIGN))
-   (clobber (match_scratch:<CSGNVMODE> 1))]
+   (clobber (match_scratch:<ssevecmodef> 1))]
   "((SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH)
     || (TARGET_SSE && (<MODE>mode == TFmode)))
    && reload_completed"
Index: config/i386/predicates.md
===================================================================
--- config/i386/predicates.md	(revision 272119)
+++ config/i386/predicates.md	(working copy)
@@ -1404,9 +1404,6 @@ 
 (define_predicate "compare_operator"
   (match_code "compare"))
 
-(define_predicate "absneg_operator"
-  (match_code "abs,neg"))
-
 ;; Return true if OP is a memory operand, aligned to
 ;; less than its natural alignment.
 (define_predicate "misaligned_operand"
Index: config/i386/sse.md
===================================================================
--- config/i386/sse.md	(revision 272119)
+++ config/i386/sse.md	(working copy)
@@ -1720,41 +1720,31 @@ 
   "TARGET_SSE"
   "ix86_expand_fp_absneg_operator (<CODE>, <MODE>mode, operands); DONE;")
 
-(define_insn_and_split "*absneg<mode>2"
+(define_insn_and_split "*<code><mode>2"
   [(set (match_operand:VF 0 "register_operand" "=x,x,v,v")
-	(match_operator:VF 3 "absneg_operator"
-	  [(match_operand:VF 1 "vector_operand" "0,  xBm,v, m")]))
+	(absneg:VF
+	  (match_operand:VF 1 "vector_operand" "0,  xBm,v, m")))
    (use (match_operand:VF 2 "vector_operand"    "xBm,0,  vm,v"))]
   "TARGET_SSE"
   "#"
   "&& reload_completed"
-  [(const_int 0)]
+  [(set (match_dup 0) (match_dup 3))]
 {
-  enum rtx_code absneg_op;
-  rtx op1, op2;
-  rtx t;
+  enum rtx_code absneg_op = <CODE> == ABS ? AND : XOR;
 
   if (TARGET_AVX)
     {
       if (MEM_P (operands[1]))
-	op1 = operands[2], op2 = operands[1];
-      else
-	op1 = operands[1], op2 = operands[2];
+        std::swap (operands[1], operands[2]);
     }
   else
-    {
-      op1 = operands[0];
-      if (rtx_equal_p (operands[0], operands[1]))
-	op2 = operands[2];
-      else
-	op2 = operands[1];
-    }
+   {
+     if (operands_match_p (operands[0], operands[2]))
+       std::swap (operands[1], operands[2]);
+   }
 
-  absneg_op = GET_CODE (operands[3]) == NEG ? XOR : AND;
-  t = gen_rtx_fmt_ee (absneg_op, <MODE>mode, op1, op2);
-  t = gen_rtx_SET (operands[0], t);
-  emit_insn (t);
-  DONE;
+  operands[3]
+    = gen_rtx_fmt_ee (absneg_op, <MODE>mode, operands[1], operands[2]);
 }
   [(set_attr "isa" "noavx,noavx,avx,avx")])