The recent(ish) improvements to widening multiplication support have
disabled madd and msub for fixed-point types.  The problem is that the
optab is now chosen based on:

  optype = build_nonstandard_integer_type (from_mode, from_unsigned1);

which is specific to integer types.

The only time optype differs from type1 is when we've switched to using
unsigned types, possibly with a wider mode.  As written, the handling of
mixed signedness really is only suitable for integer types, so this patch
enforces that and makes the call above conditional on it.  It also fixes
the first argument to be the precision rather than the mode.

(As the argument mismatch proved, the precision doesn't actually
matter here; only the signedness does.  I think an equivalent fix
would be to call:

  optype = unsigned_type_for (type1);

That ought to work for fixed point types too, but is a little less
obvious and a little less future-proof.  Since the rest of the block
hasn't been adapted to fixed point types, it didn't seem worth the
confusion.)

Tested on mips-sde-elf, where it fixes gcc.target/mips/dpaq_sa_l_w.c
and gcc.target/mips/dpsq_sa_l_w.c.  OK to install?

Richard


gcc/
        * tree-ssa-math-opts.c (convert_plusminus_to_widen): Restrict
        handling of signedness differences to integer types.  Only build
        a new optype if type1 isn't correct.

Index: gcc/tree-ssa-math-opts.c
===================================================================
--- gcc/tree-ssa-math-opts.c    2011-12-19 21:18:43.000000000 +0000
+++ gcc/tree-ssa-math-opts.c    2011-12-19 21:23:12.000000000 +0000
@@ -2304,10 +2304,13 @@ convert_plusminus_to_widen (gimple_stmt_
   from_mode = TYPE_MODE (type1);
   from_unsigned1 = TYPE_UNSIGNED (type1);
   from_unsigned2 = TYPE_UNSIGNED (type2);
+  optype = type1;
 
   /* There's no such thing as a mixed sign madd yet, so use a wider mode.  */
   if (from_unsigned1 != from_unsigned2)
     {
+      if (TREE_CODE (type) != INTEGER_TYPE)
+       return false;
       /* We can use a signed multiply with unsigned types as long as
         there is a wider mode to use, or it is the smaller of the two
         types that is unsigned.  Note that type1 >= type2, always.  */
@@ -2322,6 +2325,8 @@ convert_plusminus_to_widen (gimple_stmt_
        }
 
       from_unsigned1 = from_unsigned2 = false;
+      optype = build_nonstandard_integer_type (GET_MODE_PRECISION (from_mode),
+                                              false);
     }
 
   /* If there was a conversion between the multiply and addition
@@ -2355,7 +2360,6 @@ convert_plusminus_to_widen (gimple_stmt_
   /* Verify that the machine can perform a widening multiply
      accumulate in this mode/signedness combination, otherwise
      this transformation is likely to pessimize code.  */
-  optype = build_nonstandard_integer_type (from_mode, from_unsigned1);
   this_optab = optab_for_tree_code (wmult_code, optype, optab_default);
   handler = find_widening_optab_handler_and_mode (this_optab, to_mode,
                                                  from_mode, 0, &actual_mode);

Reply via email to