diff options
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.patch | 1255 |
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 @@ | |||
1 | 2011-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 | |||