Merge lp:~ams-codesourcery/gcc-linaro/widening-multiplies-4.6 into lp:gcc-linaro/4.6

Proposed by Andrew Stubbs
Status: Superseded
Proposed branch: lp:~ams-codesourcery/gcc-linaro/widening-multiplies-4.6
Merge into: lp:gcc-linaro/4.6
Diff against target: 1157 lines (+645/-134) (has conflicts)
17 files modified
ChangeLog.linaro (+105/-0)
gcc/config/arm/arm.md (+1/-1)
gcc/expr.c (+14/-15)
gcc/genopinit.c (+24/-20)
gcc/optabs.c (+56/-15)
gcc/optabs.h (+52/-0)
gcc/testsuite/gcc.target/arm/no-wmla-1.c (+11/-0)
gcc/testsuite/gcc.target/arm/wmul-10.c (+10/-0)
gcc/testsuite/gcc.target/arm/wmul-5.c (+10/-0)
gcc/testsuite/gcc.target/arm/wmul-6.c (+10/-0)
gcc/testsuite/gcc.target/arm/wmul-7.c (+10/-0)
gcc/testsuite/gcc.target/arm/wmul-8.c (+10/-0)
gcc/testsuite/gcc.target/arm/wmul-9.c (+10/-0)
gcc/testsuite/gcc.target/arm/wmul-bitfield-1.c (+17/-0)
gcc/testsuite/gcc.target/arm/wmul-bitfield-2.c (+17/-0)
gcc/tree-cfg.c (+2/-2)
gcc/tree-ssa-math-opts.c (+286/-81)
Text conflict in ChangeLog.linaro
To merge this branch: bzr merge lp:~ams-codesourcery/gcc-linaro/widening-multiplies-4.6
Reviewer Review Type Date Requested Status
Michael Hope Needs Fixing
Review via email: mp+68093@code.launchpad.net

This proposal has been superseded by a proposal from 2011-07-19.

Description of the change

Widening multiplies optimizations.

The first commit is not approved yet, but the rest are reviewed upstream, and read to commit.

http://<email address hidden>/msg08720.html

To post a comment you must log in.
Revision history for this message
Linaro Toolchain Builder (cbuild) wrote :

cbuild has taken a snapshot of this branch at r106781 and queued it for build.

The snapshot is available at:
 http://ex.seabright.co.nz/snapshots/gcc-linaro-4.6+bzr106781~ams-codesourcery~widening-multiplies-4.6.tar.xdelta3.xz

and will be built on the following builders:
 a9-builder armv5-builder i686 x86_64

You can track the build queue at:
 http://ex.seabright.co.nz/helpers/scheduler

cbuild-snapshot: gcc-linaro-4.6+bzr106781~ams-codesourcery~widening-multiplies-4.6
cbuild-ancestor: lp:gcc-linaro/4.6+bzr106774
cbuild-state: check

Revision history for this message
Michael Hope (michaelh1) wrote :

cbuild had trouble building this on <proposals.Build instance at 0x2b85680>.

See the *failed.txt logs under the build results at:
 http://ex.seabright.co.nz/build/gcc-linaro-4.6+bzr106781~ams-codesourcery~widening-multiplies-4.6/logs/armv7l-natty-cbuild158-ursa3-armv5r2

The test suite results were not checked.

cbuild-checked: armv7l-natty-cbuild158-ursa3-armv5r2

review: Needs Fixing
Revision history for this message
Michael Hope (michaelh1) wrote :

cbuild had trouble building this on <proposals.Build instance at 0x2141ea8>.

See the *failed.txt logs under the build results at:
 http://ex.seabright.co.nz/build/gcc-linaro-4.6+bzr106781~ams-codesourcery~widening-multiplies-4.6/logs/armv7l-natty-cbuild158-ursa4-cortexa9r1

The test suite results were not checked.

cbuild-checked: armv7l-natty-cbuild158-ursa4-cortexa9r1

review: Needs Fixing
Revision history for this message
Michael Hope (michaelh1) wrote :

cbuild had trouble building this on <proposals.Build instance at 0x7fe8f501a050>.

See the *failed.txt logs under the build results at:
 http://ex.seabright.co.nz/build/gcc-linaro-4.6+bzr106781~ams-codesourcery~widening-multiplies-4.6/logs/i686-natty-cbuild158-oort2-i686r1

The test suite results were not checked.

cbuild-checked: i686-natty-cbuild158-oort2-i686r1

review: Needs Fixing
Revision history for this message
Michael Hope (michaelh1) wrote :

cbuild had trouble building this on <proposals.Build instance at 0x7fe8f5028ab8>.

See the *failed.txt logs under the build results at:
 http://ex.seabright.co.nz/build/gcc-linaro-4.6+bzr106781~ams-codesourcery~widening-multiplies-4.6/logs/x86_64-natty-cbuild158-oort1-x86_64r1

The test suite results were not checked.

cbuild-checked: x86_64-natty-cbuild158-oort1-x86_64r1

review: Needs Fixing

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'ChangeLog.linaro'
--- ChangeLog.linaro 2011-07-14 22:14:45 +0000
+++ ChangeLog.linaro 2011-07-18 13:34:25 +0000
@@ -1,3 +1,4 @@
1<<<<<<< TREE
12011-07-15 Michael Hope <michael.hope@linaro.org>22011-07-15 Michael Hope <michael.hope@linaro.org>
23
3 Backport from mainline r1745404 Backport from mainline r174540
@@ -71,6 +72,110 @@
7172
72 * gcc.c-torture/compile/20110401-1.c: New test.73 * gcc.c-torture/compile/20110401-1.c: New test.
7374
75=======
762011-07-15 Andrew Stubbs <ams@codesourcery.com>
77
78 Backport from patches proposed for 4.7:
79
80 2011-06-24 Andrew Stubbs <ams@codesourcery.com>
81
82 gcc/
83 * tree-ssa-math-opts.c (convert_mult_to_widen): Better handle
84 unsigned inputs of different modes.
85 (convert_plusminus_to_widen): Likewise.
86
87 gcc/testsuite/
88 * gcc.target/arm/wmul-9.c: New file.
89 * gcc.target/arm/wmul-bitfield-2.c: New file.
90
91 2011-07-14 Andrew Stubbs <ams@codesourcery.com>
92
93 gcc/
94 * tree-ssa-math-opts.c (is_widening_mult_rhs_p): Add new argument
95 'type'.
96 Use 'type' from caller, not inferred from 'rhs'.
97 Don't reject non-conversion statements. Do return lhs in this case.
98 (is_widening_mult_p): Add new argument 'type'.
99 Use 'type' from caller, not inferred from 'stmt'.
100 Pass type to is_widening_mult_rhs_p.
101 (convert_mult_to_widen): Pass type to is_widening_mult_p.
102 (convert_plusminus_to_widen): Likewise.
103
104 gcc/testsuite/
105 * gcc.target/arm/wmul-8.c: New file.
106
107 2011-07-14 Andrew Stubbs <ams@codesourcery.com>
108
109 gcc/
110 * tree-ssa-math-opts.c (is_widening_mult_p): Remove FIXME.
111 Ensure the the larger type is the first operand.
112
113 gcc/testsuite/
114 * gcc.target/arm/wmul-7.c: New file.
115
116 2011-07-14 Andrew Stubbs <ams@codesourcery.com>
117
118 gcc/
119 * tree-ssa-math-opts.c (convert_mult_to_widen): Convert
120 unsupported unsigned multiplies to signed.
121 (convert_plusminus_to_widen): Likewise.
122
123 gcc/testsuite/
124 * gcc.target/arm/wmul-6.c: New file.
125
126 2011-07-14 Andrew Stubbs <ams@codesourcery.com>
127
128 gcc/
129 * tree-ssa-math-opts.c (convert_plusminus_to_widen): Permit a single
130 conversion statement separating multiply-and-accumulate.
131
132 gcc/testsuite/
133 * gcc.target/arm/wmul-5.c: New file.
134 * gcc.target/arm/no-wmla-1.c: New file.
135
136 2011-07-14 Andrew Stubbs <ams@codesourcery.com>
137
138 gcc/
139 * config/arm/arm.md (maddhidi4): Remove '*' from name.
140 * expr.c (expand_expr_real_2): Use find_widening_optab_handler.
141 * optabs.c (find_widening_optab_handler_and_mode): New function.
142 (expand_widen_pattern_expr): Use find_widening_optab_handler.
143 (expand_binop_directly): Likewise.
144 (expand_binop): Likewise.
145 * optabs.h (find_widening_optab_handler): New macro define.
146 (find_widening_optab_handler_and_mode): New prototype.
147 * tree-cfg.c (verify_gimple_assign_binary): Adjust WIDEN_MULT_EXPR
148 type precision rules.
149 (verify_gimple_assign_ternary): Likewise for WIDEN_MULT_PLUS_EXPR.
150 * tree-ssa-math-opts.c (build_and_insert_cast): New function.
151 (is_widening_mult_rhs_p): Allow widening by more than one mode.
152 Explicitly disallow mis-matched input types.
153 (convert_mult_to_widen): Use find_widening_optab_handler, and cast
154 input types to fit the new handler.
155 (convert_plusminus_to_widen): Likewise.
156
157 gcc/testsuite/
158 * gcc.target/arm/wmul-bitfield-1.c: New file.
159
160
161 2011-07-09 Andrew Stubbs <ams@codesourcery.com>
162
163 gcc/
164 * expr.c (expand_expr_real_2): Use widening_optab_handler.
165 * genopinit.c (optabs): Use set_widening_optab_handler for $N.
166 (gen_insn): $N now means $a must be wider than $b, not consecutive.
167 * optabs.c (expand_widen_pattern_expr): Use widening_optab_handler.
168 (expand_binop_directly): Likewise.
169 (expand_binop): Likewise.
170 * optabs.h (widening_optab_handlers): New struct.
171 (optab_d): New member, 'widening'.
172 (widening_optab_handler): New function.
173 (set_widening_optab_handler): New function.
174 * tree-ssa-math-opts.c (convert_mult_to_widen): Use
175 widening_optab_handler.
176 (convert_plusminus_to_widen): Likewise.
177
178>>>>>>> MERGE-SOURCE
742011-07-13 Richard Sandiford <richard.sandiford@linaro.org>1792011-07-13 Richard Sandiford <richard.sandiford@linaro.org>
75180
76 Backport from mainline:181 Backport from mainline:
77182
=== modified file 'gcc/config/arm/arm.md'
--- gcc/config/arm/arm.md 2011-06-28 12:02:27 +0000
+++ gcc/config/arm/arm.md 2011-07-18 13:34:25 +0000
@@ -1839,7 +1839,7 @@
1839 (set_attr "predicable" "yes")]1839 (set_attr "predicable" "yes")]
1840)1840)
18411841
1842(define_insn "*maddhidi4"1842(define_insn "maddhidi4"
1843 [(set (match_operand:DI 0 "s_register_operand" "=r")1843 [(set (match_operand:DI 0 "s_register_operand" "=r")
1844 (plus:DI1844 (plus:DI
1845 (mult:DI (sign_extend:DI1845 (mult:DI (sign_extend:DI
18461846
=== modified file 'gcc/expr.c'
--- gcc/expr.c 2011-06-02 12:12:00 +0000
+++ gcc/expr.c 2011-07-18 13:34:25 +0000
@@ -7658,18 +7658,16 @@
7658 {7658 {
7659 enum machine_mode innermode = TYPE_MODE (TREE_TYPE (treeop0));7659 enum machine_mode innermode = TYPE_MODE (TREE_TYPE (treeop0));
7660 this_optab = usmul_widen_optab;7660 this_optab = usmul_widen_optab;
7661 if (mode == GET_MODE_2XWIDER_MODE (innermode))7661 if (find_widening_optab_handler (this_optab, mode, innermode, 0)
7662 != CODE_FOR_nothing)
7662 {7663 {
7663 if (optab_handler (this_optab, mode) != CODE_FOR_nothing)7664 if (TYPE_UNSIGNED (TREE_TYPE (treeop0)))
7664 {7665 expand_operands (treeop0, treeop1, NULL_RTX, &op0, &op1,
7665 if (TYPE_UNSIGNED (TREE_TYPE (treeop0)))7666 EXPAND_NORMAL);
7666 expand_operands (treeop0, treeop1, NULL_RTX, &op0, &op1,7667 else
7667 EXPAND_NORMAL);7668 expand_operands (treeop0, treeop1, NULL_RTX, &op1, &op0,
7668 else7669 EXPAND_NORMAL);
7669 expand_operands (treeop0, treeop1, NULL_RTX, &op1, &op0,7670 goto binop3;
7670 EXPAND_NORMAL);
7671 goto binop3;
7672 }
7673 }7671 }
7674 }7672 }
7675 /* Check for a multiplication with matching signedness. */7673 /* Check for a multiplication with matching signedness. */
@@ -7684,10 +7682,10 @@
7684 optab other_optab = zextend_p ? smul_widen_optab : umul_widen_optab;7682 optab other_optab = zextend_p ? smul_widen_optab : umul_widen_optab;
7685 this_optab = zextend_p ? umul_widen_optab : smul_widen_optab;7683 this_optab = zextend_p ? umul_widen_optab : smul_widen_optab;
76867684
7687 if (mode == GET_MODE_2XWIDER_MODE (innermode)7685 if (TREE_CODE (treeop0) != INTEGER_CST)
7688 && TREE_CODE (treeop0) != INTEGER_CST)
7689 {7686 {
7690 if (optab_handler (this_optab, mode) != CODE_FOR_nothing)7687 if (find_widening_optab_handler (this_optab, mode, innermode, 0)
7688 != CODE_FOR_nothing)
7691 {7689 {
7692 expand_operands (treeop0, treeop1, NULL_RTX, &op0, &op1,7690 expand_operands (treeop0, treeop1, NULL_RTX, &op0, &op1,
7693 EXPAND_NORMAL);7691 EXPAND_NORMAL);
@@ -7695,7 +7693,8 @@
7695 unsignedp, this_optab);7693 unsignedp, this_optab);
7696 return REDUCE_BIT_FIELD (temp);7694 return REDUCE_BIT_FIELD (temp);
7697 }7695 }
7698 if (optab_handler (other_optab, mode) != CODE_FOR_nothing7696 if (find_widening_optab_handler (other_optab, mode, innermode, 0)
7697 != CODE_FOR_nothing
7699 && innermode == word_mode)7698 && innermode == word_mode)
7700 {7699 {
7701 rtx htem, hipart;7700 rtx htem, hipart;
77027701
=== modified file 'gcc/genopinit.c'
--- gcc/genopinit.c 2011-05-05 15:43:06 +0000
+++ gcc/genopinit.c 2011-07-18 13:34:25 +0000
@@ -46,10 +46,12 @@
46 used. $A and $B are replaced with the full name of the mode; $a and $b46 used. $A and $B are replaced with the full name of the mode; $a and $b
47 are replaced with the short form of the name, as above.47 are replaced with the short form of the name, as above.
4848
49 If $N is present in the pattern, it means the two modes must be consecutive49 If $N is present in the pattern, it means the two modes must be in
50 widths in the same mode class (e.g, QImode and HImode). $I means that50 the same mode class, and $b must be greater than $a (e.g, QImode
51 only full integer modes should be considered for the next mode, and $F51 and HImode).
52 means that only float modes should be considered.52
53 $I means that only full integer modes should be considered for the
54 next mode, and $F means that only float modes should be considered.
53 $P means that both full and partial integer modes should be considered.55 $P means that both full and partial integer modes should be considered.
54 $Q means that only fixed-point modes should be considered.56 $Q means that only fixed-point modes should be considered.
5557
@@ -99,17 +101,17 @@
99 "set_optab_handler (smulv_optab, $A, CODE_FOR_$(mulv$I$a3$))",101 "set_optab_handler (smulv_optab, $A, CODE_FOR_$(mulv$I$a3$))",
100 "set_optab_handler (umul_highpart_optab, $A, CODE_FOR_$(umul$a3_highpart$))",102 "set_optab_handler (umul_highpart_optab, $A, CODE_FOR_$(umul$a3_highpart$))",
101 "set_optab_handler (smul_highpart_optab, $A, CODE_FOR_$(smul$a3_highpart$))",103 "set_optab_handler (smul_highpart_optab, $A, CODE_FOR_$(smul$a3_highpart$))",
102 "set_optab_handler (smul_widen_optab, $B, CODE_FOR_$(mul$a$b3$)$N)",104 "set_widening_optab_handler (smul_widen_optab, $B, $A, CODE_FOR_$(mul$a$b3$)$N)",
103 "set_optab_handler (umul_widen_optab, $B, CODE_FOR_$(umul$a$b3$)$N)",105 "set_widening_optab_handler (umul_widen_optab, $B, $A, CODE_FOR_$(umul$a$b3$)$N)",
104 "set_optab_handler (usmul_widen_optab, $B, CODE_FOR_$(usmul$a$b3$)$N)",106 "set_widening_optab_handler (usmul_widen_optab, $B, $A, CODE_FOR_$(usmul$a$b3$)$N)",
105 "set_optab_handler (smadd_widen_optab, $B, CODE_FOR_$(madd$a$b4$)$N)",107 "set_widening_optab_handler (smadd_widen_optab, $B, $A, CODE_FOR_$(madd$a$b4$)$N)",
106 "set_optab_handler (umadd_widen_optab, $B, CODE_FOR_$(umadd$a$b4$)$N)",108 "set_widening_optab_handler (umadd_widen_optab, $B, $A, CODE_FOR_$(umadd$a$b4$)$N)",
107 "set_optab_handler (ssmadd_widen_optab, $B, CODE_FOR_$(ssmadd$a$b4$)$N)",109 "set_widening_optab_handler (ssmadd_widen_optab, $B, $A, CODE_FOR_$(ssmadd$a$b4$)$N)",
108 "set_optab_handler (usmadd_widen_optab, $B, CODE_FOR_$(usmadd$a$b4$)$N)",110 "set_widening_optab_handler (usmadd_widen_optab, $B, $A, CODE_FOR_$(usmadd$a$b4$)$N)",
109 "set_optab_handler (smsub_widen_optab, $B, CODE_FOR_$(msub$a$b4$)$N)",111 "set_widening_optab_handler (smsub_widen_optab, $B, $A, CODE_FOR_$(msub$a$b4$)$N)",
110 "set_optab_handler (umsub_widen_optab, $B, CODE_FOR_$(umsub$a$b4$)$N)",112 "set_widening_optab_handler (umsub_widen_optab, $B, $A, CODE_FOR_$(umsub$a$b4$)$N)",
111 "set_optab_handler (ssmsub_widen_optab, $B, CODE_FOR_$(ssmsub$a$b4$)$N)",113 "set_widening_optab_handler (ssmsub_widen_optab, $B, $A, CODE_FOR_$(ssmsub$a$b4$)$N)",
112 "set_optab_handler (usmsub_widen_optab, $B, CODE_FOR_$(usmsub$a$b4$)$N)",114 "set_widening_optab_handler (usmsub_widen_optab, $B, $A, CODE_FOR_$(usmsub$a$b4$)$N)",
113 "set_optab_handler (sdiv_optab, $A, CODE_FOR_$(div$a3$))",115 "set_optab_handler (sdiv_optab, $A, CODE_FOR_$(div$a3$))",
114 "set_optab_handler (ssdiv_optab, $A, CODE_FOR_$(ssdiv$Q$a3$))",116 "set_optab_handler (ssdiv_optab, $A, CODE_FOR_$(ssdiv$Q$a3$))",
115 "set_optab_handler (sdivv_optab, $A, CODE_FOR_$(div$V$I$a3$))",117 "set_optab_handler (sdivv_optab, $A, CODE_FOR_$(div$V$I$a3$))",
@@ -304,7 +306,7 @@
304 {306 {
305 int force_float = 0, force_int = 0, force_partial_int = 0;307 int force_float = 0, force_int = 0, force_partial_int = 0;
306 int force_fixed = 0;308 int force_fixed = 0;
307 int force_consec = 0;309 int force_wider = 0;
308 int matches = 1;310 int matches = 1;
309311
310 for (pp = optabs[pindex]; pp[0] != '$' || pp[1] != '('; pp++)312 for (pp = optabs[pindex]; pp[0] != '$' || pp[1] != '('; pp++)
@@ -322,7 +324,7 @@
322 switch (*++pp)324 switch (*++pp)
323 {325 {
324 case 'N':326 case 'N':
325 force_consec = 1;327 force_wider = 1;
326 break;328 break;
327 case 'I':329 case 'I':
328 force_int = 1;330 force_int = 1;
@@ -391,7 +393,10 @@
391 || mode_class[i] == MODE_VECTOR_FRACT393 || mode_class[i] == MODE_VECTOR_FRACT
392 || mode_class[i] == MODE_VECTOR_UFRACT394 || mode_class[i] == MODE_VECTOR_UFRACT
393 || mode_class[i] == MODE_VECTOR_ACCUM395 || mode_class[i] == MODE_VECTOR_ACCUM
394 || mode_class[i] == MODE_VECTOR_UACCUM))396 || mode_class[i] == MODE_VECTOR_UACCUM)
397 && (! force_wider
398 || *pp == 'a'
399 || m1 < i))
395 break;400 break;
396 }401 }
397402
@@ -411,8 +416,7 @@
411 }416 }
412417
413 if (matches && pp[0] == '$' && pp[1] == ')'418 if (matches && pp[0] == '$' && pp[1] == ')'
414 && *np == 0419 && *np == 0)
415 && (! force_consec || (int) GET_MODE_WIDER_MODE(m1) == m2))
416 break;420 break;
417 }421 }
418422
419423
=== modified file 'gcc/optabs.c'
--- gcc/optabs.c 2011-07-04 14:03:49 +0000
+++ gcc/optabs.c 2011-07-18 13:34:25 +0000
@@ -225,6 +225,37 @@
225 return 1;225 return 1;
226}226}
227227
228228
229/* Find a widening optab even if it doesn't widen as much as we want.
230 E.g. if from_mode is HImode, and to_mode is DImode, and there is no
231 direct HI->SI insn, then return SI->DI, if that exists.
232 If PERMIT_NON_WIDENING is non-zero then this can be used with
233 non-widening optabs also. */
234
235enum insn_code
236find_widening_optab_handler_and_mode (optab op, enum machine_mode to_mode,
237 enum machine_mode from_mode,
238 int permit_non_widening,
239 enum machine_mode *found_mode)
240{
241 for (; (permit_non_widening || from_mode != to_mode)
242 && GET_MODE_SIZE (from_mode) <= GET_MODE_SIZE (to_mode)
243 && from_mode != VOIDmode;
244 from_mode = GET_MODE_WIDER_MODE (from_mode))
245 {
246 enum insn_code handler = widening_optab_handler (op, to_mode,
247 from_mode);
248
249 if (handler != CODE_FOR_nothing)
250 {
251 if (found_mode)
252 *found_mode = from_mode;
253 return handler;
254 }
255 }
256
257 return CODE_FOR_nothing;
258}
259
229260
230/* Widen OP to MODE and return the rtx for the widened operand. UNSIGNEDP261/* Widen OP to MODE and return the rtx for the widened operand. UNSIGNEDP
231 says whether OP is signed or unsigned. NO_EXTEND is nonzero if we need262 says whether OP is signed or unsigned. NO_EXTEND is nonzero if we need
232 not actually do a sign-extend or zero-extend, but can leave the263 not actually do a sign-extend or zero-extend, but can leave the
@@ -517,8 +548,9 @@
517 optab_for_tree_code (ops->code, TREE_TYPE (oprnd0), optab_default);548 optab_for_tree_code (ops->code, TREE_TYPE (oprnd0), optab_default);
518 if (ops->code == WIDEN_MULT_PLUS_EXPR549 if (ops->code == WIDEN_MULT_PLUS_EXPR
519 || ops->code == WIDEN_MULT_MINUS_EXPR)550 || ops->code == WIDEN_MULT_MINUS_EXPR)
520 icode = (int) optab_handler (widen_pattern_optab,551 icode = (int) find_widening_optab_handler (widen_pattern_optab,
521 TYPE_MODE (TREE_TYPE (ops->op2)));552 TYPE_MODE (TREE_TYPE (ops->op2)),
553 tmode0, 0);
522 else554 else
523 icode = (int) optab_handler (widen_pattern_optab, tmode0);555 icode = (int) optab_handler (widen_pattern_optab, tmode0);
524 gcc_assert (icode != CODE_FOR_nothing);556 gcc_assert (icode != CODE_FOR_nothing);
@@ -1389,7 +1421,9 @@
1389 rtx target, int unsignedp, enum optab_methods methods,1421 rtx target, int unsignedp, enum optab_methods methods,
1390 rtx last)1422 rtx last)
1391{1423{
1392 int icode = (int) optab_handler (binoptab, mode);1424 enum machine_mode from_mode = GET_MODE (op0);
1425 int icode = (int) find_widening_optab_handler (binoptab, mode,
1426 from_mode, 1);
1393 enum machine_mode mode0 = insn_data[icode].operand[1].mode;1427 enum machine_mode mode0 = insn_data[icode].operand[1].mode;
1394 enum machine_mode mode1 = insn_data[icode].operand[2].mode;1428 enum machine_mode mode1 = insn_data[icode].operand[2].mode;
1395 enum machine_mode tmp_mode;1429 enum machine_mode tmp_mode;
@@ -1546,7 +1580,8 @@
1546 /* If we can do it with a three-operand insn, do so. */1580 /* If we can do it with a three-operand insn, do so. */
15471581
1548 if (methods != OPTAB_MUST_WIDEN1582 if (methods != OPTAB_MUST_WIDEN
1549 && optab_handler (binoptab, mode) != CODE_FOR_nothing)1583 && find_widening_optab_handler (binoptab, mode, GET_MODE (op0), 1)
1584 != CODE_FOR_nothing)
1550 {1585 {
1551 temp = expand_binop_directly (mode, binoptab, op0, op1, target,1586 temp = expand_binop_directly (mode, binoptab, op0, op1, target,
1552 unsignedp, methods, last);1587 unsignedp, methods, last);
@@ -1585,9 +1620,10 @@
1585 takes operands of this mode and makes a wider mode. */1620 takes operands of this mode and makes a wider mode. */
15861621
1587 if (binoptab == smul_optab1622 if (binoptab == smul_optab
1588 && GET_MODE_WIDER_MODE (mode) != VOIDmode1623 && GET_MODE_2XWIDER_MODE (mode) != VOIDmode
1589 && (optab_handler ((unsignedp ? umul_widen_optab : smul_widen_optab),1624 && (widening_optab_handler ((unsignedp ? umul_widen_optab
1590 GET_MODE_WIDER_MODE (mode))1625 : smul_widen_optab),
1626 GET_MODE_2XWIDER_MODE (mode), mode)
1591 != CODE_FOR_nothing))1627 != CODE_FOR_nothing))
1592 {1628 {
1593 temp = expand_binop (GET_MODE_WIDER_MODE (mode),1629 temp = expand_binop (GET_MODE_WIDER_MODE (mode),
@@ -1615,12 +1651,15 @@
1615 wider_mode != VOIDmode;1651 wider_mode != VOIDmode;
1616 wider_mode = GET_MODE_WIDER_MODE (wider_mode))1652 wider_mode = GET_MODE_WIDER_MODE (wider_mode))
1617 {1653 {
1618 if (optab_handler (binoptab, wider_mode) != CODE_FOR_nothing1654 if (optab_handler (binoptab, wider_mode)
1655 != CODE_FOR_nothing
1619 || (binoptab == smul_optab1656 || (binoptab == smul_optab
1620 && GET_MODE_WIDER_MODE (wider_mode) != VOIDmode1657 && GET_MODE_WIDER_MODE (wider_mode) != VOIDmode
1621 && (optab_handler ((unsignedp ? umul_widen_optab1658 && (find_widening_optab_handler ((unsignedp
1622 : smul_widen_optab),1659 ? umul_widen_optab
1623 GET_MODE_WIDER_MODE (wider_mode))1660 : smul_widen_optab),
1661 GET_MODE_WIDER_MODE (wider_mode),
1662 mode, 0)
1624 != CODE_FOR_nothing)))1663 != CODE_FOR_nothing)))
1625 {1664 {
1626 rtx xop0 = op0, xop1 = op1;1665 rtx xop0 = op0, xop1 = op1;
@@ -2043,8 +2082,8 @@
2043 && optab_handler (add_optab, word_mode) != CODE_FOR_nothing)2082 && optab_handler (add_optab, word_mode) != CODE_FOR_nothing)
2044 {2083 {
2045 rtx product = NULL_RTX;2084 rtx product = NULL_RTX;
20462085 if (widening_optab_handler (umul_widen_optab, mode, word_mode)
2047 if (optab_handler (umul_widen_optab, mode) != CODE_FOR_nothing)2086 != CODE_FOR_nothing)
2048 {2087 {
2049 product = expand_doubleword_mult (mode, op0, op1, target,2088 product = expand_doubleword_mult (mode, op0, op1, target,
2050 true, methods);2089 true, methods);
@@ -2053,7 +2092,8 @@
2053 }2092 }
20542093
2055 if (product == NULL_RTX2094 if (product == NULL_RTX
2056 && optab_handler (smul_widen_optab, mode) != CODE_FOR_nothing)2095 && widening_optab_handler (smul_widen_optab, mode, word_mode)
2096 != CODE_FOR_nothing)
2057 {2097 {
2058 product = expand_doubleword_mult (mode, op0, op1, target,2098 product = expand_doubleword_mult (mode, op0, op1, target,
2059 false, methods);2099 false, methods);
@@ -2144,7 +2184,8 @@
2144 wider_mode != VOIDmode;2184 wider_mode != VOIDmode;
2145 wider_mode = GET_MODE_WIDER_MODE (wider_mode))2185 wider_mode = GET_MODE_WIDER_MODE (wider_mode))
2146 {2186 {
2147 if (optab_handler (binoptab, wider_mode) != CODE_FOR_nothing2187 if (find_widening_optab_handler (binoptab, wider_mode, mode, 1)
2188 != CODE_FOR_nothing
2148 || (methods == OPTAB_LIB2189 || (methods == OPTAB_LIB
2149 && optab_libfunc (binoptab, wider_mode)))2190 && optab_libfunc (binoptab, wider_mode)))
2150 {2191 {
21512192
=== modified file 'gcc/optabs.h'
--- gcc/optabs.h 2011-05-05 15:43:06 +0000
+++ gcc/optabs.h 2011-07-18 13:34:25 +0000
@@ -42,6 +42,11 @@
42 int insn_code;42 int insn_code;
43};43};
4444
45struct widening_optab_handlers
46{
47 struct optab_handlers handlers[NUM_MACHINE_MODES][NUM_MACHINE_MODES];
48};
49
45struct optab_d50struct optab_d
46{51{
47 enum rtx_code code;52 enum rtx_code code;
@@ -50,6 +55,7 @@
50 void (*libcall_gen)(struct optab_d *, const char *name, char suffix,55 void (*libcall_gen)(struct optab_d *, const char *name, char suffix,
51 enum machine_mode);56 enum machine_mode);
52 struct optab_handlers handlers[NUM_MACHINE_MODES];57 struct optab_handlers handlers[NUM_MACHINE_MODES];
58 struct widening_optab_handlers *widening;
53};59};
54typedef struct optab_d * optab;60typedef struct optab_d * optab;
5561
@@ -799,6 +805,15 @@
799extern void emit_unop_insn (int, rtx, rtx, enum rtx_code);805extern void emit_unop_insn (int, rtx, rtx, enum rtx_code);
800extern bool maybe_emit_unop_insn (int, rtx, rtx, enum rtx_code);806extern bool maybe_emit_unop_insn (int, rtx, rtx, enum rtx_code);
801807
808/* Find a widening optab even if it doesn't widen as much as we want. */
809#define find_widening_optab_handler(A,B,C,D) \
810 find_widening_optab_handler_and_mode (A, B, C, D, NULL)
811extern enum insn_code find_widening_optab_handler_and_mode (optab,
812 enum machine_mode,
813 enum machine_mode,
814 int,
815 enum machine_mode *);
816
802/* An extra flag to control optab_for_tree_code's behavior. This is needed to817/* An extra flag to control optab_for_tree_code's behavior. This is needed to
803 distinguish between machines with a vector shift that takes a scalar for the818 distinguish between machines with a vector shift that takes a scalar for the
804 shift amount vs. machines that take a vector for the shift amount. */819 shift amount vs. machines that take a vector for the shift amount. */
@@ -874,6 +889,23 @@
874 + (int) CODE_FOR_nothing);889 + (int) CODE_FOR_nothing);
875}890}
876891
892/* Like optab_handler, but for widening_operations that have a TO_MODE and
893 a FROM_MODE. */
894
895static inline enum insn_code
896widening_optab_handler (optab op, enum machine_mode to_mode,
897 enum machine_mode from_mode)
898{
899 if (to_mode == from_mode)
900 return optab_handler (op, to_mode);
901
902 if (op->widening)
903 return (enum insn_code) (op->widening->handlers[(int) to_mode][(int) from_mode].insn_code
904 + (int) CODE_FOR_nothing);
905
906 return CODE_FOR_nothing;
907}
908
877/* Record that insn CODE should be used to implement mode MODE of OP. */909/* Record that insn CODE should be used to implement mode MODE of OP. */
878910
879static inline void911static inline void
@@ -882,6 +914,26 @@
882 op->handlers[(int) mode].insn_code = (int) code - (int) CODE_FOR_nothing;914 op->handlers[(int) mode].insn_code = (int) code - (int) CODE_FOR_nothing;
883}915}
884916
917/* Like set_optab_handler, but for widening operations that have a TO_MODE
918 and a FROM_MODE. */
919
920static inline void
921set_widening_optab_handler (optab op, enum machine_mode to_mode,
922 enum machine_mode from_mode, enum insn_code code)
923{
924 if (to_mode == from_mode)
925 set_optab_handler (op, to_mode, code);
926 else
927 {
928 if (op->widening == NULL)
929 op->widening = (struct widening_optab_handlers *)
930 xcalloc (1, sizeof (struct widening_optab_handlers));
931
932 op->widening->handlers[(int) to_mode][(int) from_mode].insn_code
933 = (int) code - (int) CODE_FOR_nothing;
934 }
935}
936
885/* Return the insn used to perform conversion OP from mode FROM_MODE937/* Return the insn used to perform conversion OP from mode FROM_MODE
886 to mode TO_MODE; return CODE_FOR_nothing if the target does not have938 to mode TO_MODE; return CODE_FOR_nothing if the target does not have
887 such an insn. */939 such an insn. */
888940
=== added file 'gcc/testsuite/gcc.target/arm/no-wmla-1.c'
--- gcc/testsuite/gcc.target/arm/no-wmla-1.c 1970-01-01 00:00:00 +0000
+++ gcc/testsuite/gcc.target/arm/no-wmla-1.c 2011-07-18 13:34:25 +0000
@@ -0,0 +1,11 @@
1/* { dg-do compile } */
2/* { dg-options "-O2 -march=armv7-a" } */
3
4int
5foo (int a, short b, short c)
6{
7 int bc = b * c;
8 return a + (short)bc;
9}
10
11/* { dg-final { scan-assembler "mul" } } */
012
=== added file 'gcc/testsuite/gcc.target/arm/wmul-10.c'
--- gcc/testsuite/gcc.target/arm/wmul-10.c 1970-01-01 00:00:00 +0000
+++ gcc/testsuite/gcc.target/arm/wmul-10.c 2011-07-18 13:34:25 +0000
@@ -0,0 +1,10 @@
1/* { dg-do compile } */
2/* { dg-options "-O2 -march=armv7-a" } */
3
4unsigned long long
5foo (unsigned short a, unsigned short *b, unsigned short *c)
6{
7 return (unsigned)a + (unsigned long long)*b * (unsigned long long)*c;
8}
9
10/* { dg-final { scan-assembler "umlal" } } */
011
=== added file 'gcc/testsuite/gcc.target/arm/wmul-5.c'
--- gcc/testsuite/gcc.target/arm/wmul-5.c 1970-01-01 00:00:00 +0000
+++ gcc/testsuite/gcc.target/arm/wmul-5.c 2011-07-18 13:34:25 +0000
@@ -0,0 +1,10 @@
1/* { dg-do compile } */
2/* { dg-options "-O2 -march=armv7-a" } */
3
4long long
5foo (long long a, char *b, char *c)
6{
7 return a + *b * *c;
8}
9
10/* { dg-final { scan-assembler "umlal" } } */
011
=== added file 'gcc/testsuite/gcc.target/arm/wmul-6.c'
--- gcc/testsuite/gcc.target/arm/wmul-6.c 1970-01-01 00:00:00 +0000
+++ gcc/testsuite/gcc.target/arm/wmul-6.c 2011-07-18 13:34:25 +0000
@@ -0,0 +1,10 @@
1/* { dg-do compile } */
2/* { dg-options "-O2 -march=armv7-a" } */
3
4long long
5foo (long long a, unsigned char *b, signed char *c)
6{
7 return a + (long long)*b * (long long)*c;
8}
9
10/* { dg-final { scan-assembler "smlal" } } */
011
=== added file 'gcc/testsuite/gcc.target/arm/wmul-7.c'
--- gcc/testsuite/gcc.target/arm/wmul-7.c 1970-01-01 00:00:00 +0000
+++ gcc/testsuite/gcc.target/arm/wmul-7.c 2011-07-18 13:34:25 +0000
@@ -0,0 +1,10 @@
1/* { dg-do compile } */
2/* { dg-options "-O2 -march=armv7-a" } */
3
4unsigned long long
5foo (unsigned long long a, unsigned char *b, unsigned short *c)
6{
7 return a + *b * *c;
8}
9
10/* { dg-final { scan-assembler "umlal" } } */
011
=== added file 'gcc/testsuite/gcc.target/arm/wmul-8.c'
--- gcc/testsuite/gcc.target/arm/wmul-8.c 1970-01-01 00:00:00 +0000
+++ gcc/testsuite/gcc.target/arm/wmul-8.c 2011-07-18 13:34:25 +0000
@@ -0,0 +1,10 @@
1/* { dg-do compile } */
2/* { dg-options "-O2 -march=armv7-a" } */
3
4long long
5foo (long long a, int *b, int *c)
6{
7 return a + *b * *c;
8}
9
10/* { dg-final { scan-assembler "smlal" } } */
011
=== added file 'gcc/testsuite/gcc.target/arm/wmul-9.c'
--- gcc/testsuite/gcc.target/arm/wmul-9.c 1970-01-01 00:00:00 +0000
+++ gcc/testsuite/gcc.target/arm/wmul-9.c 2011-07-18 13:34:25 +0000
@@ -0,0 +1,10 @@
1/* { dg-do compile } */
2/* { dg-options "-O2 -march=armv7-a" } */
3
4long long
5foo (long long a, short *b, char *c)
6{
7 return a + *b * *c;
8}
9
10/* { dg-final { scan-assembler "smlalbb" } } */
011
=== added file 'gcc/testsuite/gcc.target/arm/wmul-bitfield-1.c'
--- gcc/testsuite/gcc.target/arm/wmul-bitfield-1.c 1970-01-01 00:00:00 +0000
+++ gcc/testsuite/gcc.target/arm/wmul-bitfield-1.c 2011-07-18 13:34:25 +0000
@@ -0,0 +1,17 @@
1/* { dg-do compile } */
2/* { dg-options "-O2 -march=armv7-a" } */
3
4struct bf
5{
6 int a : 3;
7 int b : 15;
8 int c : 3;
9};
10
11long long
12foo (long long a, struct bf b, struct bf c)
13{
14 return a + b.b * c.b;
15}
16
17/* { dg-final { scan-assembler "smlalbb" } } */
018
=== added file 'gcc/testsuite/gcc.target/arm/wmul-bitfield-2.c'
--- gcc/testsuite/gcc.target/arm/wmul-bitfield-2.c 1970-01-01 00:00:00 +0000
+++ gcc/testsuite/gcc.target/arm/wmul-bitfield-2.c 2011-07-18 13:34:25 +0000
@@ -0,0 +1,17 @@
1/* { dg-do compile } */
2/* { dg-options "-O2 -march=armv7-a" } */
3
4struct bf
5{
6 int a : 3;
7 unsigned int b : 15;
8 int c : 3;
9};
10
11long long
12foo (long long a, struct bf b, struct bf c)
13{
14 return a + b.b * c.c;
15}
16
17/* { dg-final { scan-assembler "smlalbb" } } */
018
=== modified file 'gcc/tree-cfg.c'
--- gcc/tree-cfg.c 2011-07-01 09:19:21 +0000
+++ gcc/tree-cfg.c 2011-07-18 13:34:25 +0000
@@ -3574,7 +3574,7 @@
3574 case WIDEN_MULT_EXPR:3574 case WIDEN_MULT_EXPR:
3575 if (TREE_CODE (lhs_type) != INTEGER_TYPE)3575 if (TREE_CODE (lhs_type) != INTEGER_TYPE)
3576 return true;3576 return true;
3577 return ((2 * TYPE_PRECISION (rhs1_type) != TYPE_PRECISION (lhs_type))3577 return ((2 * TYPE_PRECISION (rhs1_type) > TYPE_PRECISION (lhs_type))
3578 || (TYPE_PRECISION (rhs1_type) != TYPE_PRECISION (rhs2_type)));3578 || (TYPE_PRECISION (rhs1_type) != TYPE_PRECISION (rhs2_type)));
35793579
3580 case WIDEN_SUM_EXPR:3580 case WIDEN_SUM_EXPR:
@@ -3667,7 +3667,7 @@
3667 && !FIXED_POINT_TYPE_P (rhs1_type))3667 && !FIXED_POINT_TYPE_P (rhs1_type))
3668 || !useless_type_conversion_p (rhs1_type, rhs2_type)3668 || !useless_type_conversion_p (rhs1_type, rhs2_type)
3669 || !useless_type_conversion_p (lhs_type, rhs3_type)3669 || !useless_type_conversion_p (lhs_type, rhs3_type)
3670 || 2 * TYPE_PRECISION (rhs1_type) != TYPE_PRECISION (lhs_type)3670 || 2 * TYPE_PRECISION (rhs1_type) > TYPE_PRECISION (lhs_type)
3671 || TYPE_PRECISION (rhs1_type) != TYPE_PRECISION (rhs2_type))3671 || TYPE_PRECISION (rhs1_type) != TYPE_PRECISION (rhs2_type))
3672 {3672 {
3673 error ("type mismatch in widening multiply-accumulate expression");3673 error ("type mismatch in widening multiply-accumulate expression");
36743674
=== modified file 'gcc/tree-ssa-math-opts.c'
--- gcc/tree-ssa-math-opts.c 2011-03-11 16:36:16 +0000
+++ gcc/tree-ssa-math-opts.c 2011-07-18 13:34:25 +0000
@@ -1266,42 +1266,68 @@
1266 }1266 }
1267};1267};
12681268
1269/* Return true if RHS is a suitable operand for a widening multiplication.1269/* Build a gimple assignment to cast VAL to TARGET. Insert the statement
1270 prior to GSI's current position, and return the fresh SSA name. */
1271
1272static tree
1273build_and_insert_cast (gimple_stmt_iterator *gsi, location_t loc,
1274 tree target, tree val)
1275{
1276 tree result = make_ssa_name (target, NULL);
1277 gimple stmt = gimple_build_assign_with_ops (CONVERT_EXPR, result, val, NULL);
1278 gimple_set_location (stmt, loc);
1279 gsi_insert_before (gsi, stmt, GSI_SAME_STMT);
1280 return result;
1281}
1282
1283/* Return true if RHS is a suitable operand for a widening multiplication,
1284 assuming a target type of TYPE.
1270 There are two cases:1285 There are two cases:
12711286
1272 - RHS makes some value twice as wide. Store that value in *NEW_RHS_OUT1287 - RHS makes some value at least twice as wide. Store that value
1273 if so, and store its type in *TYPE_OUT.1288 in *NEW_RHS_OUT if so, and store its type in *TYPE_OUT.
12741289
1275 - RHS is an integer constant. Store that value in *NEW_RHS_OUT if so,1290 - RHS is an integer constant. Store that value in *NEW_RHS_OUT if so,
1276 but leave *TYPE_OUT untouched. */1291 but leave *TYPE_OUT untouched. */
12771292
1278static bool1293static bool
1279is_widening_mult_rhs_p (tree rhs, tree *type_out, tree *new_rhs_out)1294is_widening_mult_rhs_p (tree type, tree rhs, tree *type_out,
1295 tree *new_rhs_out)
1280{1296{
1281 gimple stmt;1297 gimple stmt;
1282 tree type, type1, rhs1;1298 tree type1, rhs1;
1283 enum tree_code rhs_code;1299 enum tree_code rhs_code;
12841300
1285 if (TREE_CODE (rhs) == SSA_NAME)1301 if (TREE_CODE (rhs) == SSA_NAME)
1286 {1302 {
1287 type = TREE_TYPE (rhs);
1288 stmt = SSA_NAME_DEF_STMT (rhs);1303 stmt = SSA_NAME_DEF_STMT (rhs);
1289 if (!is_gimple_assign (stmt))1304 if (!is_gimple_assign (stmt))
1290 return false;1305 {
12911306 rhs1 = NULL;
1292 rhs_code = gimple_assign_rhs_code (stmt);1307 type1 = TREE_TYPE (rhs);
1293 if (TREE_CODE (type) == INTEGER_TYPE1308 }
1294 ? !CONVERT_EXPR_CODE_P (rhs_code)1309 else
1295 : rhs_code != FIXED_CONVERT_EXPR)1310 {
1296 return false;1311 rhs1 = gimple_assign_rhs1 (stmt);
12971312 type1 = TREE_TYPE (rhs1);
1298 rhs1 = gimple_assign_rhs1 (stmt);1313 }
1299 type1 = TREE_TYPE (rhs1);1314
1300 if (TREE_CODE (type1) != TREE_CODE (type)1315 if (TREE_CODE (type1) != TREE_CODE (type)
1301 || TYPE_PRECISION (type1) * 2 != TYPE_PRECISION (type))1316 || TYPE_PRECISION (type1) * 2 > TYPE_PRECISION (type))
1302 return false;1317 return false;
13031318
1304 *new_rhs_out = rhs1;1319 if (rhs1)
1320 {
1321 rhs_code = gimple_assign_rhs_code (stmt);
1322 if (TREE_CODE (type) == INTEGER_TYPE
1323 ? !CONVERT_EXPR_CODE_P (rhs_code)
1324 : rhs_code != FIXED_CONVERT_EXPR)
1325 *new_rhs_out = rhs;
1326 else
1327 *new_rhs_out = rhs1;
1328 }
1329 else
1330 *new_rhs_out = rhs;
1305 *type_out = type1;1331 *type_out = type1;
1306 return true;1332 return true;
1307 }1333 }
@@ -1316,28 +1342,27 @@
1316 return false;1342 return false;
1317}1343}
13181344
1319/* Return true if STMT performs a widening multiplication. If so,1345/* Return true if STMT performs a widening multiplication, assuming the
1320 store the unwidened types of the operands in *TYPE1_OUT and *TYPE2_OUT1346 output type is TYPE. If so, store the unwidened types of the operands
1321 respectively. Also fill *RHS1_OUT and *RHS2_OUT such that converting1347 in *TYPE1_OUT and *TYPE2_OUT respectively. Also fill *RHS1_OUT and
1322 those operands to types *TYPE1_OUT and *TYPE2_OUT would give the1348 *RHS2_OUT such that converting those operands to types *TYPE1_OUT
1323 operands of the multiplication. */1349 and *TYPE2_OUT would give the operands of the multiplication. */
13241350
1325static bool1351static bool
1326is_widening_mult_p (gimple stmt,1352is_widening_mult_p (tree type, gimple stmt,
1327 tree *type1_out, tree *rhs1_out,1353 tree *type1_out, tree *rhs1_out,
1328 tree *type2_out, tree *rhs2_out)1354 tree *type2_out, tree *rhs2_out)
1329{1355{
1330 tree type;
1331
1332 type = TREE_TYPE (gimple_assign_lhs (stmt));
1333 if (TREE_CODE (type) != INTEGER_TYPE1356 if (TREE_CODE (type) != INTEGER_TYPE
1334 && TREE_CODE (type) != FIXED_POINT_TYPE)1357 && TREE_CODE (type) != FIXED_POINT_TYPE)
1335 return false;1358 return false;
13361359
1337 if (!is_widening_mult_rhs_p (gimple_assign_rhs1 (stmt), type1_out, rhs1_out))1360 if (!is_widening_mult_rhs_p (type, gimple_assign_rhs1 (stmt), type1_out,
1361 rhs1_out))
1338 return false;1362 return false;
13391363
1340 if (!is_widening_mult_rhs_p (gimple_assign_rhs2 (stmt), type2_out, rhs2_out))1364 if (!is_widening_mult_rhs_p (type, gimple_assign_rhs2 (stmt), type2_out,
1365 rhs2_out))
1341 return false;1366 return false;
13421367
1343 if (*type1_out == NULL)1368 if (*type1_out == NULL)
@@ -1354,6 +1379,18 @@
1354 *type2_out = *type1_out;1379 *type2_out = *type1_out;
1355 }1380 }
13561381
1382 /* Ensure that the larger of the two operands comes first. */
1383 if (TYPE_PRECISION (*type1_out) < TYPE_PRECISION (*type2_out))
1384 {
1385 tree tmp;
1386 tmp = *type1_out;
1387 *type1_out = *type2_out;
1388 *type2_out = tmp;
1389 tmp = *rhs1_out;
1390 *rhs1_out = *rhs2_out;
1391 *rhs2_out = tmp;
1392 }
1393
1357 return true;1394 return true;
1358}1395}
13591396
@@ -1362,31 +1399,94 @@
1362 value is true iff we converted the statement. */1399 value is true iff we converted the statement. */
13631400
1364static bool1401static bool
1365convert_mult_to_widen (gimple stmt)1402convert_mult_to_widen (gimple stmt, gimple_stmt_iterator *gsi)
1366{1403{
1367 tree lhs, rhs1, rhs2, type, type1, type2;1404 tree lhs, rhs1, rhs2, type, type1, type2, tmp = NULL;
1368 enum insn_code handler;1405 enum insn_code handler;
1406 enum machine_mode to_mode, from_mode, actual_mode;
1407 optab op;
1408 int actual_precision;
1409 location_t loc = gimple_location (stmt);
1410 bool from_unsigned1, from_unsigned2;
13691411
1370 lhs = gimple_assign_lhs (stmt);1412 lhs = gimple_assign_lhs (stmt);
1371 type = TREE_TYPE (lhs);1413 type = TREE_TYPE (lhs);
1372 if (TREE_CODE (type) != INTEGER_TYPE)1414 if (TREE_CODE (type) != INTEGER_TYPE)
1373 return false;1415 return false;
13741416
1375 if (!is_widening_mult_p (stmt, &type1, &rhs1, &type2, &rhs2))1417 if (!is_widening_mult_p (type, stmt, &type1, &rhs1, &type2, &rhs2))
1376 return false;1418 return false;
13771419
1378 if (TYPE_UNSIGNED (type1) && TYPE_UNSIGNED (type2))1420 to_mode = TYPE_MODE (type);
1379 handler = optab_handler (umul_widen_optab, TYPE_MODE (type));1421 from_mode = TYPE_MODE (type1);
1380 else if (!TYPE_UNSIGNED (type1) && !TYPE_UNSIGNED (type2))1422 from_unsigned1 = TYPE_UNSIGNED (type1);
1381 handler = optab_handler (smul_widen_optab, TYPE_MODE (type));1423 from_unsigned2 = TYPE_UNSIGNED (type2);
1424
1425 if (from_unsigned1 && from_unsigned2)
1426 op = umul_widen_optab;
1427 else if (!from_unsigned1 && !from_unsigned2)
1428 op = smul_widen_optab;
1382 else1429 else
1383 handler = optab_handler (usmul_widen_optab, TYPE_MODE (type));1430 op = usmul_widen_optab;
1431
1432 handler = find_widening_optab_handler_and_mode (op, to_mode, from_mode,
1433 0, &actual_mode);
13841434
1385 if (handler == CODE_FOR_nothing)1435 if (handler == CODE_FOR_nothing)
1386 return false;1436 {
13871437 if (op != smul_widen_optab)
1388 gimple_assign_set_rhs1 (stmt, fold_convert (type1, rhs1));1438 {
1389 gimple_assign_set_rhs2 (stmt, fold_convert (type2, rhs2));1439 /* We can use a signed multiply with unsigned types as long as
1440 there is a wider mode to use, or it is the smaller of the two
1441 types that is unsigned. Note that type1 >= type2, always. */
1442 if ((TYPE_UNSIGNED (type1)
1443 && TYPE_PRECISION (type1) == GET_MODE_PRECISION (from_mode))
1444 || (TYPE_UNSIGNED (type2)
1445 && TYPE_PRECISION (type2) == GET_MODE_PRECISION (from_mode)))
1446 {
1447 from_mode = GET_MODE_WIDER_MODE (from_mode);
1448 if (GET_MODE_SIZE (to_mode) <= GET_MODE_SIZE (from_mode))
1449 return false;
1450 }
1451
1452 op = smul_widen_optab;
1453 handler = find_widening_optab_handler_and_mode (op, to_mode,
1454 from_mode, 0,
1455 &actual_mode);
1456
1457 if (handler == CODE_FOR_nothing)
1458 return false;
1459
1460 from_unsigned1 = from_unsigned2 = false;
1461 }
1462 else
1463 return false;
1464 }
1465
1466 /* Ensure that the inputs to the handler are in the correct precison
1467 for the opcode. This will be the full mode size. */
1468 actual_precision = GET_MODE_PRECISION (actual_mode);
1469 if (actual_precision != TYPE_PRECISION (type1)
1470 || from_unsigned1 != TYPE_UNSIGNED (type1))
1471 {
1472 tmp = create_tmp_var (build_nonstandard_integer_type
1473 (actual_precision, from_unsigned1),
1474 NULL);
1475 rhs1 = build_and_insert_cast (gsi, loc, tmp, rhs1);
1476 }
1477 if (actual_precision != TYPE_PRECISION (type2)
1478 || from_unsigned2 != TYPE_UNSIGNED (type2))
1479 {
1480 /* Reuse the same type info, if possible. */
1481 if (!tmp || from_unsigned1 != from_unsigned2)
1482 tmp = create_tmp_var (build_nonstandard_integer_type
1483 (actual_precision, from_unsigned2),
1484 NULL);
1485 rhs2 = build_and_insert_cast (gsi, loc, tmp, rhs2);
1486 }
1487
1488 gimple_assign_set_rhs1 (stmt, rhs1);
1489 gimple_assign_set_rhs2 (stmt, rhs2);
1390 gimple_assign_set_rhs_code (stmt, WIDEN_MULT_EXPR);1490 gimple_assign_set_rhs_code (stmt, WIDEN_MULT_EXPR);
1391 update_stmt (stmt);1491 update_stmt (stmt);
1392 return true;1492 return true;
@@ -1403,11 +1503,17 @@
1403 enum tree_code code)1503 enum tree_code code)
1404{1504{
1405 gimple rhs1_stmt = NULL, rhs2_stmt = NULL;1505 gimple rhs1_stmt = NULL, rhs2_stmt = NULL;
1406 tree type, type1, type2;1506 gimple conv1_stmt = NULL, conv2_stmt = NULL, conv_stmt;
1507 tree type, type1, type2, optype, tmp = NULL;
1407 tree lhs, rhs1, rhs2, mult_rhs1, mult_rhs2, add_rhs;1508 tree lhs, rhs1, rhs2, mult_rhs1, mult_rhs2, add_rhs;
1408 enum tree_code rhs1_code = ERROR_MARK, rhs2_code = ERROR_MARK;1509 enum tree_code rhs1_code = ERROR_MARK, rhs2_code = ERROR_MARK;
1409 optab this_optab;1510 optab this_optab;
1410 enum tree_code wmult_code;1511 enum tree_code wmult_code;
1512 enum insn_code handler;
1513 enum machine_mode to_mode, from_mode, actual_mode;
1514 location_t loc = gimple_location (stmt);
1515 int actual_precision;
1516 bool from_unsigned1, from_unsigned2;
14111517
1412 lhs = gimple_assign_lhs (stmt);1518 lhs = gimple_assign_lhs (stmt);
1413 type = TREE_TYPE (lhs);1519 type = TREE_TYPE (lhs);
@@ -1441,54 +1547,153 @@
1441 else1547 else
1442 return false;1548 return false;
14431549
1444 if (code == PLUS_EXPR && rhs1_code == MULT_EXPR)1550 /* Allow for one conversion statement between the multiply
1445 {1551 and addition/subtraction statement. If there are more than
1446 if (!is_widening_mult_p (rhs1_stmt, &type1, &mult_rhs1,1552 one conversions then we assume they would invalidate this
1447 &type2, &mult_rhs2))1553 transformation. If that's not the case then they should have
1448 return false;1554 been folded before now. */
1449 add_rhs = rhs2;1555 if (CONVERT_EXPR_CODE_P (rhs1_code))
1450 }1556 {
1451 else if (rhs2_code == MULT_EXPR)1557 conv1_stmt = rhs1_stmt;
1452 {1558 rhs1 = gimple_assign_rhs1 (rhs1_stmt);
1453 if (!is_widening_mult_p (rhs2_stmt, &type1, &mult_rhs1,1559 if (TREE_CODE (rhs1) == SSA_NAME)
1454 &type2, &mult_rhs2))1560 {
1455 return false;1561 rhs1_stmt = SSA_NAME_DEF_STMT (rhs1);
1456 add_rhs = rhs1;1562 if (is_gimple_assign (rhs1_stmt))
1457 }1563 rhs1_code = gimple_assign_rhs_code (rhs1_stmt);
1458 else if (code == PLUS_EXPR && rhs1_code == WIDEN_MULT_EXPR)1564 }
1459 {1565 else
1460 mult_rhs1 = gimple_assign_rhs1 (rhs1_stmt);1566 return false;
1461 mult_rhs2 = gimple_assign_rhs2 (rhs1_stmt);1567 }
1462 type1 = TREE_TYPE (mult_rhs1);1568 if (CONVERT_EXPR_CODE_P (rhs2_code))
1463 type2 = TREE_TYPE (mult_rhs2);1569 {
1464 add_rhs = rhs2;1570 conv2_stmt = rhs2_stmt;
1465 }1571 rhs2 = gimple_assign_rhs1 (rhs2_stmt);
1466 else if (rhs2_code == WIDEN_MULT_EXPR)1572 if (TREE_CODE (rhs2) == SSA_NAME)
1467 {1573 {
1468 mult_rhs1 = gimple_assign_rhs1 (rhs2_stmt);1574 rhs2_stmt = SSA_NAME_DEF_STMT (rhs2);
1469 mult_rhs2 = gimple_assign_rhs2 (rhs2_stmt);1575 if (is_gimple_assign (rhs2_stmt))
1470 type1 = TREE_TYPE (mult_rhs1);1576 rhs2_code = gimple_assign_rhs_code (rhs2_stmt);
1471 type2 = TREE_TYPE (mult_rhs2);1577 }
1472 add_rhs = rhs1;1578 else
1579 return false;
1580 }
1581
1582 /* If code is WIDEN_MULT_EXPR then it would seem unnecessary to call
1583 is_widening_mult_p, but we still need the rhs returns.
1584
1585 It might also appear that it would be sufficient to use the existing
1586 operands of the widening multiply, but that would limit the choice of
1587 multiply-and-accumulate instructions. */
1588 if (code == PLUS_EXPR
1589 && (rhs1_code == MULT_EXPR || rhs1_code == WIDEN_MULT_EXPR))
1590 {
1591 if (!is_widening_mult_p (type, rhs1_stmt, &type1, &mult_rhs1,
1592 &type2, &mult_rhs2))
1593 return false;
1594 add_rhs = rhs2;
1595 conv_stmt = conv1_stmt;
1596 }
1597 else if (rhs2_code == MULT_EXPR || rhs2_code == WIDEN_MULT_EXPR)
1598 {
1599 if (!is_widening_mult_p (type, rhs2_stmt, &type1, &mult_rhs1,
1600 &type2, &mult_rhs2))
1601 return false;
1602 add_rhs = rhs1;
1603 conv_stmt = conv2_stmt;
1473 }1604 }
1474 else1605 else
1475 return false;1606 return false;
14761607
1477 if (TYPE_UNSIGNED (type1) != TYPE_UNSIGNED (type2))1608 to_mode = TYPE_MODE (type);
1478 return false;1609 from_mode = TYPE_MODE (type1);
1610 from_unsigned1 = TYPE_UNSIGNED (type1);
1611 from_unsigned2 = TYPE_UNSIGNED (type2);
1612
1613 /* There's no such thing as a mixed sign madd yet, so use a wider mode. */
1614 if (from_unsigned1 != from_unsigned2)
1615 {
1616 /* We can use a signed multiply with unsigned types as long as
1617 there is a wider mode to use, or it is the smaller of the two
1618 types that is unsigned. Note that type1 >= type2, always. */
1619 if ((from_unsigned1
1620 && TYPE_PRECISION (type1) == GET_MODE_PRECISION (from_mode))
1621 || (from_unsigned2
1622 && TYPE_PRECISION (type2) == GET_MODE_PRECISION (from_mode)))
1623 {
1624 from_mode = GET_MODE_WIDER_MODE (from_mode);
1625 if (GET_MODE_SIZE (from_mode) >= GET_MODE_SIZE (to_mode))
1626 return false;
1627 }
1628
1629 from_unsigned1 = from_unsigned2 = false;
1630 }
1631
1632 /* If there was a conversion between the multiply and addition
1633 then we need to make sure it fits a multiply-and-accumulate.
1634 The should be a single mode change which does not change the
1635 value. */
1636 if (conv_stmt)
1637 {
1638 /* We use the original, unmodified data types for this. */
1639 tree from_type = TREE_TYPE (gimple_assign_rhs1 (conv_stmt));
1640 tree to_type = TREE_TYPE (gimple_assign_lhs (conv_stmt));
1641 int data_size = TYPE_PRECISION (type1) + TYPE_PRECISION (type2);
1642 bool is_unsigned = TYPE_UNSIGNED (type1) && TYPE_UNSIGNED (type2);
1643
1644 if (TYPE_PRECISION (from_type) > TYPE_PRECISION (to_type))
1645 {
1646 /* Conversion is a truncate. */
1647 if (TYPE_PRECISION (to_type) < data_size)
1648 return false;
1649 }
1650 else if (TYPE_PRECISION (from_type) < TYPE_PRECISION (to_type))
1651 {
1652 /* Conversion is an extend. Check it's the right sort. */
1653 if (TYPE_UNSIGNED (from_type) != is_unsigned
1654 && !(is_unsigned && TYPE_PRECISION (from_type) > data_size))
1655 return false;
1656 }
1657 /* else convert is a no-op for our purposes. */
1658 }
14791659
1480 /* Verify that the machine can perform a widening multiply1660 /* Verify that the machine can perform a widening multiply
1481 accumulate in this mode/signedness combination, otherwise1661 accumulate in this mode/signedness combination, otherwise
1482 this transformation is likely to pessimize code. */1662 this transformation is likely to pessimize code. */
1483 this_optab = optab_for_tree_code (wmult_code, type1, optab_default);1663 optype = build_nonstandard_integer_type (from_mode, from_unsigned1);
1484 if (optab_handler (this_optab, TYPE_MODE (type)) == CODE_FOR_nothing)1664 this_optab = optab_for_tree_code (wmult_code, optype, optab_default);
1665 handler = find_widening_optab_handler_and_mode (this_optab, to_mode,
1666 from_mode, 0, &actual_mode);
1667
1668 if (handler == CODE_FOR_nothing)
1485 return false;1669 return false;
14861670
1487 /* ??? May need some type verification here? */1671 /* Ensure that the inputs to the handler are in the correct precison
14881672 for the opcode. This will be the full mode size. */
1489 gimple_assign_set_rhs_with_ops_1 (gsi, wmult_code,1673 actual_precision = GET_MODE_PRECISION (actual_mode);
1490 fold_convert (type1, mult_rhs1),1674 if (actual_precision != TYPE_PRECISION (type1)
1491 fold_convert (type2, mult_rhs2),1675 || from_unsigned1 != TYPE_UNSIGNED (type1))
1676 {
1677 tmp = create_tmp_var (build_nonstandard_integer_type
1678 (actual_precision, from_unsigned1),
1679 NULL);
1680 mult_rhs1 = build_and_insert_cast (gsi, loc, tmp, mult_rhs1);
1681 }
1682 if (actual_precision != TYPE_PRECISION (type2)
1683 || from_unsigned2 != TYPE_UNSIGNED (type2))
1684 {
1685 if (!tmp || from_unsigned1 != from_unsigned2)
1686 tmp = create_tmp_var (build_nonstandard_integer_type
1687 (actual_precision, from_unsigned2),
1688 NULL);
1689 mult_rhs2 = build_and_insert_cast (gsi, loc, tmp, mult_rhs2);
1690 }
1691
1692 if (TYPE_PRECISION (type) != TYPE_PRECISION (TREE_TYPE (add_rhs)))
1693 add_rhs = build_and_insert_cast (gsi, loc, create_tmp_var (type, NULL),
1694 add_rhs);
1695
1696 gimple_assign_set_rhs_with_ops_1 (gsi, wmult_code, mult_rhs1, mult_rhs2,
1492 add_rhs);1697 add_rhs);
1493 update_stmt (gsi_stmt (*gsi));1698 update_stmt (gsi_stmt (*gsi));
1494 return true;1699 return true;
@@ -1696,7 +1901,7 @@
1696 switch (code)1901 switch (code)
1697 {1902 {
1698 case MULT_EXPR:1903 case MULT_EXPR:
1699 if (!convert_mult_to_widen (stmt)1904 if (!convert_mult_to_widen (stmt, &gsi)
1700 && convert_mult_to_fma (stmt,1905 && convert_mult_to_fma (stmt,
1701 gimple_assign_rhs1 (stmt),1906 gimple_assign_rhs1 (stmt),
1702 gimple_assign_rhs2 (stmt)))1907 gimple_assign_rhs2 (stmt)))

Subscribers

People subscribed via source and target branches