aboutsummaryrefslogtreecommitdiffstats
path: root/toolchain-layer/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106796.patch
diff options
context:
space:
mode:
Diffstat (limited to 'toolchain-layer/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106796.patch')
-rw-r--r--toolchain-layer/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106796.patch1255
1 files changed, 0 insertions, 1255 deletions
diff --git a/toolchain-layer/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106796.patch b/toolchain-layer/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106796.patch
deleted file mode 100644
index 1a940975f3..0000000000
--- a/toolchain-layer/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106796.patch
+++ /dev/null
@@ -1,1255 +0,0 @@
-2011-08-25 Andrew Stubbs <ams@codesourcery.com>
-
- Backport from FSF mainline:
-
- 2011-08-19 Andrew Stubbs <ams@codesourcery.com>
-
- gcc/
- * tree-ssa-math-opts.c (is_widening_mult_rhs_p): Handle constants
- beyond conversions.
- (convert_mult_to_widen): Convert constant inputs to the right type.
- (convert_plusminus_to_widen): Don't automatically reject inputs that
- are not an SSA_NAME.
- Convert constant inputs to the right type.
-
- gcc/testsuite/
- * gcc.target/arm/wmul-11.c: New file.
- * gcc.target/arm/wmul-12.c: New file.
- * gcc.target/arm/wmul-13.c: New file.
-
- 2011-08-19 Andrew Stubbs <ams@codesourcery.com>
-
- gcc/
- * tree-ssa-math-opts.c (convert_plusminus_to_widen): Convert add_rhs
- to the correct type.
-
- gcc/testsuite/
- * gcc.target/arm/wmul-10.c: New file.
-
- 2011-08-19 Andrew Stubbs <ams@codesourcery.com>
-
- gcc/
- * tree-ssa-math-opts.c (convert_mult_to_widen): Better handle
- unsigned inputs of different modes.
- (convert_plusminus_to_widen): Likewise.
-
- gcc/testsuite/
- * gcc.target/arm/wmul-9.c: New file.
- * gcc.target/arm/wmul-bitfield-2.c: New file.
-
- 2011-08-19 Andrew Stubbs <ams@codesourcery.com>
-
- gcc/
- * tree-ssa-math-opts.c (is_widening_mult_rhs_p): Add new argument
- 'type'.
- Use 'type' from caller, not inferred from 'rhs'.
- Don't reject non-conversion statements. Do return lhs in this case.
- (is_widening_mult_p): Add new argument 'type'.
- Use 'type' from caller, not inferred from 'stmt'.
- Pass type to is_widening_mult_rhs_p.
- (convert_mult_to_widen): Pass type to is_widening_mult_p.
- (convert_plusminus_to_widen): Likewise.
-
- gcc/testsuite/
- * gcc.target/arm/wmul-8.c: New file.
-
- 2011-08-19 Andrew Stubbs <ams@codesourcery.com>
-
- gcc/
- * tree-ssa-math-opts.c (is_widening_mult_p): Remove FIXME.
- Ensure the the larger type is the first operand.
-
- gcc/testsuite/
- * gcc.target/arm/wmul-7.c: New file.
-
- 2011-08-19 Andrew Stubbs <ams@codesourcery.com>
-
- gcc/
- * tree-ssa-math-opts.c (convert_mult_to_widen): Convert
- unsupported unsigned multiplies to signed.
- (convert_plusminus_to_widen): Likewise.
-
- gcc/testsuite/
- * gcc.target/arm/wmul-6.c: New file.
-
- 2011-08-19 Andrew Stubbs <ams@codesourcery.com>
-
- gcc/
- * tree-ssa-math-opts.c (convert_plusminus_to_widen): Permit a single
- conversion statement separating multiply-and-accumulate.
-
- gcc/testsuite/
- * gcc.target/arm/wmul-5.c: New file.
- * gcc.target/arm/no-wmla-1.c: New file.
-
- 2011-08-19 Andrew Stubbs <ams@codesourcery.com>
-
- gcc/
- * config/arm/arm.md (maddhidi4): Remove '*' from name.
- * expr.c (expand_expr_real_2): Use find_widening_optab_handler.
- * optabs.c (find_widening_optab_handler_and_mode): New function.
- (expand_widen_pattern_expr): Use find_widening_optab_handler.
- (expand_binop_directly): Likewise.
- (expand_binop): Likewise.
- * optabs.h (find_widening_optab_handler): New macro define.
- (find_widening_optab_handler_and_mode): New prototype.
- * tree-cfg.c (verify_gimple_assign_binary): Adjust WIDEN_MULT_EXPR
- type precision rules.
- (verify_gimple_assign_ternary): Likewise for WIDEN_MULT_PLUS_EXPR.
- * tree-ssa-math-opts.c (build_and_insert_cast): New function.
- (is_widening_mult_rhs_p): Allow widening by more than one mode.
- Explicitly disallow mis-matched input types.
- (convert_mult_to_widen): Use find_widening_optab_handler, and cast
- input types to fit the new handler.
- (convert_plusminus_to_widen): Likewise.
-
- gcc/testsuite/
- * gcc.target/arm/wmul-bitfield-1.c: New file.
-
- 2011-08-19 Andrew Stubbs <ams@codesourcery.com>
-
- gcc/
- * expr.c (expand_expr_real_2): Use widening_optab_handler.
- * genopinit.c (optabs): Use set_widening_optab_handler for $N.
- (gen_insn): $N now means $a must be wider than $b, not consecutive.
- * optabs.c (widened_mode): New function.
- (expand_widen_pattern_expr): Use widening_optab_handler.
- (expand_binop_directly): Likewise.
- (expand_binop): Likewise.
- * optabs.h (widening_optab_handlers): New struct.
- (optab_d): New member, 'widening'.
- (widening_optab_handler): New function.
- (set_widening_optab_handler): New function.
- * tree-ssa-math-opts.c (convert_mult_to_widen): Use
- widening_optab_handler.
- (convert_plusminus_to_widen): Likewise.
-
-=== modified file 'gcc/config/arm/arm.md'
---- old/gcc/config/arm/arm.md 2011-08-13 08:32:32 +0000
-+++ new/gcc/config/arm/arm.md 2011-08-25 11:42:09 +0000
-@@ -1839,7 +1839,7 @@
- (set_attr "predicable" "yes")]
- )
-
--(define_insn "*maddhidi4"
-+(define_insn "maddhidi4"
- [(set (match_operand:DI 0 "s_register_operand" "=r")
- (plus:DI
- (mult:DI (sign_extend:DI
-
-=== modified file 'gcc/expr.c'
---- old/gcc/expr.c 2011-08-13 08:32:32 +0000
-+++ new/gcc/expr.c 2011-08-25 11:42:09 +0000
-@@ -7688,18 +7688,16 @@
- {
- enum machine_mode innermode = TYPE_MODE (TREE_TYPE (treeop0));
- this_optab = usmul_widen_optab;
-- if (mode == GET_MODE_2XWIDER_MODE (innermode))
-+ if (find_widening_optab_handler (this_optab, mode, innermode, 0)
-+ != CODE_FOR_nothing)
- {
-- if (optab_handler (this_optab, mode) != CODE_FOR_nothing)
-- {
-- if (TYPE_UNSIGNED (TREE_TYPE (treeop0)))
-- expand_operands (treeop0, treeop1, NULL_RTX, &op0, &op1,
-- EXPAND_NORMAL);
-- else
-- expand_operands (treeop0, treeop1, NULL_RTX, &op1, &op0,
-- EXPAND_NORMAL);
-- goto binop3;
-- }
-+ if (TYPE_UNSIGNED (TREE_TYPE (treeop0)))
-+ expand_operands (treeop0, treeop1, NULL_RTX, &op0, &op1,
-+ EXPAND_NORMAL);
-+ else
-+ expand_operands (treeop0, treeop1, NULL_RTX, &op1, &op0,
-+ EXPAND_NORMAL);
-+ goto binop3;
- }
- }
- /* Check for a multiplication with matching signedness. */
-@@ -7714,10 +7712,10 @@
- optab other_optab = zextend_p ? smul_widen_optab : umul_widen_optab;
- this_optab = zextend_p ? umul_widen_optab : smul_widen_optab;
-
-- if (mode == GET_MODE_2XWIDER_MODE (innermode)
-- && TREE_CODE (treeop0) != INTEGER_CST)
-+ if (TREE_CODE (treeop0) != INTEGER_CST)
- {
-- if (optab_handler (this_optab, mode) != CODE_FOR_nothing)
-+ if (find_widening_optab_handler (this_optab, mode, innermode, 0)
-+ != CODE_FOR_nothing)
- {
- expand_operands (treeop0, treeop1, NULL_RTX, &op0, &op1,
- EXPAND_NORMAL);
-@@ -7725,7 +7723,8 @@
- unsignedp, this_optab);
- return REDUCE_BIT_FIELD (temp);
- }
-- if (optab_handler (other_optab, mode) != CODE_FOR_nothing
-+ if (find_widening_optab_handler (other_optab, mode, innermode, 0)
-+ != CODE_FOR_nothing
- && innermode == word_mode)
- {
- rtx htem, hipart;
-
-=== modified file 'gcc/genopinit.c'
---- old/gcc/genopinit.c 2011-05-05 15:43:06 +0000
-+++ new/gcc/genopinit.c 2011-07-15 13:06:31 +0000
-@@ -46,10 +46,12 @@
- used. $A and $B are replaced with the full name of the mode; $a and $b
- are replaced with the short form of the name, as above.
-
-- If $N is present in the pattern, it means the two modes must be consecutive
-- widths in the same mode class (e.g, QImode and HImode). $I means that
-- only full integer modes should be considered for the next mode, and $F
-- means that only float modes should be considered.
-+ If $N is present in the pattern, it means the two modes must be in
-+ the same mode class, and $b must be greater than $a (e.g, QImode
-+ and HImode).
-+
-+ $I means that only full integer modes should be considered for the
-+ next mode, and $F means that only float modes should be considered.
- $P means that both full and partial integer modes should be considered.
- $Q means that only fixed-point modes should be considered.
-
-@@ -99,17 +101,17 @@
- "set_optab_handler (smulv_optab, $A, CODE_FOR_$(mulv$I$a3$))",
- "set_optab_handler (umul_highpart_optab, $A, CODE_FOR_$(umul$a3_highpart$))",
- "set_optab_handler (smul_highpart_optab, $A, CODE_FOR_$(smul$a3_highpart$))",
-- "set_optab_handler (smul_widen_optab, $B, CODE_FOR_$(mul$a$b3$)$N)",
-- "set_optab_handler (umul_widen_optab, $B, CODE_FOR_$(umul$a$b3$)$N)",
-- "set_optab_handler (usmul_widen_optab, $B, CODE_FOR_$(usmul$a$b3$)$N)",
-- "set_optab_handler (smadd_widen_optab, $B, CODE_FOR_$(madd$a$b4$)$N)",
-- "set_optab_handler (umadd_widen_optab, $B, CODE_FOR_$(umadd$a$b4$)$N)",
-- "set_optab_handler (ssmadd_widen_optab, $B, CODE_FOR_$(ssmadd$a$b4$)$N)",
-- "set_optab_handler (usmadd_widen_optab, $B, CODE_FOR_$(usmadd$a$b4$)$N)",
-- "set_optab_handler (smsub_widen_optab, $B, CODE_FOR_$(msub$a$b4$)$N)",
-- "set_optab_handler (umsub_widen_optab, $B, CODE_FOR_$(umsub$a$b4$)$N)",
-- "set_optab_handler (ssmsub_widen_optab, $B, CODE_FOR_$(ssmsub$a$b4$)$N)",
-- "set_optab_handler (usmsub_widen_optab, $B, CODE_FOR_$(usmsub$a$b4$)$N)",
-+ "set_widening_optab_handler (smul_widen_optab, $B, $A, CODE_FOR_$(mul$a$b3$)$N)",
-+ "set_widening_optab_handler (umul_widen_optab, $B, $A, CODE_FOR_$(umul$a$b3$)$N)",
-+ "set_widening_optab_handler (usmul_widen_optab, $B, $A, CODE_FOR_$(usmul$a$b3$)$N)",
-+ "set_widening_optab_handler (smadd_widen_optab, $B, $A, CODE_FOR_$(madd$a$b4$)$N)",
-+ "set_widening_optab_handler (umadd_widen_optab, $B, $A, CODE_FOR_$(umadd$a$b4$)$N)",
-+ "set_widening_optab_handler (ssmadd_widen_optab, $B, $A, CODE_FOR_$(ssmadd$a$b4$)$N)",
-+ "set_widening_optab_handler (usmadd_widen_optab, $B, $A, CODE_FOR_$(usmadd$a$b4$)$N)",
-+ "set_widening_optab_handler (smsub_widen_optab, $B, $A, CODE_FOR_$(msub$a$b4$)$N)",
-+ "set_widening_optab_handler (umsub_widen_optab, $B, $A, CODE_FOR_$(umsub$a$b4$)$N)",
-+ "set_widening_optab_handler (ssmsub_widen_optab, $B, $A, CODE_FOR_$(ssmsub$a$b4$)$N)",
-+ "set_widening_optab_handler (usmsub_widen_optab, $B, $A, CODE_FOR_$(usmsub$a$b4$)$N)",
- "set_optab_handler (sdiv_optab, $A, CODE_FOR_$(div$a3$))",
- "set_optab_handler (ssdiv_optab, $A, CODE_FOR_$(ssdiv$Q$a3$))",
- "set_optab_handler (sdivv_optab, $A, CODE_FOR_$(div$V$I$a3$))",
-@@ -304,7 +306,7 @@
- {
- int force_float = 0, force_int = 0, force_partial_int = 0;
- int force_fixed = 0;
-- int force_consec = 0;
-+ int force_wider = 0;
- int matches = 1;
-
- for (pp = optabs[pindex]; pp[0] != '$' || pp[1] != '('; pp++)
-@@ -322,7 +324,7 @@
- switch (*++pp)
- {
- case 'N':
-- force_consec = 1;
-+ force_wider = 1;
- break;
- case 'I':
- force_int = 1;
-@@ -391,7 +393,10 @@
- || mode_class[i] == MODE_VECTOR_FRACT
- || mode_class[i] == MODE_VECTOR_UFRACT
- || mode_class[i] == MODE_VECTOR_ACCUM
-- || mode_class[i] == MODE_VECTOR_UACCUM))
-+ || mode_class[i] == MODE_VECTOR_UACCUM)
-+ && (! force_wider
-+ || *pp == 'a'
-+ || m1 < i))
- break;
- }
-
-@@ -411,8 +416,7 @@
- }
-
- if (matches && pp[0] == '$' && pp[1] == ')'
-- && *np == 0
-- && (! force_consec || (int) GET_MODE_WIDER_MODE(m1) == m2))
-+ && *np == 0)
- break;
- }
-
-
-=== modified file 'gcc/optabs.c'
---- old/gcc/optabs.c 2011-07-04 14:03:49 +0000
-+++ new/gcc/optabs.c 2011-08-11 15:46:01 +0000
-@@ -225,6 +225,61 @@
- return 1;
- }
-
-+/* Given two input operands, OP0 and OP1, determine what the correct from_mode
-+ for a widening operation would be. In most cases this would be OP0, but if
-+ that's a constant it'll be VOIDmode, which isn't useful. */
-+
-+static enum machine_mode
-+widened_mode (enum machine_mode to_mode, rtx op0, rtx op1)
-+{
-+ enum machine_mode m0 = GET_MODE (op0);
-+ enum machine_mode m1 = GET_MODE (op1);
-+ enum machine_mode result;
-+
-+ if (m0 == VOIDmode && m1 == VOIDmode)
-+ return to_mode;
-+ else if (m0 == VOIDmode || GET_MODE_SIZE (m0) < GET_MODE_SIZE (m1))
-+ result = m1;
-+ else
-+ result = m0;
-+
-+ if (GET_MODE_SIZE (result) > GET_MODE_SIZE (to_mode))
-+ return to_mode;
-+
-+ return result;
-+}
-+
-+/* Find a widening optab even if it doesn't widen as much as we want.
-+ E.g. if from_mode is HImode, and to_mode is DImode, and there is no
-+ direct HI->SI insn, then return SI->DI, if that exists.
-+ If PERMIT_NON_WIDENING is non-zero then this can be used with
-+ non-widening optabs also. */
-+
-+enum insn_code
-+find_widening_optab_handler_and_mode (optab op, enum machine_mode to_mode,
-+ enum machine_mode from_mode,
-+ int permit_non_widening,
-+ enum machine_mode *found_mode)
-+{
-+ for (; (permit_non_widening || from_mode != to_mode)
-+ && GET_MODE_SIZE (from_mode) <= GET_MODE_SIZE (to_mode)
-+ && from_mode != VOIDmode;
-+ from_mode = GET_MODE_WIDER_MODE (from_mode))
-+ {
-+ enum insn_code handler = widening_optab_handler (op, to_mode,
-+ from_mode);
-+
-+ if (handler != CODE_FOR_nothing)
-+ {
-+ if (found_mode)
-+ *found_mode = from_mode;
-+ return handler;
-+ }
-+ }
-+
-+ return CODE_FOR_nothing;
-+}
-+
- /* Widen OP to MODE and return the rtx for the widened operand. UNSIGNEDP
- says whether OP is signed or unsigned. NO_EXTEND is nonzero if we need
- not actually do a sign-extend or zero-extend, but can leave the
-@@ -517,8 +572,9 @@
- optab_for_tree_code (ops->code, TREE_TYPE (oprnd0), optab_default);
- if (ops->code == WIDEN_MULT_PLUS_EXPR
- || ops->code == WIDEN_MULT_MINUS_EXPR)
-- icode = (int) optab_handler (widen_pattern_optab,
-- TYPE_MODE (TREE_TYPE (ops->op2)));
-+ icode = (int) find_widening_optab_handler (widen_pattern_optab,
-+ TYPE_MODE (TREE_TYPE (ops->op2)),
-+ tmode0, 0);
- else
- icode = (int) optab_handler (widen_pattern_optab, tmode0);
- gcc_assert (icode != CODE_FOR_nothing);
-@@ -1389,7 +1445,9 @@
- rtx target, int unsignedp, enum optab_methods methods,
- rtx last)
- {
-- int icode = (int) optab_handler (binoptab, mode);
-+ enum machine_mode from_mode = widened_mode (mode, op0, op1);
-+ int icode = (int) find_widening_optab_handler (binoptab, mode,
-+ from_mode, 1);
- enum machine_mode mode0 = insn_data[icode].operand[1].mode;
- enum machine_mode mode1 = insn_data[icode].operand[2].mode;
- enum machine_mode tmp_mode;
-@@ -1546,7 +1604,9 @@
- /* If we can do it with a three-operand insn, do so. */
-
- if (methods != OPTAB_MUST_WIDEN
-- && optab_handler (binoptab, mode) != CODE_FOR_nothing)
-+ && find_widening_optab_handler (binoptab, mode,
-+ widened_mode (mode, op0, op1), 1)
-+ != CODE_FOR_nothing)
- {
- temp = expand_binop_directly (mode, binoptab, op0, op1, target,
- unsignedp, methods, last);
-@@ -1586,8 +1646,9 @@
-
- if (binoptab == smul_optab
- && GET_MODE_WIDER_MODE (mode) != VOIDmode
-- && (optab_handler ((unsignedp ? umul_widen_optab : smul_widen_optab),
-- GET_MODE_WIDER_MODE (mode))
-+ && (widening_optab_handler ((unsignedp ? umul_widen_optab
-+ : smul_widen_optab),
-+ GET_MODE_WIDER_MODE (mode), mode)
- != CODE_FOR_nothing))
- {
- temp = expand_binop (GET_MODE_WIDER_MODE (mode),
-@@ -1618,9 +1679,11 @@
- if (optab_handler (binoptab, wider_mode) != CODE_FOR_nothing
- || (binoptab == smul_optab
- && GET_MODE_WIDER_MODE (wider_mode) != VOIDmode
-- && (optab_handler ((unsignedp ? umul_widen_optab
-- : smul_widen_optab),
-- GET_MODE_WIDER_MODE (wider_mode))
-+ && (find_widening_optab_handler ((unsignedp
-+ ? umul_widen_optab
-+ : smul_widen_optab),
-+ GET_MODE_WIDER_MODE (wider_mode),
-+ mode, 0)
- != CODE_FOR_nothing)))
- {
- rtx xop0 = op0, xop1 = op1;
-@@ -2043,8 +2106,8 @@
- && optab_handler (add_optab, word_mode) != CODE_FOR_nothing)
- {
- rtx product = NULL_RTX;
--
-- if (optab_handler (umul_widen_optab, mode) != CODE_FOR_nothing)
-+ if (widening_optab_handler (umul_widen_optab, mode, word_mode)
-+ != CODE_FOR_nothing)
- {
- product = expand_doubleword_mult (mode, op0, op1, target,
- true, methods);
-@@ -2053,7 +2116,8 @@
- }
-
- if (product == NULL_RTX
-- && optab_handler (smul_widen_optab, mode) != CODE_FOR_nothing)
-+ && widening_optab_handler (smul_widen_optab, mode, word_mode)
-+ != CODE_FOR_nothing)
- {
- product = expand_doubleword_mult (mode, op0, op1, target,
- false, methods);
-@@ -2144,7 +2208,8 @@
- wider_mode != VOIDmode;
- wider_mode = GET_MODE_WIDER_MODE (wider_mode))
- {
-- if (optab_handler (binoptab, wider_mode) != CODE_FOR_nothing
-+ if (find_widening_optab_handler (binoptab, wider_mode, mode, 1)
-+ != CODE_FOR_nothing
- || (methods == OPTAB_LIB
- && optab_libfunc (binoptab, wider_mode)))
- {
-
-=== modified file 'gcc/optabs.h'
---- old/gcc/optabs.h 2011-05-05 15:43:06 +0000
-+++ new/gcc/optabs.h 2011-07-27 14:12:45 +0000
-@@ -42,6 +42,11 @@
- int insn_code;
- };
-
-+struct widening_optab_handlers
-+{
-+ struct optab_handlers handlers[NUM_MACHINE_MODES][NUM_MACHINE_MODES];
-+};
-+
- struct optab_d
- {
- enum rtx_code code;
-@@ -50,6 +55,7 @@
- void (*libcall_gen)(struct optab_d *, const char *name, char suffix,
- enum machine_mode);
- struct optab_handlers handlers[NUM_MACHINE_MODES];
-+ struct widening_optab_handlers *widening;
- };
- typedef struct optab_d * optab;
-
-@@ -799,6 +805,15 @@
- extern void emit_unop_insn (int, rtx, rtx, enum rtx_code);
- extern bool maybe_emit_unop_insn (int, rtx, rtx, enum rtx_code);
-
-+/* Find a widening optab even if it doesn't widen as much as we want. */
-+#define find_widening_optab_handler(A,B,C,D) \
-+ find_widening_optab_handler_and_mode (A, B, C, D, NULL)
-+extern enum insn_code find_widening_optab_handler_and_mode (optab,
-+ enum machine_mode,
-+ enum machine_mode,
-+ int,
-+ enum machine_mode *);
-+
- /* An extra flag to control optab_for_tree_code's behavior. This is needed to
- distinguish between machines with a vector shift that takes a scalar for the
- shift amount vs. machines that take a vector for the shift amount. */
-@@ -874,6 +889,23 @@
- + (int) CODE_FOR_nothing);
- }
-
-+/* Like optab_handler, but for widening_operations that have a TO_MODE and
-+ a FROM_MODE. */
-+
-+static inline enum insn_code
-+widening_optab_handler (optab op, enum machine_mode to_mode,
-+ enum machine_mode from_mode)
-+{
-+ if (to_mode == from_mode || from_mode == VOIDmode)
-+ return optab_handler (op, to_mode);
-+
-+ if (op->widening)
-+ return (enum insn_code) (op->widening->handlers[(int) to_mode][(int) from_mode].insn_code
-+ + (int) CODE_FOR_nothing);
-+
-+ return CODE_FOR_nothing;
-+}
-+
- /* Record that insn CODE should be used to implement mode MODE of OP. */
-
- static inline void
-@@ -882,6 +914,26 @@
- op->handlers[(int) mode].insn_code = (int) code - (int) CODE_FOR_nothing;
- }
-
-+/* Like set_optab_handler, but for widening operations that have a TO_MODE
-+ and a FROM_MODE. */
-+
-+static inline void
-+set_widening_optab_handler (optab op, enum machine_mode to_mode,
-+ enum machine_mode from_mode, enum insn_code code)
-+{
-+ if (to_mode == from_mode)
-+ set_optab_handler (op, to_mode, code);
-+ else
-+ {
-+ if (op->widening == NULL)
-+ op->widening = (struct widening_optab_handlers *)
-+ xcalloc (1, sizeof (struct widening_optab_handlers));
-+
-+ op->widening->handlers[(int) to_mode][(int) from_mode].insn_code
-+ = (int) code - (int) CODE_FOR_nothing;
-+ }
-+}
-+
- /* Return the insn used to perform conversion OP from mode FROM_MODE
- to mode TO_MODE; return CODE_FOR_nothing if the target does not have
- such an insn. */
-
-=== added file 'gcc/testsuite/gcc.target/arm/no-wmla-1.c'
---- old/gcc/testsuite/gcc.target/arm/no-wmla-1.c 1970-01-01 00:00:00 +0000
-+++ new/gcc/testsuite/gcc.target/arm/no-wmla-1.c 2011-07-15 13:52:38 +0000
-@@ -0,0 +1,11 @@
-+/* { dg-do compile } */
-+/* { dg-options "-O2 -march=armv7-a" } */
-+
-+int
-+foo (int a, short b, short c)
-+{
-+ int bc = b * c;
-+ return a + (short)bc;
-+}
-+
-+/* { dg-final { scan-assembler "mul" } } */
-
-=== added file 'gcc/testsuite/gcc.target/arm/wmul-10.c'
---- old/gcc/testsuite/gcc.target/arm/wmul-10.c 1970-01-01 00:00:00 +0000
-+++ new/gcc/testsuite/gcc.target/arm/wmul-10.c 2011-07-18 12:56:20 +0000
-@@ -0,0 +1,10 @@
-+/* { dg-do compile } */
-+/* { dg-options "-O2 -march=armv7-a" } */
-+
-+unsigned long long
-+foo (unsigned short a, unsigned short *b, unsigned short *c)
-+{
-+ return (unsigned)a + (unsigned long long)*b * (unsigned long long)*c;
-+}
-+
-+/* { dg-final { scan-assembler "umlal" } } */
-
-=== added file 'gcc/testsuite/gcc.target/arm/wmul-11.c'
---- old/gcc/testsuite/gcc.target/arm/wmul-11.c 1970-01-01 00:00:00 +0000
-+++ new/gcc/testsuite/gcc.target/arm/wmul-11.c 2011-07-22 15:46:42 +0000
-@@ -0,0 +1,10 @@
-+/* { dg-do compile } */
-+/* { dg-options "-O2 -march=armv7-a" } */
-+
-+long long
-+foo (int *b)
-+{
-+ return 10 * (long long)*b;
-+}
-+
-+/* { dg-final { scan-assembler "smull" } } */
-
-=== added file 'gcc/testsuite/gcc.target/arm/wmul-12.c'
---- old/gcc/testsuite/gcc.target/arm/wmul-12.c 1970-01-01 00:00:00 +0000
-+++ new/gcc/testsuite/gcc.target/arm/wmul-12.c 2011-07-22 15:46:42 +0000
-@@ -0,0 +1,11 @@
-+/* { dg-do compile } */
-+/* { dg-options "-O2 -march=armv7-a" } */
-+
-+long long
-+foo (int *b, int *c)
-+{
-+ int tmp = *b * *c;
-+ return 10 + (long long)tmp;
-+}
-+
-+/* { dg-final { scan-assembler "smlal" } } */
-
-=== added file 'gcc/testsuite/gcc.target/arm/wmul-13.c'
---- old/gcc/testsuite/gcc.target/arm/wmul-13.c 1970-01-01 00:00:00 +0000
-+++ new/gcc/testsuite/gcc.target/arm/wmul-13.c 2011-07-22 15:46:42 +0000
-@@ -0,0 +1,10 @@
-+/* { dg-do compile } */
-+/* { dg-options "-O2 -march=armv7-a" } */
-+
-+long long
-+foo (int *a, int *b)
-+{
-+ return *a + (long long)*b * 10;
-+}
-+
-+/* { dg-final { scan-assembler "smlal" } } */
-
-=== added file 'gcc/testsuite/gcc.target/arm/wmul-5.c'
---- old/gcc/testsuite/gcc.target/arm/wmul-5.c 1970-01-01 00:00:00 +0000
-+++ new/gcc/testsuite/gcc.target/arm/wmul-5.c 2011-07-15 13:52:38 +0000
-@@ -0,0 +1,10 @@
-+/* { dg-do compile } */
-+/* { dg-options "-O2 -march=armv7-a" } */
-+
-+long long
-+foo (long long a, char *b, char *c)
-+{
-+ return a + *b * *c;
-+}
-+
-+/* { dg-final { scan-assembler "umlal" } } */
-
-=== added file 'gcc/testsuite/gcc.target/arm/wmul-6.c'
---- old/gcc/testsuite/gcc.target/arm/wmul-6.c 1970-01-01 00:00:00 +0000
-+++ new/gcc/testsuite/gcc.target/arm/wmul-6.c 2011-07-15 13:59:11 +0000
-@@ -0,0 +1,10 @@
-+/* { dg-do compile } */
-+/* { dg-options "-O2 -march=armv7-a" } */
-+
-+long long
-+foo (long long a, unsigned char *b, signed char *c)
-+{
-+ return a + (long long)*b * (long long)*c;
-+}
-+
-+/* { dg-final { scan-assembler "smlal" } } */
-
-=== added file 'gcc/testsuite/gcc.target/arm/wmul-7.c'
---- old/gcc/testsuite/gcc.target/arm/wmul-7.c 1970-01-01 00:00:00 +0000
-+++ new/gcc/testsuite/gcc.target/arm/wmul-7.c 2011-07-15 14:11:23 +0000
-@@ -0,0 +1,10 @@
-+/* { dg-do compile } */
-+/* { dg-options "-O2 -march=armv7-a" } */
-+
-+unsigned long long
-+foo (unsigned long long a, unsigned char *b, unsigned short *c)
-+{
-+ return a + *b * *c;
-+}
-+
-+/* { dg-final { scan-assembler "umlal" } } */
-
-=== added file 'gcc/testsuite/gcc.target/arm/wmul-8.c'
---- old/gcc/testsuite/gcc.target/arm/wmul-8.c 1970-01-01 00:00:00 +0000
-+++ new/gcc/testsuite/gcc.target/arm/wmul-8.c 2011-07-15 14:16:54 +0000
-@@ -0,0 +1,10 @@
-+/* { dg-do compile } */
-+/* { dg-options "-O2 -march=armv7-a" } */
-+
-+long long
-+foo (long long a, int *b, int *c)
-+{
-+ return a + *b * *c;
-+}
-+
-+/* { dg-final { scan-assembler "smlal" } } */
-
-=== added file 'gcc/testsuite/gcc.target/arm/wmul-9.c'
---- old/gcc/testsuite/gcc.target/arm/wmul-9.c 1970-01-01 00:00:00 +0000
-+++ new/gcc/testsuite/gcc.target/arm/wmul-9.c 2011-07-15 14:22:39 +0000
-@@ -0,0 +1,10 @@
-+/* { dg-do compile } */
-+/* { dg-options "-O2 -march=armv7-a" } */
-+
-+long long
-+foo (long long a, short *b, char *c)
-+{
-+ return a + *b * *c;
-+}
-+
-+/* { dg-final { scan-assembler "smlalbb" } } */
-
-=== added file 'gcc/testsuite/gcc.target/arm/wmul-bitfield-1.c'
---- old/gcc/testsuite/gcc.target/arm/wmul-bitfield-1.c 1970-01-01 00:00:00 +0000
-+++ new/gcc/testsuite/gcc.target/arm/wmul-bitfield-1.c 2011-07-15 13:44:50 +0000
-@@ -0,0 +1,17 @@
-+/* { dg-do compile } */
-+/* { dg-options "-O2 -march=armv7-a" } */
-+
-+struct bf
-+{
-+ int a : 3;
-+ int b : 15;
-+ int c : 3;
-+};
-+
-+long long
-+foo (long long a, struct bf b, struct bf c)
-+{
-+ return a + b.b * c.b;
-+}
-+
-+/* { dg-final { scan-assembler "smlalbb" } } */
-
-=== added file 'gcc/testsuite/gcc.target/arm/wmul-bitfield-2.c'
---- old/gcc/testsuite/gcc.target/arm/wmul-bitfield-2.c 1970-01-01 00:00:00 +0000
-+++ new/gcc/testsuite/gcc.target/arm/wmul-bitfield-2.c 2011-07-15 14:22:39 +0000
-@@ -0,0 +1,17 @@
-+/* { dg-do compile } */
-+/* { dg-options "-O2 -march=armv7-a" } */
-+
-+struct bf
-+{
-+ int a : 3;
-+ unsigned int b : 15;
-+ int c : 3;
-+};
-+
-+long long
-+foo (long long a, struct bf b, struct bf c)
-+{
-+ return a + b.b * c.c;
-+}
-+
-+/* { dg-final { scan-assembler "smlalbb" } } */
-
-=== modified file 'gcc/tree-cfg.c'
---- old/gcc/tree-cfg.c 2011-07-01 09:19:21 +0000
-+++ new/gcc/tree-cfg.c 2011-07-15 13:44:50 +0000
-@@ -3574,7 +3574,7 @@
- case WIDEN_MULT_EXPR:
- if (TREE_CODE (lhs_type) != INTEGER_TYPE)
- return true;
-- return ((2 * TYPE_PRECISION (rhs1_type) != TYPE_PRECISION (lhs_type))
-+ return ((2 * TYPE_PRECISION (rhs1_type) > TYPE_PRECISION (lhs_type))
- || (TYPE_PRECISION (rhs1_type) != TYPE_PRECISION (rhs2_type)));
-
- case WIDEN_SUM_EXPR:
-@@ -3667,7 +3667,7 @@
- && !FIXED_POINT_TYPE_P (rhs1_type))
- || !useless_type_conversion_p (rhs1_type, rhs2_type)
- || !useless_type_conversion_p (lhs_type, rhs3_type)
-- || 2 * TYPE_PRECISION (rhs1_type) != TYPE_PRECISION (lhs_type)
-+ || 2 * TYPE_PRECISION (rhs1_type) > TYPE_PRECISION (lhs_type)
- || TYPE_PRECISION (rhs1_type) != TYPE_PRECISION (rhs2_type))
- {
- error ("type mismatch in widening multiply-accumulate expression");
-
-=== modified file 'gcc/tree-ssa-math-opts.c'
---- old/gcc/tree-ssa-math-opts.c 2011-03-11 16:36:16 +0000
-+++ new/gcc/tree-ssa-math-opts.c 2011-08-09 10:26:48 +0000
-@@ -1266,39 +1266,67 @@
- }
- };
-
--/* Return true if RHS is a suitable operand for a widening multiplication.
-+/* Build a gimple assignment to cast VAL to TARGET. Insert the statement
-+ prior to GSI's current position, and return the fresh SSA name. */
-+
-+static tree
-+build_and_insert_cast (gimple_stmt_iterator *gsi, location_t loc,
-+ tree target, tree val)
-+{
-+ tree result = make_ssa_name (target, NULL);
-+ gimple stmt = gimple_build_assign_with_ops (CONVERT_EXPR, result, val, NULL);
-+ gimple_set_location (stmt, loc);
-+ gsi_insert_before (gsi, stmt, GSI_SAME_STMT);
-+ return result;
-+}
-+
-+/* Return true if RHS is a suitable operand for a widening multiplication,
-+ assuming a target type of TYPE.
- There are two cases:
-
-- - RHS makes some value twice as wide. Store that value in *NEW_RHS_OUT
-- if so, and store its type in *TYPE_OUT.
-+ - RHS makes some value at least twice as wide. Store that value
-+ in *NEW_RHS_OUT if so, and store its type in *TYPE_OUT.
-
- - RHS is an integer constant. Store that value in *NEW_RHS_OUT if so,
- but leave *TYPE_OUT untouched. */
-
- static bool
--is_widening_mult_rhs_p (tree rhs, tree *type_out, tree *new_rhs_out)
-+is_widening_mult_rhs_p (tree type, tree rhs, tree *type_out,
-+ tree *new_rhs_out)
- {
- gimple stmt;
-- tree type, type1, rhs1;
-+ tree type1, rhs1;
- enum tree_code rhs_code;
-
- if (TREE_CODE (rhs) == SSA_NAME)
- {
-- type = TREE_TYPE (rhs);
- stmt = SSA_NAME_DEF_STMT (rhs);
-- if (!is_gimple_assign (stmt))
-- return false;
--
-- rhs_code = gimple_assign_rhs_code (stmt);
-- if (TREE_CODE (type) == INTEGER_TYPE
-- ? !CONVERT_EXPR_CODE_P (rhs_code)
-- : rhs_code != FIXED_CONVERT_EXPR)
-- return false;
--
-- rhs1 = gimple_assign_rhs1 (stmt);
-+ if (is_gimple_assign (stmt))
-+ {
-+ rhs_code = gimple_assign_rhs_code (stmt);
-+ if (TREE_CODE (type) == INTEGER_TYPE
-+ ? !CONVERT_EXPR_CODE_P (rhs_code)
-+ : rhs_code != FIXED_CONVERT_EXPR)
-+ rhs1 = rhs;
-+ else
-+ {
-+ rhs1 = gimple_assign_rhs1 (stmt);
-+
-+ if (TREE_CODE (rhs1) == INTEGER_CST)
-+ {
-+ *new_rhs_out = rhs1;
-+ *type_out = NULL;
-+ return true;
-+ }
-+ }
-+ }
-+ else
-+ rhs1 = rhs;
-+
- type1 = TREE_TYPE (rhs1);
-+
- if (TREE_CODE (type1) != TREE_CODE (type)
-- || TYPE_PRECISION (type1) * 2 != TYPE_PRECISION (type))
-+ || TYPE_PRECISION (type1) * 2 > TYPE_PRECISION (type))
- return false;
-
- *new_rhs_out = rhs1;
-@@ -1316,28 +1344,27 @@
- return false;
- }
-
--/* Return true if STMT performs a widening multiplication. If so,
-- store the unwidened types of the operands in *TYPE1_OUT and *TYPE2_OUT
-- respectively. Also fill *RHS1_OUT and *RHS2_OUT such that converting
-- those operands to types *TYPE1_OUT and *TYPE2_OUT would give the
-- operands of the multiplication. */
-+/* Return true if STMT performs a widening multiplication, assuming the
-+ output type is TYPE. If so, store the unwidened types of the operands
-+ in *TYPE1_OUT and *TYPE2_OUT respectively. Also fill *RHS1_OUT and
-+ *RHS2_OUT such that converting those operands to types *TYPE1_OUT
-+ and *TYPE2_OUT would give the operands of the multiplication. */
-
- static bool
--is_widening_mult_p (gimple stmt,
-+is_widening_mult_p (tree type, gimple stmt,
- tree *type1_out, tree *rhs1_out,
- tree *type2_out, tree *rhs2_out)
- {
-- tree type;
--
-- type = TREE_TYPE (gimple_assign_lhs (stmt));
- if (TREE_CODE (type) != INTEGER_TYPE
- && TREE_CODE (type) != FIXED_POINT_TYPE)
- return false;
-
-- if (!is_widening_mult_rhs_p (gimple_assign_rhs1 (stmt), type1_out, rhs1_out))
-+ if (!is_widening_mult_rhs_p (type, gimple_assign_rhs1 (stmt), type1_out,
-+ rhs1_out))
- return false;
-
-- if (!is_widening_mult_rhs_p (gimple_assign_rhs2 (stmt), type2_out, rhs2_out))
-+ if (!is_widening_mult_rhs_p (type, gimple_assign_rhs2 (stmt), type2_out,
-+ rhs2_out))
- return false;
-
- if (*type1_out == NULL)
-@@ -1354,6 +1381,18 @@
- *type2_out = *type1_out;
- }
-
-+ /* Ensure that the larger of the two operands comes first. */
-+ if (TYPE_PRECISION (*type1_out) < TYPE_PRECISION (*type2_out))
-+ {
-+ tree tmp;
-+ tmp = *type1_out;
-+ *type1_out = *type2_out;
-+ *type2_out = tmp;
-+ tmp = *rhs1_out;
-+ *rhs1_out = *rhs2_out;
-+ *rhs2_out = tmp;
-+ }
-+
- return true;
- }
-
-@@ -1362,31 +1401,100 @@
- value is true iff we converted the statement. */
-
- static bool
--convert_mult_to_widen (gimple stmt)
-+convert_mult_to_widen (gimple stmt, gimple_stmt_iterator *gsi)
- {
-- tree lhs, rhs1, rhs2, type, type1, type2;
-+ tree lhs, rhs1, rhs2, type, type1, type2, tmp = NULL;
- enum insn_code handler;
-+ enum machine_mode to_mode, from_mode, actual_mode;
-+ optab op;
-+ int actual_precision;
-+ location_t loc = gimple_location (stmt);
-+ bool from_unsigned1, from_unsigned2;
-
- lhs = gimple_assign_lhs (stmt);
- type = TREE_TYPE (lhs);
- if (TREE_CODE (type) != INTEGER_TYPE)
- return false;
-
-- if (!is_widening_mult_p (stmt, &type1, &rhs1, &type2, &rhs2))
-+ if (!is_widening_mult_p (type, stmt, &type1, &rhs1, &type2, &rhs2))
- return false;
-
-- if (TYPE_UNSIGNED (type1) && TYPE_UNSIGNED (type2))
-- handler = optab_handler (umul_widen_optab, TYPE_MODE (type));
-- else if (!TYPE_UNSIGNED (type1) && !TYPE_UNSIGNED (type2))
-- handler = optab_handler (smul_widen_optab, TYPE_MODE (type));
-+ to_mode = TYPE_MODE (type);
-+ from_mode = TYPE_MODE (type1);
-+ from_unsigned1 = TYPE_UNSIGNED (type1);
-+ from_unsigned2 = TYPE_UNSIGNED (type2);
-+
-+ if (from_unsigned1 && from_unsigned2)
-+ op = umul_widen_optab;
-+ else if (!from_unsigned1 && !from_unsigned2)
-+ op = smul_widen_optab;
- else
-- handler = optab_handler (usmul_widen_optab, TYPE_MODE (type));
-+ op = usmul_widen_optab;
-+
-+ handler = find_widening_optab_handler_and_mode (op, to_mode, from_mode,
-+ 0, &actual_mode);
-
- if (handler == CODE_FOR_nothing)
-- return false;
--
-- gimple_assign_set_rhs1 (stmt, fold_convert (type1, rhs1));
-- gimple_assign_set_rhs2 (stmt, fold_convert (type2, rhs2));
-+ {
-+ if (op != smul_widen_optab)
-+ {
-+ /* 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. */
-+ if ((TYPE_UNSIGNED (type1)
-+ && TYPE_PRECISION (type1) == GET_MODE_PRECISION (from_mode))
-+ || (TYPE_UNSIGNED (type2)
-+ && TYPE_PRECISION (type2) == GET_MODE_PRECISION (from_mode)))
-+ {
-+ from_mode = GET_MODE_WIDER_MODE (from_mode);
-+ if (GET_MODE_SIZE (to_mode) <= GET_MODE_SIZE (from_mode))
-+ return false;
-+ }
-+
-+ op = smul_widen_optab;
-+ handler = find_widening_optab_handler_and_mode (op, to_mode,
-+ from_mode, 0,
-+ &actual_mode);
-+
-+ if (handler == CODE_FOR_nothing)
-+ return false;
-+
-+ from_unsigned1 = from_unsigned2 = false;
-+ }
-+ else
-+ return false;
-+ }
-+
-+ /* Ensure that the inputs to the handler are in the correct precison
-+ for the opcode. This will be the full mode size. */
-+ actual_precision = GET_MODE_PRECISION (actual_mode);
-+ if (actual_precision != TYPE_PRECISION (type1)
-+ || from_unsigned1 != TYPE_UNSIGNED (type1))
-+ {
-+ tmp = create_tmp_var (build_nonstandard_integer_type
-+ (actual_precision, from_unsigned1),
-+ NULL);
-+ rhs1 = build_and_insert_cast (gsi, loc, tmp, rhs1);
-+ }
-+ if (actual_precision != TYPE_PRECISION (type2)
-+ || from_unsigned2 != TYPE_UNSIGNED (type2))
-+ {
-+ /* Reuse the same type info, if possible. */
-+ if (!tmp || from_unsigned1 != from_unsigned2)
-+ tmp = create_tmp_var (build_nonstandard_integer_type
-+ (actual_precision, from_unsigned2),
-+ NULL);
-+ rhs2 = build_and_insert_cast (gsi, loc, tmp, rhs2);
-+ }
-+
-+ /* Handle constants. */
-+ if (TREE_CODE (rhs1) == INTEGER_CST)
-+ rhs1 = fold_convert (type1, rhs1);
-+ if (TREE_CODE (rhs2) == INTEGER_CST)
-+ rhs2 = fold_convert (type2, rhs2);
-+
-+ gimple_assign_set_rhs1 (stmt, rhs1);
-+ gimple_assign_set_rhs2 (stmt, rhs2);
- gimple_assign_set_rhs_code (stmt, WIDEN_MULT_EXPR);
- update_stmt (stmt);
- return true;
-@@ -1403,11 +1511,17 @@
- enum tree_code code)
- {
- gimple rhs1_stmt = NULL, rhs2_stmt = NULL;
-- tree type, type1, type2;
-+ gimple conv1_stmt = NULL, conv2_stmt = NULL, conv_stmt;
-+ tree type, type1, type2, optype, tmp = NULL;
- tree lhs, rhs1, rhs2, mult_rhs1, mult_rhs2, add_rhs;
- enum tree_code rhs1_code = ERROR_MARK, rhs2_code = ERROR_MARK;
- optab this_optab;
- enum tree_code wmult_code;
-+ enum insn_code handler;
-+ enum machine_mode to_mode, from_mode, actual_mode;
-+ location_t loc = gimple_location (stmt);
-+ int actual_precision;
-+ bool from_unsigned1, from_unsigned2;
-
- lhs = gimple_assign_lhs (stmt);
- type = TREE_TYPE (lhs);
-@@ -1429,8 +1543,6 @@
- if (is_gimple_assign (rhs1_stmt))
- rhs1_code = gimple_assign_rhs_code (rhs1_stmt);
- }
-- else
-- return false;
-
- if (TREE_CODE (rhs2) == SSA_NAME)
- {
-@@ -1438,57 +1550,160 @@
- if (is_gimple_assign (rhs2_stmt))
- rhs2_code = gimple_assign_rhs_code (rhs2_stmt);
- }
-- else
-- return false;
--
-- if (code == PLUS_EXPR && rhs1_code == MULT_EXPR)
-- {
-- if (!is_widening_mult_p (rhs1_stmt, &type1, &mult_rhs1,
-- &type2, &mult_rhs2))
-- return false;
-- add_rhs = rhs2;
-- }
-- else if (rhs2_code == MULT_EXPR)
-- {
-- if (!is_widening_mult_p (rhs2_stmt, &type1, &mult_rhs1,
-- &type2, &mult_rhs2))
-- return false;
-- add_rhs = rhs1;
-- }
-- else if (code == PLUS_EXPR && rhs1_code == WIDEN_MULT_EXPR)
-- {
-- mult_rhs1 = gimple_assign_rhs1 (rhs1_stmt);
-- mult_rhs2 = gimple_assign_rhs2 (rhs1_stmt);
-- type1 = TREE_TYPE (mult_rhs1);
-- type2 = TREE_TYPE (mult_rhs2);
-- add_rhs = rhs2;
-- }
-- else if (rhs2_code == WIDEN_MULT_EXPR)
-- {
-- mult_rhs1 = gimple_assign_rhs1 (rhs2_stmt);
-- mult_rhs2 = gimple_assign_rhs2 (rhs2_stmt);
-- type1 = TREE_TYPE (mult_rhs1);
-- type2 = TREE_TYPE (mult_rhs2);
-- add_rhs = rhs1;
-- }
-- else
-- return false;
--
-- if (TYPE_UNSIGNED (type1) != TYPE_UNSIGNED (type2))
-- return false;
-+
-+ /* Allow for one conversion statement between the multiply
-+ and addition/subtraction statement. If there are more than
-+ one conversions then we assume they would invalidate this
-+ transformation. If that's not the case then they should have
-+ been folded before now. */
-+ if (CONVERT_EXPR_CODE_P (rhs1_code))
-+ {
-+ conv1_stmt = rhs1_stmt;
-+ rhs1 = gimple_assign_rhs1 (rhs1_stmt);
-+ if (TREE_CODE (rhs1) == SSA_NAME)
-+ {
-+ rhs1_stmt = SSA_NAME_DEF_STMT (rhs1);
-+ if (is_gimple_assign (rhs1_stmt))
-+ rhs1_code = gimple_assign_rhs_code (rhs1_stmt);
-+ }
-+ else
-+ return false;
-+ }
-+ if (CONVERT_EXPR_CODE_P (rhs2_code))
-+ {
-+ conv2_stmt = rhs2_stmt;
-+ rhs2 = gimple_assign_rhs1 (rhs2_stmt);
-+ if (TREE_CODE (rhs2) == SSA_NAME)
-+ {
-+ rhs2_stmt = SSA_NAME_DEF_STMT (rhs2);
-+ if (is_gimple_assign (rhs2_stmt))
-+ rhs2_code = gimple_assign_rhs_code (rhs2_stmt);
-+ }
-+ else
-+ return false;
-+ }
-+
-+ /* If code is WIDEN_MULT_EXPR then it would seem unnecessary to call
-+ is_widening_mult_p, but we still need the rhs returns.
-+
-+ It might also appear that it would be sufficient to use the existing
-+ operands of the widening multiply, but that would limit the choice of
-+ multiply-and-accumulate instructions. */
-+ if (code == PLUS_EXPR
-+ && (rhs1_code == MULT_EXPR || rhs1_code == WIDEN_MULT_EXPR))
-+ {
-+ if (!is_widening_mult_p (type, rhs1_stmt, &type1, &mult_rhs1,
-+ &type2, &mult_rhs2))
-+ return false;
-+ add_rhs = rhs2;
-+ conv_stmt = conv1_stmt;
-+ }
-+ else if (rhs2_code == MULT_EXPR || rhs2_code == WIDEN_MULT_EXPR)
-+ {
-+ if (!is_widening_mult_p (type, rhs2_stmt, &type1, &mult_rhs1,
-+ &type2, &mult_rhs2))
-+ return false;
-+ add_rhs = rhs1;
-+ conv_stmt = conv2_stmt;
-+ }
-+ else
-+ return false;
-+
-+ to_mode = TYPE_MODE (type);
-+ from_mode = TYPE_MODE (type1);
-+ from_unsigned1 = TYPE_UNSIGNED (type1);
-+ from_unsigned2 = TYPE_UNSIGNED (type2);
-+
-+ /* There's no such thing as a mixed sign madd yet, so use a wider mode. */
-+ if (from_unsigned1 != from_unsigned2)
-+ {
-+ /* 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. */
-+ if ((from_unsigned1
-+ && TYPE_PRECISION (type1) == GET_MODE_PRECISION (from_mode))
-+ || (from_unsigned2
-+ && TYPE_PRECISION (type2) == GET_MODE_PRECISION (from_mode)))
-+ {
-+ from_mode = GET_MODE_WIDER_MODE (from_mode);
-+ if (GET_MODE_SIZE (from_mode) >= GET_MODE_SIZE (to_mode))
-+ return false;
-+ }
-+
-+ from_unsigned1 = from_unsigned2 = false;
-+ }
-+
-+ /* If there was a conversion between the multiply and addition
-+ then we need to make sure it fits a multiply-and-accumulate.
-+ The should be a single mode change which does not change the
-+ value. */
-+ if (conv_stmt)
-+ {
-+ /* We use the original, unmodified data types for this. */
-+ tree from_type = TREE_TYPE (gimple_assign_rhs1 (conv_stmt));
-+ tree to_type = TREE_TYPE (gimple_assign_lhs (conv_stmt));
-+ int data_size = TYPE_PRECISION (type1) + TYPE_PRECISION (type2);
-+ bool is_unsigned = TYPE_UNSIGNED (type1) && TYPE_UNSIGNED (type2);
-+
-+ if (TYPE_PRECISION (from_type) > TYPE_PRECISION (to_type))
-+ {
-+ /* Conversion is a truncate. */
-+ if (TYPE_PRECISION (to_type) < data_size)
-+ return false;
-+ }
-+ else if (TYPE_PRECISION (from_type) < TYPE_PRECISION (to_type))
-+ {
-+ /* Conversion is an extend. Check it's the right sort. */
-+ if (TYPE_UNSIGNED (from_type) != is_unsigned
-+ && !(is_unsigned && TYPE_PRECISION (from_type) > data_size))
-+ return false;
-+ }
-+ /* else convert is a no-op for our purposes. */
-+ }
-
- /* Verify that the machine can perform a widening multiply
- accumulate in this mode/signedness combination, otherwise
- this transformation is likely to pessimize code. */
-- this_optab = optab_for_tree_code (wmult_code, type1, optab_default);
-- if (optab_handler (this_optab, TYPE_MODE (type)) == CODE_FOR_nothing)
-+ 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);
-+
-+ if (handler == CODE_FOR_nothing)
- return false;
-
-- /* ??? May need some type verification here? */
--
-- gimple_assign_set_rhs_with_ops_1 (gsi, wmult_code,
-- fold_convert (type1, mult_rhs1),
-- fold_convert (type2, mult_rhs2),
-+ /* Ensure that the inputs to the handler are in the correct precison
-+ for the opcode. This will be the full mode size. */
-+ actual_precision = GET_MODE_PRECISION (actual_mode);
-+ if (actual_precision != TYPE_PRECISION (type1)
-+ || from_unsigned1 != TYPE_UNSIGNED (type1))
-+ {
-+ tmp = create_tmp_var (build_nonstandard_integer_type
-+ (actual_precision, from_unsigned1),
-+ NULL);
-+ mult_rhs1 = build_and_insert_cast (gsi, loc, tmp, mult_rhs1);
-+ }
-+ if (actual_precision != TYPE_PRECISION (type2)
-+ || from_unsigned2 != TYPE_UNSIGNED (type2))
-+ {
-+ if (!tmp || from_unsigned1 != from_unsigned2)
-+ tmp = create_tmp_var (build_nonstandard_integer_type
-+ (actual_precision, from_unsigned2),
-+ NULL);
-+ mult_rhs2 = build_and_insert_cast (gsi, loc, tmp, mult_rhs2);
-+ }
-+
-+ if (!useless_type_conversion_p (type, TREE_TYPE (add_rhs)))
-+ add_rhs = build_and_insert_cast (gsi, loc, create_tmp_var (type, NULL),
-+ add_rhs);
-+
-+ /* Handle constants. */
-+ if (TREE_CODE (mult_rhs1) == INTEGER_CST)
-+ rhs1 = fold_convert (type1, mult_rhs1);
-+ if (TREE_CODE (mult_rhs2) == INTEGER_CST)
-+ rhs2 = fold_convert (type2, mult_rhs2);
-+
-+ gimple_assign_set_rhs_with_ops_1 (gsi, wmult_code, mult_rhs1, mult_rhs2,
- add_rhs);
- update_stmt (gsi_stmt (*gsi));
- return true;
-@@ -1696,7 +1911,7 @@
- switch (code)
- {
- case MULT_EXPR:
-- if (!convert_mult_to_widen (stmt)
-+ if (!convert_mult_to_widen (stmt, &gsi)
- && convert_mult_to_fma (stmt,
- gimple_assign_rhs1 (stmt),
- gimple_assign_rhs2 (stmt)))
-