summaryrefslogtreecommitdiffstats
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 1a940975f..000000000
--- a/toolchain-layer/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106796.patch
+++ /dev/null
@@ -1,1255 +0,0 @@
12011-08-25 Andrew Stubbs <ams@codesourcery.com>
2
3 Backport from FSF mainline:
4
5 2011-08-19 Andrew Stubbs <ams@codesourcery.com>
6
7 gcc/
8 * tree-ssa-math-opts.c (is_widening_mult_rhs_p): Handle constants
9 beyond conversions.
10 (convert_mult_to_widen): Convert constant inputs to the right type.
11 (convert_plusminus_to_widen): Don't automatically reject inputs that
12 are not an SSA_NAME.
13 Convert constant inputs to the right type.
14
15 gcc/testsuite/
16 * gcc.target/arm/wmul-11.c: New file.
17 * gcc.target/arm/wmul-12.c: New file.
18 * gcc.target/arm/wmul-13.c: New file.
19
20 2011-08-19 Andrew Stubbs <ams@codesourcery.com>
21
22 gcc/
23 * tree-ssa-math-opts.c (convert_plusminus_to_widen): Convert add_rhs
24 to the correct type.
25
26 gcc/testsuite/
27 * gcc.target/arm/wmul-10.c: New file.
28
29 2011-08-19 Andrew Stubbs <ams@codesourcery.com>
30
31 gcc/
32 * tree-ssa-math-opts.c (convert_mult_to_widen): Better handle
33 unsigned inputs of different modes.
34 (convert_plusminus_to_widen): Likewise.
35
36 gcc/testsuite/
37 * gcc.target/arm/wmul-9.c: New file.
38 * gcc.target/arm/wmul-bitfield-2.c: New file.
39
40 2011-08-19 Andrew Stubbs <ams@codesourcery.com>
41
42 gcc/
43 * tree-ssa-math-opts.c (is_widening_mult_rhs_p): Add new argument
44 'type'.
45 Use 'type' from caller, not inferred from 'rhs'.
46 Don't reject non-conversion statements. Do return lhs in this case.
47 (is_widening_mult_p): Add new argument 'type'.
48 Use 'type' from caller, not inferred from 'stmt'.
49 Pass type to is_widening_mult_rhs_p.
50 (convert_mult_to_widen): Pass type to is_widening_mult_p.
51 (convert_plusminus_to_widen): Likewise.
52
53 gcc/testsuite/
54 * gcc.target/arm/wmul-8.c: New file.
55
56 2011-08-19 Andrew Stubbs <ams@codesourcery.com>
57
58 gcc/
59 * tree-ssa-math-opts.c (is_widening_mult_p): Remove FIXME.
60 Ensure the the larger type is the first operand.
61
62 gcc/testsuite/
63 * gcc.target/arm/wmul-7.c: New file.
64
65 2011-08-19 Andrew Stubbs <ams@codesourcery.com>
66
67 gcc/
68 * tree-ssa-math-opts.c (convert_mult_to_widen): Convert
69 unsupported unsigned multiplies to signed.
70 (convert_plusminus_to_widen): Likewise.
71
72 gcc/testsuite/
73 * gcc.target/arm/wmul-6.c: New file.
74
75 2011-08-19 Andrew Stubbs <ams@codesourcery.com>
76
77 gcc/
78 * tree-ssa-math-opts.c (convert_plusminus_to_widen): Permit a single
79 conversion statement separating multiply-and-accumulate.
80
81 gcc/testsuite/
82 * gcc.target/arm/wmul-5.c: New file.
83 * gcc.target/arm/no-wmla-1.c: New file.
84
85 2011-08-19 Andrew Stubbs <ams@codesourcery.com>
86
87 gcc/
88 * config/arm/arm.md (maddhidi4): Remove '*' from name.
89 * expr.c (expand_expr_real_2): Use find_widening_optab_handler.
90 * optabs.c (find_widening_optab_handler_and_mode): New function.
91 (expand_widen_pattern_expr): Use find_widening_optab_handler.
92 (expand_binop_directly): Likewise.
93 (expand_binop): Likewise.
94 * optabs.h (find_widening_optab_handler): New macro define.
95 (find_widening_optab_handler_and_mode): New prototype.
96 * tree-cfg.c (verify_gimple_assign_binary): Adjust WIDEN_MULT_EXPR
97 type precision rules.
98 (verify_gimple_assign_ternary): Likewise for WIDEN_MULT_PLUS_EXPR.
99 * tree-ssa-math-opts.c (build_and_insert_cast): New function.
100 (is_widening_mult_rhs_p): Allow widening by more than one mode.
101 Explicitly disallow mis-matched input types.
102 (convert_mult_to_widen): Use find_widening_optab_handler, and cast
103 input types to fit the new handler.
104 (convert_plusminus_to_widen): Likewise.
105
106 gcc/testsuite/
107 * gcc.target/arm/wmul-bitfield-1.c: New file.
108
109 2011-08-19 Andrew Stubbs <ams@codesourcery.com>
110
111 gcc/
112 * expr.c (expand_expr_real_2): Use widening_optab_handler.
113 * genopinit.c (optabs): Use set_widening_optab_handler for $N.
114 (gen_insn): $N now means $a must be wider than $b, not consecutive.
115 * optabs.c (widened_mode): New function.
116 (expand_widen_pattern_expr): Use widening_optab_handler.
117 (expand_binop_directly): Likewise.
118 (expand_binop): Likewise.
119 * optabs.h (widening_optab_handlers): New struct.
120 (optab_d): New member, 'widening'.
121 (widening_optab_handler): New function.
122 (set_widening_optab_handler): New function.
123 * tree-ssa-math-opts.c (convert_mult_to_widen): Use
124 widening_optab_handler.
125 (convert_plusminus_to_widen): Likewise.
126
127=== modified file 'gcc/config/arm/arm.md'
128--- old/gcc/config/arm/arm.md 2011-08-13 08:32:32 +0000
129+++ new/gcc/config/arm/arm.md 2011-08-25 11:42:09 +0000
130@@ -1839,7 +1839,7 @@
131 (set_attr "predicable" "yes")]
132 )
133
134-(define_insn "*maddhidi4"
135+(define_insn "maddhidi4"
136 [(set (match_operand:DI 0 "s_register_operand" "=r")
137 (plus:DI
138 (mult:DI (sign_extend:DI
139
140=== modified file 'gcc/expr.c'
141--- old/gcc/expr.c 2011-08-13 08:32:32 +0000
142+++ new/gcc/expr.c 2011-08-25 11:42:09 +0000
143@@ -7688,18 +7688,16 @@
144 {
145 enum machine_mode innermode = TYPE_MODE (TREE_TYPE (treeop0));
146 this_optab = usmul_widen_optab;
147- if (mode == GET_MODE_2XWIDER_MODE (innermode))
148+ if (find_widening_optab_handler (this_optab, mode, innermode, 0)
149+ != CODE_FOR_nothing)
150 {
151- if (optab_handler (this_optab, mode) != CODE_FOR_nothing)
152- {
153- if (TYPE_UNSIGNED (TREE_TYPE (treeop0)))
154- expand_operands (treeop0, treeop1, NULL_RTX, &op0, &op1,
155- EXPAND_NORMAL);
156- else
157- expand_operands (treeop0, treeop1, NULL_RTX, &op1, &op0,
158- EXPAND_NORMAL);
159- goto binop3;
160- }
161+ if (TYPE_UNSIGNED (TREE_TYPE (treeop0)))
162+ expand_operands (treeop0, treeop1, NULL_RTX, &op0, &op1,
163+ EXPAND_NORMAL);
164+ else
165+ expand_operands (treeop0, treeop1, NULL_RTX, &op1, &op0,
166+ EXPAND_NORMAL);
167+ goto binop3;
168 }
169 }
170 /* Check for a multiplication with matching signedness. */
171@@ -7714,10 +7712,10 @@
172 optab other_optab = zextend_p ? smul_widen_optab : umul_widen_optab;
173 this_optab = zextend_p ? umul_widen_optab : smul_widen_optab;
174
175- if (mode == GET_MODE_2XWIDER_MODE (innermode)
176- && TREE_CODE (treeop0) != INTEGER_CST)
177+ if (TREE_CODE (treeop0) != INTEGER_CST)
178 {
179- if (optab_handler (this_optab, mode) != CODE_FOR_nothing)
180+ if (find_widening_optab_handler (this_optab, mode, innermode, 0)
181+ != CODE_FOR_nothing)
182 {
183 expand_operands (treeop0, treeop1, NULL_RTX, &op0, &op1,
184 EXPAND_NORMAL);
185@@ -7725,7 +7723,8 @@
186 unsignedp, this_optab);
187 return REDUCE_BIT_FIELD (temp);
188 }
189- if (optab_handler (other_optab, mode) != CODE_FOR_nothing
190+ if (find_widening_optab_handler (other_optab, mode, innermode, 0)
191+ != CODE_FOR_nothing
192 && innermode == word_mode)
193 {
194 rtx htem, hipart;
195
196=== modified file 'gcc/genopinit.c'
197--- old/gcc/genopinit.c 2011-05-05 15:43:06 +0000
198+++ new/gcc/genopinit.c 2011-07-15 13:06:31 +0000
199@@ -46,10 +46,12 @@
200 used. $A and $B are replaced with the full name of the mode; $a and $b
201 are replaced with the short form of the name, as above.
202
203- If $N is present in the pattern, it means the two modes must be consecutive
204- widths in the same mode class (e.g, QImode and HImode). $I means that
205- only full integer modes should be considered for the next mode, and $F
206- means that only float modes should be considered.
207+ If $N is present in the pattern, it means the two modes must be in
208+ the same mode class, and $b must be greater than $a (e.g, QImode
209+ and HImode).
210+
211+ $I means that only full integer modes should be considered for the
212+ next mode, and $F means that only float modes should be considered.
213 $P means that both full and partial integer modes should be considered.
214 $Q means that only fixed-point modes should be considered.
215
216@@ -99,17 +101,17 @@
217 "set_optab_handler (smulv_optab, $A, CODE_FOR_$(mulv$I$a3$))",
218 "set_optab_handler (umul_highpart_optab, $A, CODE_FOR_$(umul$a3_highpart$))",
219 "set_optab_handler (smul_highpart_optab, $A, CODE_FOR_$(smul$a3_highpart$))",
220- "set_optab_handler (smul_widen_optab, $B, CODE_FOR_$(mul$a$b3$)$N)",
221- "set_optab_handler (umul_widen_optab, $B, CODE_FOR_$(umul$a$b3$)$N)",
222- "set_optab_handler (usmul_widen_optab, $B, CODE_FOR_$(usmul$a$b3$)$N)",
223- "set_optab_handler (smadd_widen_optab, $B, CODE_FOR_$(madd$a$b4$)$N)",
224- "set_optab_handler (umadd_widen_optab, $B, CODE_FOR_$(umadd$a$b4$)$N)",
225- "set_optab_handler (ssmadd_widen_optab, $B, CODE_FOR_$(ssmadd$a$b4$)$N)",
226- "set_optab_handler (usmadd_widen_optab, $B, CODE_FOR_$(usmadd$a$b4$)$N)",
227- "set_optab_handler (smsub_widen_optab, $B, CODE_FOR_$(msub$a$b4$)$N)",
228- "set_optab_handler (umsub_widen_optab, $B, CODE_FOR_$(umsub$a$b4$)$N)",
229- "set_optab_handler (ssmsub_widen_optab, $B, CODE_FOR_$(ssmsub$a$b4$)$N)",
230- "set_optab_handler (usmsub_widen_optab, $B, CODE_FOR_$(usmsub$a$b4$)$N)",
231+ "set_widening_optab_handler (smul_widen_optab, $B, $A, CODE_FOR_$(mul$a$b3$)$N)",
232+ "set_widening_optab_handler (umul_widen_optab, $B, $A, CODE_FOR_$(umul$a$b3$)$N)",
233+ "set_widening_optab_handler (usmul_widen_optab, $B, $A, CODE_FOR_$(usmul$a$b3$)$N)",
234+ "set_widening_optab_handler (smadd_widen_optab, $B, $A, CODE_FOR_$(madd$a$b4$)$N)",
235+ "set_widening_optab_handler (umadd_widen_optab, $B, $A, CODE_FOR_$(umadd$a$b4$)$N)",
236+ "set_widening_optab_handler (ssmadd_widen_optab, $B, $A, CODE_FOR_$(ssmadd$a$b4$)$N)",
237+ "set_widening_optab_handler (usmadd_widen_optab, $B, $A, CODE_FOR_$(usmadd$a$b4$)$N)",
238+ "set_widening_optab_handler (smsub_widen_optab, $B, $A, CODE_FOR_$(msub$a$b4$)$N)",
239+ "set_widening_optab_handler (umsub_widen_optab, $B, $A, CODE_FOR_$(umsub$a$b4$)$N)",
240+ "set_widening_optab_handler (ssmsub_widen_optab, $B, $A, CODE_FOR_$(ssmsub$a$b4$)$N)",
241+ "set_widening_optab_handler (usmsub_widen_optab, $B, $A, CODE_FOR_$(usmsub$a$b4$)$N)",
242 "set_optab_handler (sdiv_optab, $A, CODE_FOR_$(div$a3$))",
243 "set_optab_handler (ssdiv_optab, $A, CODE_FOR_$(ssdiv$Q$a3$))",
244 "set_optab_handler (sdivv_optab, $A, CODE_FOR_$(div$V$I$a3$))",
245@@ -304,7 +306,7 @@
246 {
247 int force_float = 0, force_int = 0, force_partial_int = 0;
248 int force_fixed = 0;
249- int force_consec = 0;
250+ int force_wider = 0;
251 int matches = 1;
252
253 for (pp = optabs[pindex]; pp[0] != '$' || pp[1] != '('; pp++)
254@@ -322,7 +324,7 @@
255 switch (*++pp)
256 {
257 case 'N':
258- force_consec = 1;
259+ force_wider = 1;
260 break;
261 case 'I':
262 force_int = 1;
263@@ -391,7 +393,10 @@
264 || mode_class[i] == MODE_VECTOR_FRACT
265 || mode_class[i] == MODE_VECTOR_UFRACT
266 || mode_class[i] == MODE_VECTOR_ACCUM
267- || mode_class[i] == MODE_VECTOR_UACCUM))
268+ || mode_class[i] == MODE_VECTOR_UACCUM)
269+ && (! force_wider
270+ || *pp == 'a'
271+ || m1 < i))
272 break;
273 }
274
275@@ -411,8 +416,7 @@
276 }
277
278 if (matches && pp[0] == '$' && pp[1] == ')'
279- && *np == 0
280- && (! force_consec || (int) GET_MODE_WIDER_MODE(m1) == m2))
281+ && *np == 0)
282 break;
283 }
284
285
286=== modified file 'gcc/optabs.c'
287--- old/gcc/optabs.c 2011-07-04 14:03:49 +0000
288+++ new/gcc/optabs.c 2011-08-11 15:46:01 +0000
289@@ -225,6 +225,61 @@
290 return 1;
291 }
292
293+/* Given two input operands, OP0 and OP1, determine what the correct from_mode
294+ for a widening operation would be. In most cases this would be OP0, but if
295+ that's a constant it'll be VOIDmode, which isn't useful. */
296+
297+static enum machine_mode
298+widened_mode (enum machine_mode to_mode, rtx op0, rtx op1)
299+{
300+ enum machine_mode m0 = GET_MODE (op0);
301+ enum machine_mode m1 = GET_MODE (op1);
302+ enum machine_mode result;
303+
304+ if (m0 == VOIDmode && m1 == VOIDmode)
305+ return to_mode;
306+ else if (m0 == VOIDmode || GET_MODE_SIZE (m0) < GET_MODE_SIZE (m1))
307+ result = m1;
308+ else
309+ result = m0;
310+
311+ if (GET_MODE_SIZE (result) > GET_MODE_SIZE (to_mode))
312+ return to_mode;
313+
314+ return result;
315+}
316+
317+/* Find a widening optab even if it doesn't widen as much as we want.
318+ E.g. if from_mode is HImode, and to_mode is DImode, and there is no
319+ direct HI->SI insn, then return SI->DI, if that exists.
320+ If PERMIT_NON_WIDENING is non-zero then this can be used with
321+ non-widening optabs also. */
322+
323+enum insn_code
324+find_widening_optab_handler_and_mode (optab op, enum machine_mode to_mode,
325+ enum machine_mode from_mode,
326+ int permit_non_widening,
327+ enum machine_mode *found_mode)
328+{
329+ for (; (permit_non_widening || from_mode != to_mode)
330+ && GET_MODE_SIZE (from_mode) <= GET_MODE_SIZE (to_mode)
331+ && from_mode != VOIDmode;
332+ from_mode = GET_MODE_WIDER_MODE (from_mode))
333+ {
334+ enum insn_code handler = widening_optab_handler (op, to_mode,
335+ from_mode);
336+
337+ if (handler != CODE_FOR_nothing)
338+ {
339+ if (found_mode)
340+ *found_mode = from_mode;
341+ return handler;
342+ }
343+ }
344+
345+ return CODE_FOR_nothing;
346+}
347+
348 /* Widen OP to MODE and return the rtx for the widened operand. UNSIGNEDP
349 says whether OP is signed or unsigned. NO_EXTEND is nonzero if we need
350 not actually do a sign-extend or zero-extend, but can leave the
351@@ -517,8 +572,9 @@
352 optab_for_tree_code (ops->code, TREE_TYPE (oprnd0), optab_default);
353 if (ops->code == WIDEN_MULT_PLUS_EXPR
354 || ops->code == WIDEN_MULT_MINUS_EXPR)
355- icode = (int) optab_handler (widen_pattern_optab,
356- TYPE_MODE (TREE_TYPE (ops->op2)));
357+ icode = (int) find_widening_optab_handler (widen_pattern_optab,
358+ TYPE_MODE (TREE_TYPE (ops->op2)),
359+ tmode0, 0);
360 else
361 icode = (int) optab_handler (widen_pattern_optab, tmode0);
362 gcc_assert (icode != CODE_FOR_nothing);
363@@ -1389,7 +1445,9 @@
364 rtx target, int unsignedp, enum optab_methods methods,
365 rtx last)
366 {
367- int icode = (int) optab_handler (binoptab, mode);
368+ enum machine_mode from_mode = widened_mode (mode, op0, op1);
369+ int icode = (int) find_widening_optab_handler (binoptab, mode,
370+ from_mode, 1);
371 enum machine_mode mode0 = insn_data[icode].operand[1].mode;
372 enum machine_mode mode1 = insn_data[icode].operand[2].mode;
373 enum machine_mode tmp_mode;
374@@ -1546,7 +1604,9 @@
375 /* If we can do it with a three-operand insn, do so. */
376
377 if (methods != OPTAB_MUST_WIDEN
378- && optab_handler (binoptab, mode) != CODE_FOR_nothing)
379+ && find_widening_optab_handler (binoptab, mode,
380+ widened_mode (mode, op0, op1), 1)
381+ != CODE_FOR_nothing)
382 {
383 temp = expand_binop_directly (mode, binoptab, op0, op1, target,
384 unsignedp, methods, last);
385@@ -1586,8 +1646,9 @@
386
387 if (binoptab == smul_optab
388 && GET_MODE_WIDER_MODE (mode) != VOIDmode
389- && (optab_handler ((unsignedp ? umul_widen_optab : smul_widen_optab),
390- GET_MODE_WIDER_MODE (mode))
391+ && (widening_optab_handler ((unsignedp ? umul_widen_optab
392+ : smul_widen_optab),
393+ GET_MODE_WIDER_MODE (mode), mode)
394 != CODE_FOR_nothing))
395 {
396 temp = expand_binop (GET_MODE_WIDER_MODE (mode),
397@@ -1618,9 +1679,11 @@
398 if (optab_handler (binoptab, wider_mode) != CODE_FOR_nothing
399 || (binoptab == smul_optab
400 && GET_MODE_WIDER_MODE (wider_mode) != VOIDmode
401- && (optab_handler ((unsignedp ? umul_widen_optab
402- : smul_widen_optab),
403- GET_MODE_WIDER_MODE (wider_mode))
404+ && (find_widening_optab_handler ((unsignedp
405+ ? umul_widen_optab
406+ : smul_widen_optab),
407+ GET_MODE_WIDER_MODE (wider_mode),
408+ mode, 0)
409 != CODE_FOR_nothing)))
410 {
411 rtx xop0 = op0, xop1 = op1;
412@@ -2043,8 +2106,8 @@
413 && optab_handler (add_optab, word_mode) != CODE_FOR_nothing)
414 {
415 rtx product = NULL_RTX;
416-
417- if (optab_handler (umul_widen_optab, mode) != CODE_FOR_nothing)
418+ if (widening_optab_handler (umul_widen_optab, mode, word_mode)
419+ != CODE_FOR_nothing)
420 {
421 product = expand_doubleword_mult (mode, op0, op1, target,
422 true, methods);
423@@ -2053,7 +2116,8 @@
424 }
425
426 if (product == NULL_RTX
427- && optab_handler (smul_widen_optab, mode) != CODE_FOR_nothing)
428+ && widening_optab_handler (smul_widen_optab, mode, word_mode)
429+ != CODE_FOR_nothing)
430 {
431 product = expand_doubleword_mult (mode, op0, op1, target,
432 false, methods);
433@@ -2144,7 +2208,8 @@
434 wider_mode != VOIDmode;
435 wider_mode = GET_MODE_WIDER_MODE (wider_mode))
436 {
437- if (optab_handler (binoptab, wider_mode) != CODE_FOR_nothing
438+ if (find_widening_optab_handler (binoptab, wider_mode, mode, 1)
439+ != CODE_FOR_nothing
440 || (methods == OPTAB_LIB
441 && optab_libfunc (binoptab, wider_mode)))
442 {
443
444=== modified file 'gcc/optabs.h'
445--- old/gcc/optabs.h 2011-05-05 15:43:06 +0000
446+++ new/gcc/optabs.h 2011-07-27 14:12:45 +0000
447@@ -42,6 +42,11 @@
448 int insn_code;
449 };
450
451+struct widening_optab_handlers
452+{
453+ struct optab_handlers handlers[NUM_MACHINE_MODES][NUM_MACHINE_MODES];
454+};
455+
456 struct optab_d
457 {
458 enum rtx_code code;
459@@ -50,6 +55,7 @@
460 void (*libcall_gen)(struct optab_d *, const char *name, char suffix,
461 enum machine_mode);
462 struct optab_handlers handlers[NUM_MACHINE_MODES];
463+ struct widening_optab_handlers *widening;
464 };
465 typedef struct optab_d * optab;
466
467@@ -799,6 +805,15 @@
468 extern void emit_unop_insn (int, rtx, rtx, enum rtx_code);
469 extern bool maybe_emit_unop_insn (int, rtx, rtx, enum rtx_code);
470
471+/* Find a widening optab even if it doesn't widen as much as we want. */
472+#define find_widening_optab_handler(A,B,C,D) \
473+ find_widening_optab_handler_and_mode (A, B, C, D, NULL)
474+extern enum insn_code find_widening_optab_handler_and_mode (optab,
475+ enum machine_mode,
476+ enum machine_mode,
477+ int,
478+ enum machine_mode *);
479+
480 /* An extra flag to control optab_for_tree_code's behavior. This is needed to
481 distinguish between machines with a vector shift that takes a scalar for the
482 shift amount vs. machines that take a vector for the shift amount. */
483@@ -874,6 +889,23 @@
484 + (int) CODE_FOR_nothing);
485 }
486
487+/* Like optab_handler, but for widening_operations that have a TO_MODE and
488+ a FROM_MODE. */
489+
490+static inline enum insn_code
491+widening_optab_handler (optab op, enum machine_mode to_mode,
492+ enum machine_mode from_mode)
493+{
494+ if (to_mode == from_mode || from_mode == VOIDmode)
495+ return optab_handler (op, to_mode);
496+
497+ if (op->widening)
498+ return (enum insn_code) (op->widening->handlers[(int) to_mode][(int) from_mode].insn_code
499+ + (int) CODE_FOR_nothing);
500+
501+ return CODE_FOR_nothing;
502+}
503+
504 /* Record that insn CODE should be used to implement mode MODE of OP. */
505
506 static inline void
507@@ -882,6 +914,26 @@
508 op->handlers[(int) mode].insn_code = (int) code - (int) CODE_FOR_nothing;
509 }
510
511+/* Like set_optab_handler, but for widening operations that have a TO_MODE
512+ and a FROM_MODE. */
513+
514+static inline void
515+set_widening_optab_handler (optab op, enum machine_mode to_mode,
516+ enum machine_mode from_mode, enum insn_code code)
517+{
518+ if (to_mode == from_mode)
519+ set_optab_handler (op, to_mode, code);
520+ else
521+ {
522+ if (op->widening == NULL)
523+ op->widening = (struct widening_optab_handlers *)
524+ xcalloc (1, sizeof (struct widening_optab_handlers));
525+
526+ op->widening->handlers[(int) to_mode][(int) from_mode].insn_code
527+ = (int) code - (int) CODE_FOR_nothing;
528+ }
529+}
530+
531 /* Return the insn used to perform conversion OP from mode FROM_MODE
532 to mode TO_MODE; return CODE_FOR_nothing if the target does not have
533 such an insn. */
534
535=== added file 'gcc/testsuite/gcc.target/arm/no-wmla-1.c'
536--- old/gcc/testsuite/gcc.target/arm/no-wmla-1.c 1970-01-01 00:00:00 +0000
537+++ new/gcc/testsuite/gcc.target/arm/no-wmla-1.c 2011-07-15 13:52:38 +0000
538@@ -0,0 +1,11 @@
539+/* { dg-do compile } */
540+/* { dg-options "-O2 -march=armv7-a" } */
541+
542+int
543+foo (int a, short b, short c)
544+{
545+ int bc = b * c;
546+ return a + (short)bc;
547+}
548+
549+/* { dg-final { scan-assembler "mul" } } */
550
551=== added file 'gcc/testsuite/gcc.target/arm/wmul-10.c'
552--- old/gcc/testsuite/gcc.target/arm/wmul-10.c 1970-01-01 00:00:00 +0000
553+++ new/gcc/testsuite/gcc.target/arm/wmul-10.c 2011-07-18 12:56:20 +0000
554@@ -0,0 +1,10 @@
555+/* { dg-do compile } */
556+/* { dg-options "-O2 -march=armv7-a" } */
557+
558+unsigned long long
559+foo (unsigned short a, unsigned short *b, unsigned short *c)
560+{
561+ return (unsigned)a + (unsigned long long)*b * (unsigned long long)*c;
562+}
563+
564+/* { dg-final { scan-assembler "umlal" } } */
565
566=== added file 'gcc/testsuite/gcc.target/arm/wmul-11.c'
567--- old/gcc/testsuite/gcc.target/arm/wmul-11.c 1970-01-01 00:00:00 +0000
568+++ new/gcc/testsuite/gcc.target/arm/wmul-11.c 2011-07-22 15:46:42 +0000
569@@ -0,0 +1,10 @@
570+/* { dg-do compile } */
571+/* { dg-options "-O2 -march=armv7-a" } */
572+
573+long long
574+foo (int *b)
575+{
576+ return 10 * (long long)*b;
577+}
578+
579+/* { dg-final { scan-assembler "smull" } } */
580
581=== added file 'gcc/testsuite/gcc.target/arm/wmul-12.c'
582--- old/gcc/testsuite/gcc.target/arm/wmul-12.c 1970-01-01 00:00:00 +0000
583+++ new/gcc/testsuite/gcc.target/arm/wmul-12.c 2011-07-22 15:46:42 +0000
584@@ -0,0 +1,11 @@
585+/* { dg-do compile } */
586+/* { dg-options "-O2 -march=armv7-a" } */
587+
588+long long
589+foo (int *b, int *c)
590+{
591+ int tmp = *b * *c;
592+ return 10 + (long long)tmp;
593+}
594+
595+/* { dg-final { scan-assembler "smlal" } } */
596
597=== added file 'gcc/testsuite/gcc.target/arm/wmul-13.c'
598--- old/gcc/testsuite/gcc.target/arm/wmul-13.c 1970-01-01 00:00:00 +0000
599+++ new/gcc/testsuite/gcc.target/arm/wmul-13.c 2011-07-22 15:46:42 +0000
600@@ -0,0 +1,10 @@
601+/* { dg-do compile } */
602+/* { dg-options "-O2 -march=armv7-a" } */
603+
604+long long
605+foo (int *a, int *b)
606+{
607+ return *a + (long long)*b * 10;
608+}
609+
610+/* { dg-final { scan-assembler "smlal" } } */
611
612=== added file 'gcc/testsuite/gcc.target/arm/wmul-5.c'
613--- old/gcc/testsuite/gcc.target/arm/wmul-5.c 1970-01-01 00:00:00 +0000
614+++ new/gcc/testsuite/gcc.target/arm/wmul-5.c 2011-07-15 13:52:38 +0000
615@@ -0,0 +1,10 @@
616+/* { dg-do compile } */
617+/* { dg-options "-O2 -march=armv7-a" } */
618+
619+long long
620+foo (long long a, char *b, char *c)
621+{
622+ return a + *b * *c;
623+}
624+
625+/* { dg-final { scan-assembler "umlal" } } */
626
627=== added file 'gcc/testsuite/gcc.target/arm/wmul-6.c'
628--- old/gcc/testsuite/gcc.target/arm/wmul-6.c 1970-01-01 00:00:00 +0000
629+++ new/gcc/testsuite/gcc.target/arm/wmul-6.c 2011-07-15 13:59:11 +0000
630@@ -0,0 +1,10 @@
631+/* { dg-do compile } */
632+/* { dg-options "-O2 -march=armv7-a" } */
633+
634+long long
635+foo (long long a, unsigned char *b, signed char *c)
636+{
637+ return a + (long long)*b * (long long)*c;
638+}
639+
640+/* { dg-final { scan-assembler "smlal" } } */
641
642=== added file 'gcc/testsuite/gcc.target/arm/wmul-7.c'
643--- old/gcc/testsuite/gcc.target/arm/wmul-7.c 1970-01-01 00:00:00 +0000
644+++ new/gcc/testsuite/gcc.target/arm/wmul-7.c 2011-07-15 14:11:23 +0000
645@@ -0,0 +1,10 @@
646+/* { dg-do compile } */
647+/* { dg-options "-O2 -march=armv7-a" } */
648+
649+unsigned long long
650+foo (unsigned long long a, unsigned char *b, unsigned short *c)
651+{
652+ return a + *b * *c;
653+}
654+
655+/* { dg-final { scan-assembler "umlal" } } */
656
657=== added file 'gcc/testsuite/gcc.target/arm/wmul-8.c'
658--- old/gcc/testsuite/gcc.target/arm/wmul-8.c 1970-01-01 00:00:00 +0000
659+++ new/gcc/testsuite/gcc.target/arm/wmul-8.c 2011-07-15 14:16:54 +0000
660@@ -0,0 +1,10 @@
661+/* { dg-do compile } */
662+/* { dg-options "-O2 -march=armv7-a" } */
663+
664+long long
665+foo (long long a, int *b, int *c)
666+{
667+ return a + *b * *c;
668+}
669+
670+/* { dg-final { scan-assembler "smlal" } } */
671
672=== added file 'gcc/testsuite/gcc.target/arm/wmul-9.c'
673--- old/gcc/testsuite/gcc.target/arm/wmul-9.c 1970-01-01 00:00:00 +0000
674+++ new/gcc/testsuite/gcc.target/arm/wmul-9.c 2011-07-15 14:22:39 +0000
675@@ -0,0 +1,10 @@
676+/* { dg-do compile } */
677+/* { dg-options "-O2 -march=armv7-a" } */
678+
679+long long
680+foo (long long a, short *b, char *c)
681+{
682+ return a + *b * *c;
683+}
684+
685+/* { dg-final { scan-assembler "smlalbb" } } */
686
687=== added file 'gcc/testsuite/gcc.target/arm/wmul-bitfield-1.c'
688--- old/gcc/testsuite/gcc.target/arm/wmul-bitfield-1.c 1970-01-01 00:00:00 +0000
689+++ new/gcc/testsuite/gcc.target/arm/wmul-bitfield-1.c 2011-07-15 13:44:50 +0000
690@@ -0,0 +1,17 @@
691+/* { dg-do compile } */
692+/* { dg-options "-O2 -march=armv7-a" } */
693+
694+struct bf
695+{
696+ int a : 3;
697+ int b : 15;
698+ int c : 3;
699+};
700+
701+long long
702+foo (long long a, struct bf b, struct bf c)
703+{
704+ return a + b.b * c.b;
705+}
706+
707+/* { dg-final { scan-assembler "smlalbb" } } */
708
709=== added file 'gcc/testsuite/gcc.target/arm/wmul-bitfield-2.c'
710--- old/gcc/testsuite/gcc.target/arm/wmul-bitfield-2.c 1970-01-01 00:00:00 +0000
711+++ new/gcc/testsuite/gcc.target/arm/wmul-bitfield-2.c 2011-07-15 14:22:39 +0000
712@@ -0,0 +1,17 @@
713+/* { dg-do compile } */
714+/* { dg-options "-O2 -march=armv7-a" } */
715+
716+struct bf
717+{
718+ int a : 3;
719+ unsigned int b : 15;
720+ int c : 3;
721+};
722+
723+long long
724+foo (long long a, struct bf b, struct bf c)
725+{
726+ return a + b.b * c.c;
727+}
728+
729+/* { dg-final { scan-assembler "smlalbb" } } */
730
731=== modified file 'gcc/tree-cfg.c'
732--- old/gcc/tree-cfg.c 2011-07-01 09:19:21 +0000
733+++ new/gcc/tree-cfg.c 2011-07-15 13:44:50 +0000
734@@ -3574,7 +3574,7 @@
735 case WIDEN_MULT_EXPR:
736 if (TREE_CODE (lhs_type) != INTEGER_TYPE)
737 return true;
738- return ((2 * TYPE_PRECISION (rhs1_type) != TYPE_PRECISION (lhs_type))
739+ return ((2 * TYPE_PRECISION (rhs1_type) > TYPE_PRECISION (lhs_type))
740 || (TYPE_PRECISION (rhs1_type) != TYPE_PRECISION (rhs2_type)));
741
742 case WIDEN_SUM_EXPR:
743@@ -3667,7 +3667,7 @@
744 && !FIXED_POINT_TYPE_P (rhs1_type))
745 || !useless_type_conversion_p (rhs1_type, rhs2_type)
746 || !useless_type_conversion_p (lhs_type, rhs3_type)
747- || 2 * TYPE_PRECISION (rhs1_type) != TYPE_PRECISION (lhs_type)
748+ || 2 * TYPE_PRECISION (rhs1_type) > TYPE_PRECISION (lhs_type)
749 || TYPE_PRECISION (rhs1_type) != TYPE_PRECISION (rhs2_type))
750 {
751 error ("type mismatch in widening multiply-accumulate expression");
752
753=== modified file 'gcc/tree-ssa-math-opts.c'
754--- old/gcc/tree-ssa-math-opts.c 2011-03-11 16:36:16 +0000
755+++ new/gcc/tree-ssa-math-opts.c 2011-08-09 10:26:48 +0000
756@@ -1266,39 +1266,67 @@
757 }
758 };
759
760-/* Return true if RHS is a suitable operand for a widening multiplication.
761+/* Build a gimple assignment to cast VAL to TARGET. Insert the statement
762+ prior to GSI's current position, and return the fresh SSA name. */
763+
764+static tree
765+build_and_insert_cast (gimple_stmt_iterator *gsi, location_t loc,
766+ tree target, tree val)
767+{
768+ tree result = make_ssa_name (target, NULL);
769+ gimple stmt = gimple_build_assign_with_ops (CONVERT_EXPR, result, val, NULL);
770+ gimple_set_location (stmt, loc);
771+ gsi_insert_before (gsi, stmt, GSI_SAME_STMT);
772+ return result;
773+}
774+
775+/* Return true if RHS is a suitable operand for a widening multiplication,
776+ assuming a target type of TYPE.
777 There are two cases:
778
779- - RHS makes some value twice as wide. Store that value in *NEW_RHS_OUT
780- if so, and store its type in *TYPE_OUT.
781+ - RHS makes some value at least twice as wide. Store that value
782+ in *NEW_RHS_OUT if so, and store its type in *TYPE_OUT.
783
784 - RHS is an integer constant. Store that value in *NEW_RHS_OUT if so,
785 but leave *TYPE_OUT untouched. */
786
787 static bool
788-is_widening_mult_rhs_p (tree rhs, tree *type_out, tree *new_rhs_out)
789+is_widening_mult_rhs_p (tree type, tree rhs, tree *type_out,
790+ tree *new_rhs_out)
791 {
792 gimple stmt;
793- tree type, type1, rhs1;
794+ tree type1, rhs1;
795 enum tree_code rhs_code;
796
797 if (TREE_CODE (rhs) == SSA_NAME)
798 {
799- type = TREE_TYPE (rhs);
800 stmt = SSA_NAME_DEF_STMT (rhs);
801- if (!is_gimple_assign (stmt))
802- return false;
803-
804- rhs_code = gimple_assign_rhs_code (stmt);
805- if (TREE_CODE (type) == INTEGER_TYPE
806- ? !CONVERT_EXPR_CODE_P (rhs_code)
807- : rhs_code != FIXED_CONVERT_EXPR)
808- return false;
809-
810- rhs1 = gimple_assign_rhs1 (stmt);
811+ if (is_gimple_assign (stmt))
812+ {
813+ rhs_code = gimple_assign_rhs_code (stmt);
814+ if (TREE_CODE (type) == INTEGER_TYPE
815+ ? !CONVERT_EXPR_CODE_P (rhs_code)
816+ : rhs_code != FIXED_CONVERT_EXPR)
817+ rhs1 = rhs;
818+ else
819+ {
820+ rhs1 = gimple_assign_rhs1 (stmt);
821+
822+ if (TREE_CODE (rhs1) == INTEGER_CST)
823+ {
824+ *new_rhs_out = rhs1;
825+ *type_out = NULL;
826+ return true;
827+ }
828+ }
829+ }
830+ else
831+ rhs1 = rhs;
832+
833 type1 = TREE_TYPE (rhs1);
834+
835 if (TREE_CODE (type1) != TREE_CODE (type)
836- || TYPE_PRECISION (type1) * 2 != TYPE_PRECISION (type))
837+ || TYPE_PRECISION (type1) * 2 > TYPE_PRECISION (type))
838 return false;
839
840 *new_rhs_out = rhs1;
841@@ -1316,28 +1344,27 @@
842 return false;
843 }
844
845-/* Return true if STMT performs a widening multiplication. If so,
846- store the unwidened types of the operands in *TYPE1_OUT and *TYPE2_OUT
847- respectively. Also fill *RHS1_OUT and *RHS2_OUT such that converting
848- those operands to types *TYPE1_OUT and *TYPE2_OUT would give the
849- operands of the multiplication. */
850+/* Return true if STMT performs a widening multiplication, assuming the
851+ output type is TYPE. If so, store the unwidened types of the operands
852+ in *TYPE1_OUT and *TYPE2_OUT respectively. Also fill *RHS1_OUT and
853+ *RHS2_OUT such that converting those operands to types *TYPE1_OUT
854+ and *TYPE2_OUT would give the operands of the multiplication. */
855
856 static bool
857-is_widening_mult_p (gimple stmt,
858+is_widening_mult_p (tree type, gimple stmt,
859 tree *type1_out, tree *rhs1_out,
860 tree *type2_out, tree *rhs2_out)
861 {
862- tree type;
863-
864- type = TREE_TYPE (gimple_assign_lhs (stmt));
865 if (TREE_CODE (type) != INTEGER_TYPE
866 && TREE_CODE (type) != FIXED_POINT_TYPE)
867 return false;
868
869- if (!is_widening_mult_rhs_p (gimple_assign_rhs1 (stmt), type1_out, rhs1_out))
870+ if (!is_widening_mult_rhs_p (type, gimple_assign_rhs1 (stmt), type1_out,
871+ rhs1_out))
872 return false;
873
874- if (!is_widening_mult_rhs_p (gimple_assign_rhs2 (stmt), type2_out, rhs2_out))
875+ if (!is_widening_mult_rhs_p (type, gimple_assign_rhs2 (stmt), type2_out,
876+ rhs2_out))
877 return false;
878
879 if (*type1_out == NULL)
880@@ -1354,6 +1381,18 @@
881 *type2_out = *type1_out;
882 }
883
884+ /* Ensure that the larger of the two operands comes first. */
885+ if (TYPE_PRECISION (*type1_out) < TYPE_PRECISION (*type2_out))
886+ {
887+ tree tmp;
888+ tmp = *type1_out;
889+ *type1_out = *type2_out;
890+ *type2_out = tmp;
891+ tmp = *rhs1_out;
892+ *rhs1_out = *rhs2_out;
893+ *rhs2_out = tmp;
894+ }
895+
896 return true;
897 }
898
899@@ -1362,31 +1401,100 @@
900 value is true iff we converted the statement. */
901
902 static bool
903-convert_mult_to_widen (gimple stmt)
904+convert_mult_to_widen (gimple stmt, gimple_stmt_iterator *gsi)
905 {
906- tree lhs, rhs1, rhs2, type, type1, type2;
907+ tree lhs, rhs1, rhs2, type, type1, type2, tmp = NULL;
908 enum insn_code handler;
909+ enum machine_mode to_mode, from_mode, actual_mode;
910+ optab op;
911+ int actual_precision;
912+ location_t loc = gimple_location (stmt);
913+ bool from_unsigned1, from_unsigned2;
914
915 lhs = gimple_assign_lhs (stmt);
916 type = TREE_TYPE (lhs);
917 if (TREE_CODE (type) != INTEGER_TYPE)
918 return false;
919
920- if (!is_widening_mult_p (stmt, &type1, &rhs1, &type2, &rhs2))
921+ if (!is_widening_mult_p (type, stmt, &type1, &rhs1, &type2, &rhs2))
922 return false;
923
924- if (TYPE_UNSIGNED (type1) && TYPE_UNSIGNED (type2))
925- handler = optab_handler (umul_widen_optab, TYPE_MODE (type));
926- else if (!TYPE_UNSIGNED (type1) && !TYPE_UNSIGNED (type2))
927- handler = optab_handler (smul_widen_optab, TYPE_MODE (type));
928+ to_mode = TYPE_MODE (type);
929+ from_mode = TYPE_MODE (type1);
930+ from_unsigned1 = TYPE_UNSIGNED (type1);
931+ from_unsigned2 = TYPE_UNSIGNED (type2);
932+
933+ if (from_unsigned1 && from_unsigned2)
934+ op = umul_widen_optab;
935+ else if (!from_unsigned1 && !from_unsigned2)
936+ op = smul_widen_optab;
937 else
938- handler = optab_handler (usmul_widen_optab, TYPE_MODE (type));
939+ op = usmul_widen_optab;
940+
941+ handler = find_widening_optab_handler_and_mode (op, to_mode, from_mode,
942+ 0, &actual_mode);
943
944 if (handler == CODE_FOR_nothing)
945- return false;
946-
947- gimple_assign_set_rhs1 (stmt, fold_convert (type1, rhs1));
948- gimple_assign_set_rhs2 (stmt, fold_convert (type2, rhs2));
949+ {
950+ if (op != smul_widen_optab)
951+ {
952+ /* We can use a signed multiply with unsigned types as long as
953+ there is a wider mode to use, or it is the smaller of the two
954+ types that is unsigned. Note that type1 >= type2, always. */
955+ if ((TYPE_UNSIGNED (type1)
956+ && TYPE_PRECISION (type1) == GET_MODE_PRECISION (from_mode))
957+ || (TYPE_UNSIGNED (type2)
958+ && TYPE_PRECISION (type2) == GET_MODE_PRECISION (from_mode)))
959+ {
960+ from_mode = GET_MODE_WIDER_MODE (from_mode);
961+ if (GET_MODE_SIZE (to_mode) <= GET_MODE_SIZE (from_mode))
962+ return false;
963+ }
964+
965+ op = smul_widen_optab;
966+ handler = find_widening_optab_handler_and_mode (op, to_mode,
967+ from_mode, 0,
968+ &actual_mode);
969+
970+ if (handler == CODE_FOR_nothing)
971+ return false;
972+
973+ from_unsigned1 = from_unsigned2 = false;
974+ }
975+ else
976+ return false;
977+ }
978+
979+ /* Ensure that the inputs to the handler are in the correct precison
980+ for the opcode. This will be the full mode size. */
981+ actual_precision = GET_MODE_PRECISION (actual_mode);
982+ if (actual_precision != TYPE_PRECISION (type1)
983+ || from_unsigned1 != TYPE_UNSIGNED (type1))
984+ {
985+ tmp = create_tmp_var (build_nonstandard_integer_type
986+ (actual_precision, from_unsigned1),
987+ NULL);
988+ rhs1 = build_and_insert_cast (gsi, loc, tmp, rhs1);
989+ }
990+ if (actual_precision != TYPE_PRECISION (type2)
991+ || from_unsigned2 != TYPE_UNSIGNED (type2))
992+ {
993+ /* Reuse the same type info, if possible. */
994+ if (!tmp || from_unsigned1 != from_unsigned2)
995+ tmp = create_tmp_var (build_nonstandard_integer_type
996+ (actual_precision, from_unsigned2),
997+ NULL);
998+ rhs2 = build_and_insert_cast (gsi, loc, tmp, rhs2);
999+ }
1000+
1001+ /* Handle constants. */
1002+ if (TREE_CODE (rhs1) == INTEGER_CST)
1003+ rhs1 = fold_convert (type1, rhs1);
1004+ if (TREE_CODE (rhs2) == INTEGER_CST)
1005+ rhs2 = fold_convert (type2, rhs2);
1006+
1007+ gimple_assign_set_rhs1 (stmt, rhs1);
1008+ gimple_assign_set_rhs2 (stmt, rhs2);
1009 gimple_assign_set_rhs_code (stmt, WIDEN_MULT_EXPR);
1010 update_stmt (stmt);
1011 return true;
1012@@ -1403,11 +1511,17 @@
1013 enum tree_code code)
1014 {
1015 gimple rhs1_stmt = NULL, rhs2_stmt = NULL;
1016- tree type, type1, type2;
1017+ gimple conv1_stmt = NULL, conv2_stmt = NULL, conv_stmt;
1018+ tree type, type1, type2, optype, tmp = NULL;
1019 tree lhs, rhs1, rhs2, mult_rhs1, mult_rhs2, add_rhs;
1020 enum tree_code rhs1_code = ERROR_MARK, rhs2_code = ERROR_MARK;
1021 optab this_optab;
1022 enum tree_code wmult_code;
1023+ enum insn_code handler;
1024+ enum machine_mode to_mode, from_mode, actual_mode;
1025+ location_t loc = gimple_location (stmt);
1026+ int actual_precision;
1027+ bool from_unsigned1, from_unsigned2;
1028
1029 lhs = gimple_assign_lhs (stmt);
1030 type = TREE_TYPE (lhs);
1031@@ -1429,8 +1543,6 @@
1032 if (is_gimple_assign (rhs1_stmt))
1033 rhs1_code = gimple_assign_rhs_code (rhs1_stmt);
1034 }
1035- else
1036- return false;
1037
1038 if (TREE_CODE (rhs2) == SSA_NAME)
1039 {
1040@@ -1438,57 +1550,160 @@
1041 if (is_gimple_assign (rhs2_stmt))
1042 rhs2_code = gimple_assign_rhs_code (rhs2_stmt);
1043 }
1044- else
1045- return false;
1046-
1047- if (code == PLUS_EXPR && rhs1_code == MULT_EXPR)
1048- {
1049- if (!is_widening_mult_p (rhs1_stmt, &type1, &mult_rhs1,
1050- &type2, &mult_rhs2))
1051- return false;
1052- add_rhs = rhs2;
1053- }
1054- else if (rhs2_code == MULT_EXPR)
1055- {
1056- if (!is_widening_mult_p (rhs2_stmt, &type1, &mult_rhs1,
1057- &type2, &mult_rhs2))
1058- return false;
1059- add_rhs = rhs1;
1060- }
1061- else if (code == PLUS_EXPR && rhs1_code == WIDEN_MULT_EXPR)
1062- {
1063- mult_rhs1 = gimple_assign_rhs1 (rhs1_stmt);
1064- mult_rhs2 = gimple_assign_rhs2 (rhs1_stmt);
1065- type1 = TREE_TYPE (mult_rhs1);
1066- type2 = TREE_TYPE (mult_rhs2);
1067- add_rhs = rhs2;
1068- }
1069- else if (rhs2_code == WIDEN_MULT_EXPR)
1070- {
1071- mult_rhs1 = gimple_assign_rhs1 (rhs2_stmt);
1072- mult_rhs2 = gimple_assign_rhs2 (rhs2_stmt);
1073- type1 = TREE_TYPE (mult_rhs1);
1074- type2 = TREE_TYPE (mult_rhs2);
1075- add_rhs = rhs1;
1076- }
1077- else
1078- return false;
1079-
1080- if (TYPE_UNSIGNED (type1) != TYPE_UNSIGNED (type2))
1081- return false;
1082+
1083+ /* Allow for one conversion statement between the multiply
1084+ and addition/subtraction statement. If there are more than
1085+ one conversions then we assume they would invalidate this
1086+ transformation. If that's not the case then they should have
1087+ been folded before now. */
1088+ if (CONVERT_EXPR_CODE_P (rhs1_code))
1089+ {
1090+ conv1_stmt = rhs1_stmt;
1091+ rhs1 = gimple_assign_rhs1 (rhs1_stmt);
1092+ if (TREE_CODE (rhs1) == SSA_NAME)
1093+ {
1094+ rhs1_stmt = SSA_NAME_DEF_STMT (rhs1);
1095+ if (is_gimple_assign (rhs1_stmt))
1096+ rhs1_code = gimple_assign_rhs_code (rhs1_stmt);
1097+ }
1098+ else
1099+ return false;
1100+ }
1101+ if (CONVERT_EXPR_CODE_P (rhs2_code))
1102+ {
1103+ conv2_stmt = rhs2_stmt;
1104+ rhs2 = gimple_assign_rhs1 (rhs2_stmt);
1105+ if (TREE_CODE (rhs2) == SSA_NAME)
1106+ {
1107+ rhs2_stmt = SSA_NAME_DEF_STMT (rhs2);
1108+ if (is_gimple_assign (rhs2_stmt))
1109+ rhs2_code = gimple_assign_rhs_code (rhs2_stmt);
1110+ }
1111+ else
1112+ return false;
1113+ }
1114+
1115+ /* If code is WIDEN_MULT_EXPR then it would seem unnecessary to call
1116+ is_widening_mult_p, but we still need the rhs returns.
1117+
1118+ It might also appear that it would be sufficient to use the existing
1119+ operands of the widening multiply, but that would limit the choice of
1120+ multiply-and-accumulate instructions. */
1121+ if (code == PLUS_EXPR
1122+ && (rhs1_code == MULT_EXPR || rhs1_code == WIDEN_MULT_EXPR))
1123+ {
1124+ if (!is_widening_mult_p (type, rhs1_stmt, &type1, &mult_rhs1,
1125+ &type2, &mult_rhs2))
1126+ return false;
1127+ add_rhs = rhs2;
1128+ conv_stmt = conv1_stmt;
1129+ }
1130+ else if (rhs2_code == MULT_EXPR || rhs2_code == WIDEN_MULT_EXPR)
1131+ {
1132+ if (!is_widening_mult_p (type, rhs2_stmt, &type1, &mult_rhs1,
1133+ &type2, &mult_rhs2))
1134+ return false;
1135+ add_rhs = rhs1;
1136+ conv_stmt = conv2_stmt;
1137+ }
1138+ else
1139+ return false;
1140+
1141+ to_mode = TYPE_MODE (type);
1142+ from_mode = TYPE_MODE (type1);
1143+ from_unsigned1 = TYPE_UNSIGNED (type1);
1144+ from_unsigned2 = TYPE_UNSIGNED (type2);
1145+
1146+ /* There's no such thing as a mixed sign madd yet, so use a wider mode. */
1147+ if (from_unsigned1 != from_unsigned2)
1148+ {
1149+ /* We can use a signed multiply with unsigned types as long as
1150+ there is a wider mode to use, or it is the smaller of the two
1151+ types that is unsigned. Note that type1 >= type2, always. */
1152+ if ((from_unsigned1
1153+ && TYPE_PRECISION (type1) == GET_MODE_PRECISION (from_mode))
1154+ || (from_unsigned2
1155+ && TYPE_PRECISION (type2) == GET_MODE_PRECISION (from_mode)))
1156+ {
1157+ from_mode = GET_MODE_WIDER_MODE (from_mode);
1158+ if (GET_MODE_SIZE (from_mode) >= GET_MODE_SIZE (to_mode))
1159+ return false;
1160+ }
1161+
1162+ from_unsigned1 = from_unsigned2 = false;
1163+ }
1164+
1165+ /* If there was a conversion between the multiply and addition
1166+ then we need to make sure it fits a multiply-and-accumulate.
1167+ The should be a single mode change which does not change the
1168+ value. */
1169+ if (conv_stmt)
1170+ {
1171+ /* We use the original, unmodified data types for this. */
1172+ tree from_type = TREE_TYPE (gimple_assign_rhs1 (conv_stmt));
1173+ tree to_type = TREE_TYPE (gimple_assign_lhs (conv_stmt));
1174+ int data_size = TYPE_PRECISION (type1) + TYPE_PRECISION (type2);
1175+ bool is_unsigned = TYPE_UNSIGNED (type1) && TYPE_UNSIGNED (type2);
1176+
1177+ if (TYPE_PRECISION (from_type) > TYPE_PRECISION (to_type))
1178+ {
1179+ /* Conversion is a truncate. */
1180+ if (TYPE_PRECISION (to_type) < data_size)
1181+ return false;
1182+ }
1183+ else if (TYPE_PRECISION (from_type) < TYPE_PRECISION (to_type))
1184+ {
1185+ /* Conversion is an extend. Check it's the right sort. */
1186+ if (TYPE_UNSIGNED (from_type) != is_unsigned
1187+ && !(is_unsigned && TYPE_PRECISION (from_type) > data_size))
1188+ return false;
1189+ }
1190+ /* else convert is a no-op for our purposes. */
1191+ }
1192
1193 /* Verify that the machine can perform a widening multiply
1194 accumulate in this mode/signedness combination, otherwise
1195 this transformation is likely to pessimize code. */
1196- this_optab = optab_for_tree_code (wmult_code, type1, optab_default);
1197- if (optab_handler (this_optab, TYPE_MODE (type)) == CODE_FOR_nothing)
1198+ optype = build_nonstandard_integer_type (from_mode, from_unsigned1);
1199+ this_optab = optab_for_tree_code (wmult_code, optype, optab_default);
1200+ handler = find_widening_optab_handler_and_mode (this_optab, to_mode,
1201+ from_mode, 0, &actual_mode);
1202+
1203+ if (handler == CODE_FOR_nothing)
1204 return false;
1205
1206- /* ??? May need some type verification here? */
1207-
1208- gimple_assign_set_rhs_with_ops_1 (gsi, wmult_code,
1209- fold_convert (type1, mult_rhs1),
1210- fold_convert (type2, mult_rhs2),
1211+ /* Ensure that the inputs to the handler are in the correct precison
1212+ for the opcode. This will be the full mode size. */
1213+ actual_precision = GET_MODE_PRECISION (actual_mode);
1214+ if (actual_precision != TYPE_PRECISION (type1)
1215+ || from_unsigned1 != TYPE_UNSIGNED (type1))
1216+ {
1217+ tmp = create_tmp_var (build_nonstandard_integer_type
1218+ (actual_precision, from_unsigned1),
1219+ NULL);
1220+ mult_rhs1 = build_and_insert_cast (gsi, loc, tmp, mult_rhs1);
1221+ }
1222+ if (actual_precision != TYPE_PRECISION (type2)
1223+ || from_unsigned2 != TYPE_UNSIGNED (type2))
1224+ {
1225+ if (!tmp || from_unsigned1 != from_unsigned2)
1226+ tmp = create_tmp_var (build_nonstandard_integer_type
1227+ (actual_precision, from_unsigned2),
1228+ NULL);
1229+ mult_rhs2 = build_and_insert_cast (gsi, loc, tmp, mult_rhs2);
1230+ }
1231+
1232+ if (!useless_type_conversion_p (type, TREE_TYPE (add_rhs)))
1233+ add_rhs = build_and_insert_cast (gsi, loc, create_tmp_var (type, NULL),
1234+ add_rhs);
1235+
1236+ /* Handle constants. */
1237+ if (TREE_CODE (mult_rhs1) == INTEGER_CST)
1238+ rhs1 = fold_convert (type1, mult_rhs1);
1239+ if (TREE_CODE (mult_rhs2) == INTEGER_CST)
1240+ rhs2 = fold_convert (type2, mult_rhs2);
1241+
1242+ gimple_assign_set_rhs_with_ops_1 (gsi, wmult_code, mult_rhs1, mult_rhs2,
1243 add_rhs);
1244 update_stmt (gsi_stmt (*gsi));
1245 return true;
1246@@ -1696,7 +1911,7 @@
1247 switch (code)
1248 {
1249 case MULT_EXPR:
1250- if (!convert_mult_to_widen (stmt)
1251+ if (!convert_mult_to_widen (stmt, &gsi)
1252 && convert_mult_to_fma (stmt,
1253 gimple_assign_rhs1 (stmt),
1254 gimple_assign_rhs2 (stmt)))
1255