Index: gcc/expr.c
===================================================================
--- gcc/expr.c	(revision 249619)
+++ gcc/expr.c	(working copy)
@@ -8182,6 +8182,59 @@
   return NULL_RTX;
 }
 
+static bool
+is_copysign_call_with_1 (gimple *call)
+{
+  if (!is_gimple_call (call))
+    return false;
+
+  if (gimple_call_builtin_p (call, BUILT_IN_NORMAL))
+    {
+      gcall *c = as_a<gcall*> (call);
+      tree decl = gimple_call_fndecl (call);
+      switch (DECL_FUNCTION_CODE (decl))
+	{
+        CASE_FLT_FN (BUILT_IN_COPYSIGN):
+	CASE_FLT_FN_FLOATN_NX (BUILT_IN_COPYSIGN):
+	  return real_one_p (gimple_call_arg (c, 0));
+	default:
+	  return false;
+	}
+    }
+}
+
+static rtx
+maybe_expand_mult_copysign (tree treeop0, tree treeop1, rtx target)
+{
+  tree type = TREE_TYPE (treeop0);
+  rtx op0, op1;
+
+  if (!SCALAR_FLOAT_TYPE_P (type)
+      && VECTOR_FLOAT_TYPE_P (type))
+    return NULL;
+
+  if (HONOR_SNANS (type))
+    return NULL;
+
+  if (!targetm.expand_mult_copysign_xor ())
+    return NULL;
+
+  if (TREE_CODE (treeop0) == SSA_NAME)
+    {
+      gimple *call0 = SSA_NAME_DEF_STMT (treeop0);
+      if (is_copysign_call_with_1 (call0))
+	{
+	  gcall *c = as_a<gcall*> (call0);
+	  treeop0 = gimple_call_arg (c, 1);
+	  expand_operands (treeop1, treeop0, NULL_RTX, &op0, &op1, EXPAND_NORMAL);
+	  return expand_copysign (op0, op1, target, true);
+	}
+    }
+
+  return NULL;
+}
+
+
 rtx
 expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode,
 		    enum expand_modifier modifier)
@@ -8791,6 +8844,10 @@
       if (modifier == EXPAND_STACK_PARM)
 	target = 0;
 
+      temp = maybe_expand_mult_copysign (treeop0, treeop1);
+      if (temp)
+	return temp;
+
       expand_operands (treeop0, treeop1, subtarget, &op0, &op1, EXPAND_NORMAL);
       return REDUCE_BIT_FIELD (expand_mult (mode, op0, op1, target, unsignedp));
 
Index: gcc/target.def
===================================================================
--- gcc/target.def	(revision 249619)
+++ gcc/target.def	(working copy)
@@ -2640,6 +2640,13 @@
  default_have_conditional_execution)
 
 DEFHOOK
+(expand_mult_copysign_xor,
+ "This target hook returns true if the target wants to use xor's\n
+to expand x * copysign (1., y) as x ^ (y & (1 << sign_bit_position)).\n"
+ bool, (void),
+ hook_bool_void_false)
+
+DEFHOOK
 (gen_ccmp_first,
  "This function prepares to emit a comparison insn for the first compare in a\n\
  sequence of conditional comparisions.  It returns an appropriate comparison\n\
