diff options
Diffstat (limited to 'toolchain-layer/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99396.patch')
-rw-r--r-- | toolchain-layer/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99396.patch | 1721 |
1 files changed, 0 insertions, 1721 deletions
diff --git a/toolchain-layer/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99396.patch b/toolchain-layer/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99396.patch deleted file mode 100644 index b7eaa685ae..0000000000 --- a/toolchain-layer/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99396.patch +++ /dev/null @@ -1,1721 +0,0 @@ -2010-09-15 Chung-Lin Tang <cltang@codesourcery.com> - - Issue #9441 - - Backport from mainline: - - 2010-06-25 Bernd Schmidt <bernds@codesourcery.com> - - With large parts from Jim Wilson: - PR target/43902 - - gcc/ - * tree-pretty-print.c (dump_generic_node, op_code_prio): Add - WIDEN_MULT_PLUS_EXPR and WIDEN_MULT_MINUS_EXPR. - * optabs.c (optab_for_tree_code): Likewise. - (expand_widen_pattern_expr): Likewise. - * tree-ssa-math-opts.c (convert_mult_to_widen): New function, broken - out of execute_optimize_widening_mul. - (convert_plusminus_to_widen): New function. - (execute_optimize_widening_mul): Use the two new functions. - * expr.c (expand_expr_real_2): Add support for GIMPLE_TERNARY_RHS. - Remove code to generate widening multiply-accumulate. Add support - for WIDEN_MULT_PLUS_EXPR and WIDEN_MULT_MINUS_EXPR. - * gimple-pretty-print.c (dump_ternary_rhs): New function. - (dump_gimple_assign): Call it when appropriate. - * tree.def (WIDEN_MULT_PLUS_EXPR, WIDEN_MULT_MINUS_EXPR): New codes. - * cfgexpand.c (gimple_assign_rhs_to_tree): Likewise. - (expand_gimple_stmt_1): Likewise. - (expand_debug_expr): Support WIDEN_MULT_PLUS_EXPR and - WIDEN_MULT_MINUS_EXPR. - * tree-ssa-operands.c (get_expr_operands): Likewise. - * tree-inline.c (estimate_operator_cost): Likewise. - * gimple.c (extract_ops_from_tree_1): Renamed from - extract_ops_from_tree. Add new arg for a third operand; fill it. - (gimple_build_assign_stat): Support operations with three operands. - (gimple_build_assign_with_ops_stat): Likewise. - (gimple_assign_set_rhs_from_tree): Likewise. - (gimple_assign_set_rhs_with_ops_1): Renamed from - gimple_assign_set_rhs_with_ops. Add new arg for a third operand. - (get_gimple_rhs_num_ops): Support GIMPLE_TERNARY_RHS. - (get_gimple_rhs_num_ops): Handle WIDEN_MULT_PLUS_EXPR and - WIDEN_MULT_MINUS_EXPR. - * gimple.h (enum gimple_rhs_class): Add GIMPLE_TERNARY_RHS. - (extract_ops_from_tree_1): Adjust declaration. - (gimple_assign_set_rhs_with_ops_1): Likewise. - (gimple_build_assign_with_ops): Pass NULL for last operand. - (gimple_build_assign_with_ops3): New macro. - (gimple_assign_rhs3, gimple_assign_rhs3_ptr, gimple_assign_set_rhs3, - gimple_assign_set_rhs_with_ops, extract_ops_from_tree): New inline - functions. - * tree-cfg.c (verify_gimple_assign_ternary): New static function. - (verify_gimple_assign): Call it. - * doc/gimple.texi (Manipulating operands): Document GIMPLE_TERNARY_RHS. - (Tuple specific accessors, subsection GIMPLE_ASSIGN): Document new - functions for dealing with three-operand statements. - * tree.c (commutative_ternary_tree_code): New function. - * tree.h (commutative_ternary_tree_code): Declare it. - * tree-vrp.c (gimple_assign_nonnegative_warnv_p): Return false for - ternary statements. - (gimple_assign_nonzero_warnv_p): Likewise. - * tree-ssa-sccvn.c (stmt_has_constants): Handle GIMPLE_TERNARY_RHS. - * tree-ssa-ccp.c (get_rhs_assign_op_for_ccp): New static function. - (ccp_fold): Use it. Handle GIMPLE_TERNARY_RHS. - * tree-ssa-dom.c (enum expr_kind): Add EXPR_TERNARY. - (struct hashtable_expr): New member ternary in the union. - (initialize_hash_element): Handle GIMPLE_TERNARY_RHS. - (hashable_expr_equal_p): Fix indentation. Handle EXPR_TERNARY. - (iterative_hash_hashable_expr): Likewise. - (print_expr_hash_elt): Handle EXPR_TERNARY. - * gimple-fold.c (fold_gimple_assign): Handle GIMPLE_TERNARY_RHS. - * tree-ssa-threadedge.c (fold_assignment_stmt): Remove useless break - statements. Handle GIMPLE_TERNARY_RHS. - - From Jim Wilson: - gcc/testsuite/ - * gcc.target/mips/madd-9.c: New test. - - 2010-06-29 Bernd Schmidt <bernds@codesourcery.com> - - PR target/43902 - gcc/ - * config/arm/arm.md (maddsidi4, umaddsidi4): New expanders. - (maddhisi4): Renamed from mulhisi3addsi. Operands renumbered. - (maddhidi4): Likewise. - - gcc/testsuite/ - * gcc.target/arm/wmul-1.c: Test for smlabb instead of smulbb. - * gcc.target/arm/wmul-3.c: New test. - * gcc.target/arm/wmul-4.c: New test. - - 2010-07-22 Richard Sandiford <rdsandiford@googlemail.com> - - gcc/ - * tree-ssa-math-opts.c (is_widening_mult_rhs_p): New function. - (is_widening_mult_p): Likewise. - (convert_to_widen): Use them. - (convert_plusminus_to_widen): Likewise. Handle fixed-point types as - well as integer ones. - - 2010-07-31 Richard Sandiford <rdsandiford@googlemail.com> - - gcc/ - * tree-ssa-math-opts.c (convert_plusminus_to_widen): Fix type - used in the call to optab_for_tree_code. Fix the second - is_widening_mult_p call. Check that both unwidened operands - have the same sign. - - 2010-09-15 Jie Zhang <jie@codesourcery.com> - - Backport from mainline: - -=== modified file 'gcc/cfgexpand.c' -Index: gcc-4_5-branch/gcc/cfgexpand.c -=================================================================== ---- gcc-4_5-branch.orig/gcc/cfgexpand.c 2011-07-22 16:59:23.000000000 -0700 -+++ gcc-4_5-branch/gcc/cfgexpand.c 2011-07-22 16:59:28.581747691 -0700 -@@ -64,7 +64,13 @@ - - grhs_class = get_gimple_rhs_class (gimple_expr_code (stmt)); - -- if (grhs_class == GIMPLE_BINARY_RHS) -+ if (grhs_class == GIMPLE_TERNARY_RHS) -+ t = build3 (gimple_assign_rhs_code (stmt), -+ TREE_TYPE (gimple_assign_lhs (stmt)), -+ gimple_assign_rhs1 (stmt), -+ gimple_assign_rhs2 (stmt), -+ gimple_assign_rhs3 (stmt)); -+ else if (grhs_class == GIMPLE_BINARY_RHS) - t = build2 (gimple_assign_rhs_code (stmt), - TREE_TYPE (gimple_assign_lhs (stmt)), - gimple_assign_rhs1 (stmt), -@@ -1893,6 +1899,9 @@ - ops.type = TREE_TYPE (lhs); - switch (get_gimple_rhs_class (gimple_expr_code (stmt))) - { -+ case GIMPLE_TERNARY_RHS: -+ ops.op2 = gimple_assign_rhs3 (stmt); -+ /* Fallthru */ - case GIMPLE_BINARY_RHS: - ops.op1 = gimple_assign_rhs2 (stmt); - /* Fallthru */ -@@ -2243,6 +2252,8 @@ - { - case COND_EXPR: - case DOT_PROD_EXPR: -+ case WIDEN_MULT_PLUS_EXPR: -+ case WIDEN_MULT_MINUS_EXPR: - goto ternary; - - case TRUTH_ANDIF_EXPR: -@@ -3030,6 +3041,8 @@ - return NULL; - - case WIDEN_MULT_EXPR: -+ case WIDEN_MULT_PLUS_EXPR: -+ case WIDEN_MULT_MINUS_EXPR: - if (SCALAR_INT_MODE_P (GET_MODE (op0)) - && SCALAR_INT_MODE_P (mode)) - { -@@ -3042,7 +3055,13 @@ - op1 = simplify_gen_unary (ZERO_EXTEND, mode, op1, inner_mode); - else - op1 = simplify_gen_unary (SIGN_EXTEND, mode, op1, inner_mode); -- return gen_rtx_MULT (mode, op0, op1); -+ op0 = gen_rtx_MULT (mode, op0, op1); -+ if (TREE_CODE (exp) == WIDEN_MULT_EXPR) -+ return op0; -+ else if (TREE_CODE (exp) == WIDEN_MULT_PLUS_EXPR) -+ return gen_rtx_PLUS (mode, op0, op2); -+ else -+ return gen_rtx_MINUS (mode, op2, op0); - } - return NULL; - -Index: gcc-4_5-branch/gcc/config/arm/arm.md -=================================================================== ---- gcc-4_5-branch.orig/gcc/config/arm/arm.md 2011-07-22 16:59:25.000000000 -0700 -+++ gcc-4_5-branch/gcc/config/arm/arm.md 2011-07-22 16:59:28.581747691 -0700 -@@ -1507,7 +1507,15 @@ - (set_attr "predicable" "yes")] - ) - --;; Unnamed template to match long long multiply-accumulate (smlal) -+(define_expand "maddsidi4" -+ [(set (match_operand:DI 0 "s_register_operand" "") -+ (plus:DI -+ (mult:DI -+ (sign_extend:DI (match_operand:SI 1 "s_register_operand" "")) -+ (sign_extend:DI (match_operand:SI 2 "s_register_operand" ""))) -+ (match_operand:DI 3 "s_register_operand" "")))] -+ "TARGET_32BIT && arm_arch3m" -+ "") - - (define_insn "*mulsidi3adddi" - [(set (match_operand:DI 0 "s_register_operand" "=&r") -@@ -1603,7 +1611,15 @@ - (set_attr "predicable" "yes")] - ) - --;; Unnamed template to match long long unsigned multiply-accumulate (umlal) -+(define_expand "umaddsidi4" -+ [(set (match_operand:DI 0 "s_register_operand" "") -+ (plus:DI -+ (mult:DI -+ (zero_extend:DI (match_operand:SI 1 "s_register_operand" "")) -+ (zero_extend:DI (match_operand:SI 2 "s_register_operand" ""))) -+ (match_operand:DI 3 "s_register_operand" "")))] -+ "TARGET_32BIT && arm_arch3m" -+ "") - - (define_insn "*umulsidi3adddi" - [(set (match_operand:DI 0 "s_register_operand" "=&r") -@@ -1771,29 +1787,29 @@ - (set_attr "predicable" "yes")] - ) - --(define_insn "*mulhisi3addsi" -+(define_insn "maddhisi4" - [(set (match_operand:SI 0 "s_register_operand" "=r") -- (plus:SI (match_operand:SI 1 "s_register_operand" "r") -+ (plus:SI (match_operand:SI 3 "s_register_operand" "r") - (mult:SI (sign_extend:SI -- (match_operand:HI 2 "s_register_operand" "%r")) -+ (match_operand:HI 1 "s_register_operand" "%r")) - (sign_extend:SI -- (match_operand:HI 3 "s_register_operand" "r")))))] -+ (match_operand:HI 2 "s_register_operand" "r")))))] - "TARGET_DSP_MULTIPLY" -- "smlabb%?\\t%0, %2, %3, %1" -+ "smlabb%?\\t%0, %1, %2, %3" - [(set_attr "insn" "smlaxy") - (set_attr "predicable" "yes")] - ) - --(define_insn "*mulhidi3adddi" -+(define_insn "*maddhidi4" - [(set (match_operand:DI 0 "s_register_operand" "=r") - (plus:DI -- (match_operand:DI 1 "s_register_operand" "0") -+ (match_operand:DI 3 "s_register_operand" "0") - (mult:DI (sign_extend:DI -- (match_operand:HI 2 "s_register_operand" "%r")) -+ (match_operand:HI 1 "s_register_operand" "%r")) - (sign_extend:DI -- (match_operand:HI 3 "s_register_operand" "r")))))] -+ (match_operand:HI 2 "s_register_operand" "r")))))] - "TARGET_DSP_MULTIPLY" -- "smlalbb%?\\t%Q0, %R0, %2, %3" -+ "smlalbb%?\\t%Q0, %R0, %1, %2" - [(set_attr "insn" "smlalxy") - (set_attr "predicable" "yes")]) - -Index: gcc-4_5-branch/gcc/doc/gimple.texi -=================================================================== ---- gcc-4_5-branch.orig/gcc/doc/gimple.texi 2011-07-22 16:58:48.000000000 -0700 -+++ gcc-4_5-branch/gcc/doc/gimple.texi 2011-07-22 16:59:28.581747691 -0700 -@@ -554,6 +554,9 @@ - @item @code{GIMPLE_INVALID_RHS} - The tree cannot be used as a GIMPLE operand. - -+@item @code{GIMPLE_TERNARY_RHS} -+The tree is a valid GIMPLE ternary operation. -+ - @item @code{GIMPLE_BINARY_RHS} - The tree is a valid GIMPLE binary operation. - -@@ -575,10 +578,11 @@ - expressions should be flattened into the operand vector. - @end itemize - --For tree nodes in the categories @code{GIMPLE_BINARY_RHS} and --@code{GIMPLE_UNARY_RHS}, they cannot be stored inside tuples directly. --They first need to be flattened and separated into individual --components. For instance, given the GENERIC expression -+For tree nodes in the categories @code{GIMPLE_TERNARY_RHS}, -+@code{GIMPLE_BINARY_RHS} and @code{GIMPLE_UNARY_RHS}, they cannot be -+stored inside tuples directly. They first need to be flattened and -+separated into individual components. For instance, given the GENERIC -+expression - - @smallexample - a = b + c -@@ -1082,7 +1086,16 @@ - Return the address of the second operand on the @code{RHS} of assignment - statement @code{G}. - @end deftypefn -+ -+@deftypefn {GIMPLE function} tree gimple_assign_rhs3 (gimple g) -+Return the third operand on the @code{RHS} of assignment statement @code{G}. -+@end deftypefn - -+@deftypefn {GIMPLE function} tree *gimple_assign_rhs3_ptr (gimple g) -+Return the address of the third operand on the @code{RHS} of assignment -+statement @code{G}. -+@end deftypefn -+ - @deftypefn {GIMPLE function} void gimple_assign_set_lhs (gimple g, tree lhs) - Set @code{LHS} to be the @code{LHS} operand of assignment statement @code{G}. - @end deftypefn -@@ -1092,17 +1105,13 @@ - statement @code{G}. - @end deftypefn - --@deftypefn {GIMPLE function} tree gimple_assign_rhs2 (gimple g) --Return the second operand on the @code{RHS} of assignment statement @code{G}. --@end deftypefn -- --@deftypefn {GIMPLE function} tree *gimple_assign_rhs2_ptr (gimple g) --Return a pointer to the second operand on the @code{RHS} of assignment -+@deftypefn {GIMPLE function} void gimple_assign_set_rhs2 (gimple g, tree rhs) -+Set @code{RHS} to be the second operand on the @code{RHS} of assignment - statement @code{G}. - @end deftypefn - --@deftypefn {GIMPLE function} void gimple_assign_set_rhs2 (gimple g, tree rhs) --Set @code{RHS} to be the second operand on the @code{RHS} of assignment -+@deftypefn {GIMPLE function} void gimple_assign_set_rhs3 (gimple g, tree rhs) -+Set @code{RHS} to be the third operand on the @code{RHS} of assignment - statement @code{G}. - @end deftypefn - -Index: gcc-4_5-branch/gcc/expr.c -=================================================================== ---- gcc-4_5-branch.orig/gcc/expr.c 2011-07-22 16:59:23.000000000 -0700 -+++ gcc-4_5-branch/gcc/expr.c 2011-07-22 16:59:28.591747691 -0700 -@@ -7228,8 +7228,6 @@ - rtx subtarget, original_target; - int ignore; - bool reduce_bit_field; -- gimple subexp0_def, subexp1_def; -- tree top0, top1; - location_t loc = ops->location; - tree treeop0, treeop1; - #define REDUCE_BIT_FIELD(expr) (reduce_bit_field \ -@@ -7249,7 +7247,8 @@ - exactly those that are valid in gimple expressions that aren't - GIMPLE_SINGLE_RHS (or invalid). */ - gcc_assert (get_gimple_rhs_class (code) == GIMPLE_UNARY_RHS -- || get_gimple_rhs_class (code) == GIMPLE_BINARY_RHS); -+ || get_gimple_rhs_class (code) == GIMPLE_BINARY_RHS -+ || get_gimple_rhs_class (code) == GIMPLE_TERNARY_RHS); - - ignore = (target == const0_rtx - || ((CONVERT_EXPR_CODE_P (code) -@@ -7424,58 +7423,6 @@ - fold_convert_loc (loc, ssizetype, - treeop1)); - case PLUS_EXPR: -- -- /* Check if this is a case for multiplication and addition. */ -- if ((TREE_CODE (type) == INTEGER_TYPE -- || TREE_CODE (type) == FIXED_POINT_TYPE) -- && (subexp0_def = get_def_for_expr (treeop0, -- MULT_EXPR))) -- { -- tree subsubexp0, subsubexp1; -- gimple subsubexp0_def, subsubexp1_def; -- enum tree_code this_code; -- -- this_code = TREE_CODE (type) == INTEGER_TYPE ? NOP_EXPR -- : FIXED_CONVERT_EXPR; -- subsubexp0 = gimple_assign_rhs1 (subexp0_def); -- subsubexp0_def = get_def_for_expr (subsubexp0, this_code); -- subsubexp1 = gimple_assign_rhs2 (subexp0_def); -- subsubexp1_def = get_def_for_expr (subsubexp1, this_code); -- if (subsubexp0_def && subsubexp1_def -- && (top0 = gimple_assign_rhs1 (subsubexp0_def)) -- && (top1 = gimple_assign_rhs1 (subsubexp1_def)) -- && (TYPE_PRECISION (TREE_TYPE (top0)) -- < TYPE_PRECISION (TREE_TYPE (subsubexp0))) -- && (TYPE_PRECISION (TREE_TYPE (top0)) -- == TYPE_PRECISION (TREE_TYPE (top1))) -- && (TYPE_UNSIGNED (TREE_TYPE (top0)) -- == TYPE_UNSIGNED (TREE_TYPE (top1)))) -- { -- tree op0type = TREE_TYPE (top0); -- enum machine_mode innermode = TYPE_MODE (op0type); -- bool zextend_p = TYPE_UNSIGNED (op0type); -- bool sat_p = TYPE_SATURATING (TREE_TYPE (subsubexp0)); -- if (sat_p == 0) -- this_optab = zextend_p ? umadd_widen_optab : smadd_widen_optab; -- else -- this_optab = zextend_p ? usmadd_widen_optab -- : ssmadd_widen_optab; -- if (mode == GET_MODE_2XWIDER_MODE (innermode) -- && (optab_handler (this_optab, mode)->insn_code -- != CODE_FOR_nothing)) -- { -- expand_operands (top0, top1, NULL_RTX, &op0, &op1, -- EXPAND_NORMAL); -- op2 = expand_expr (treeop1, subtarget, -- VOIDmode, EXPAND_NORMAL); -- temp = expand_ternary_op (mode, this_optab, op0, op1, op2, -- target, unsignedp); -- gcc_assert (temp); -- return REDUCE_BIT_FIELD (temp); -- } -- } -- } -- - /* If we are adding a constant, a VAR_DECL that is sp, fp, or ap, and - something else, make sure we add the register to the constant and - then to the other thing. This case can occur during strength -@@ -7590,57 +7537,6 @@ - return REDUCE_BIT_FIELD (simplify_gen_binary (PLUS, mode, op0, op1)); - - case MINUS_EXPR: -- /* Check if this is a case for multiplication and subtraction. */ -- if ((TREE_CODE (type) == INTEGER_TYPE -- || TREE_CODE (type) == FIXED_POINT_TYPE) -- && (subexp1_def = get_def_for_expr (treeop1, -- MULT_EXPR))) -- { -- tree subsubexp0, subsubexp1; -- gimple subsubexp0_def, subsubexp1_def; -- enum tree_code this_code; -- -- this_code = TREE_CODE (type) == INTEGER_TYPE ? NOP_EXPR -- : FIXED_CONVERT_EXPR; -- subsubexp0 = gimple_assign_rhs1 (subexp1_def); -- subsubexp0_def = get_def_for_expr (subsubexp0, this_code); -- subsubexp1 = gimple_assign_rhs2 (subexp1_def); -- subsubexp1_def = get_def_for_expr (subsubexp1, this_code); -- if (subsubexp0_def && subsubexp1_def -- && (top0 = gimple_assign_rhs1 (subsubexp0_def)) -- && (top1 = gimple_assign_rhs1 (subsubexp1_def)) -- && (TYPE_PRECISION (TREE_TYPE (top0)) -- < TYPE_PRECISION (TREE_TYPE (subsubexp0))) -- && (TYPE_PRECISION (TREE_TYPE (top0)) -- == TYPE_PRECISION (TREE_TYPE (top1))) -- && (TYPE_UNSIGNED (TREE_TYPE (top0)) -- == TYPE_UNSIGNED (TREE_TYPE (top1)))) -- { -- tree op0type = TREE_TYPE (top0); -- enum machine_mode innermode = TYPE_MODE (op0type); -- bool zextend_p = TYPE_UNSIGNED (op0type); -- bool sat_p = TYPE_SATURATING (TREE_TYPE (subsubexp0)); -- if (sat_p == 0) -- this_optab = zextend_p ? umsub_widen_optab : smsub_widen_optab; -- else -- this_optab = zextend_p ? usmsub_widen_optab -- : ssmsub_widen_optab; -- if (mode == GET_MODE_2XWIDER_MODE (innermode) -- && (optab_handler (this_optab, mode)->insn_code -- != CODE_FOR_nothing)) -- { -- expand_operands (top0, top1, NULL_RTX, &op0, &op1, -- EXPAND_NORMAL); -- op2 = expand_expr (treeop0, subtarget, -- VOIDmode, EXPAND_NORMAL); -- temp = expand_ternary_op (mode, this_optab, op0, op1, op2, -- target, unsignedp); -- gcc_assert (temp); -- return REDUCE_BIT_FIELD (temp); -- } -- } -- } -- - /* For initializers, we are allowed to return a MINUS of two - symbolic constants. Here we handle all cases when both operands - are constant. */ -@@ -7681,6 +7577,14 @@ - - goto binop2; - -+ case WIDEN_MULT_PLUS_EXPR: -+ case WIDEN_MULT_MINUS_EXPR: -+ expand_operands (treeop0, treeop1, NULL_RTX, &op0, &op1, EXPAND_NORMAL); -+ op2 = expand_normal (ops->op2); -+ target = expand_widen_pattern_expr (ops, op0, op1, op2, -+ target, unsignedp); -+ return target; -+ - case WIDEN_MULT_EXPR: - /* If first operand is constant, swap them. - Thus the following special case checks need only -Index: gcc-4_5-branch/gcc/gimple-pretty-print.c -=================================================================== ---- gcc-4_5-branch.orig/gcc/gimple-pretty-print.c 2011-07-22 16:58:48.000000000 -0700 -+++ gcc-4_5-branch/gcc/gimple-pretty-print.c 2011-07-22 16:59:28.591747691 -0700 -@@ -376,6 +376,34 @@ - } - } - -+/* Helper for dump_gimple_assign. Print the ternary RHS of the -+ assignment GS. BUFFER, SPC and FLAGS are as in dump_gimple_stmt. */ -+ -+static void -+dump_ternary_rhs (pretty_printer *buffer, gimple gs, int spc, int flags) -+{ -+ const char *p; -+ enum tree_code code = gimple_assign_rhs_code (gs); -+ switch (code) -+ { -+ case WIDEN_MULT_PLUS_EXPR: -+ case WIDEN_MULT_MINUS_EXPR: -+ for (p = tree_code_name [(int) code]; *p; p++) -+ pp_character (buffer, TOUPPER (*p)); -+ pp_string (buffer, " <"); -+ dump_generic_node (buffer, gimple_assign_rhs1 (gs), spc, flags, false); -+ pp_string (buffer, ", "); -+ dump_generic_node (buffer, gimple_assign_rhs2 (gs), spc, flags, false); -+ pp_string (buffer, ", "); -+ dump_generic_node (buffer, gimple_assign_rhs3 (gs), spc, flags, false); -+ pp_character (buffer, '>'); -+ break; -+ -+ default: -+ gcc_unreachable (); -+ } -+} -+ - - /* Dump the gimple assignment GS. BUFFER, SPC and FLAGS are as in - dump_gimple_stmt. */ -@@ -418,6 +446,8 @@ - dump_unary_rhs (buffer, gs, spc, flags); - else if (gimple_num_ops (gs) == 3) - dump_binary_rhs (buffer, gs, spc, flags); -+ else if (gimple_num_ops (gs) == 4) -+ dump_ternary_rhs (buffer, gs, spc, flags); - else - gcc_unreachable (); - if (!(flags & TDF_RHS_ONLY)) -Index: gcc-4_5-branch/gcc/gimple.c -=================================================================== ---- gcc-4_5-branch.orig/gcc/gimple.c 2011-07-22 16:59:25.000000000 -0700 -+++ gcc-4_5-branch/gcc/gimple.c 2011-07-22 16:59:28.591747691 -0700 -@@ -289,31 +289,40 @@ - - - /* Extract the operands and code for expression EXPR into *SUBCODE_P, -- *OP1_P and *OP2_P respectively. */ -+ *OP1_P, *OP2_P and *OP3_P respectively. */ - - void --extract_ops_from_tree (tree expr, enum tree_code *subcode_p, tree *op1_p, -- tree *op2_p) -+extract_ops_from_tree_1 (tree expr, enum tree_code *subcode_p, tree *op1_p, -+ tree *op2_p, tree *op3_p) - { - enum gimple_rhs_class grhs_class; - - *subcode_p = TREE_CODE (expr); - grhs_class = get_gimple_rhs_class (*subcode_p); - -- if (grhs_class == GIMPLE_BINARY_RHS) -+ if (grhs_class == GIMPLE_TERNARY_RHS) - { - *op1_p = TREE_OPERAND (expr, 0); - *op2_p = TREE_OPERAND (expr, 1); -+ *op3_p = TREE_OPERAND (expr, 2); -+ } -+ else if (grhs_class == GIMPLE_BINARY_RHS) -+ { -+ *op1_p = TREE_OPERAND (expr, 0); -+ *op2_p = TREE_OPERAND (expr, 1); -+ *op3_p = NULL_TREE; - } - else if (grhs_class == GIMPLE_UNARY_RHS) - { - *op1_p = TREE_OPERAND (expr, 0); - *op2_p = NULL_TREE; -+ *op3_p = NULL_TREE; - } - else if (grhs_class == GIMPLE_SINGLE_RHS) - { - *op1_p = expr; - *op2_p = NULL_TREE; -+ *op3_p = NULL_TREE; - } - else - gcc_unreachable (); -@@ -329,10 +338,10 @@ - gimple_build_assign_stat (tree lhs, tree rhs MEM_STAT_DECL) - { - enum tree_code subcode; -- tree op1, op2; -+ tree op1, op2, op3; - -- extract_ops_from_tree (rhs, &subcode, &op1, &op2); -- return gimple_build_assign_with_ops_stat (subcode, lhs, op1, op2 -+ extract_ops_from_tree_1 (rhs, &subcode, &op1, &op2, &op3); -+ return gimple_build_assign_with_ops_stat (subcode, lhs, op1, op2, op3 - PASS_MEM_STAT); - } - -@@ -343,7 +352,7 @@ - - gimple - gimple_build_assign_with_ops_stat (enum tree_code subcode, tree lhs, tree op1, -- tree op2 MEM_STAT_DECL) -+ tree op2, tree op3 MEM_STAT_DECL) - { - unsigned num_ops; - gimple p; -@@ -362,6 +371,12 @@ - gimple_assign_set_rhs2 (p, op2); - } - -+ if (op3) -+ { -+ gcc_assert (num_ops > 3); -+ gimple_assign_set_rhs3 (p, op3); -+ } -+ - return p; - } - -@@ -1860,22 +1875,22 @@ - gimple_assign_set_rhs_from_tree (gimple_stmt_iterator *gsi, tree expr) - { - enum tree_code subcode; -- tree op1, op2; -+ tree op1, op2, op3; - -- extract_ops_from_tree (expr, &subcode, &op1, &op2); -- gimple_assign_set_rhs_with_ops (gsi, subcode, op1, op2); -+ extract_ops_from_tree_1 (expr, &subcode, &op1, &op2, &op3); -+ gimple_assign_set_rhs_with_ops_1 (gsi, subcode, op1, op2, op3); - } - - - /* Set the RHS of assignment statement pointed-to by GSI to CODE with -- operands OP1 and OP2. -+ operands OP1, OP2 and OP3. - - NOTE: The statement pointed-to by GSI may be reallocated if it - did not have enough operand slots. */ - - void --gimple_assign_set_rhs_with_ops (gimple_stmt_iterator *gsi, enum tree_code code, -- tree op1, tree op2) -+gimple_assign_set_rhs_with_ops_1 (gimple_stmt_iterator *gsi, enum tree_code code, -+ tree op1, tree op2, tree op3) - { - unsigned new_rhs_ops = get_gimple_rhs_num_ops (code); - gimple stmt = gsi_stmt (*gsi); -@@ -1899,6 +1914,8 @@ - gimple_assign_set_rhs1 (stmt, op1); - if (new_rhs_ops > 1) - gimple_assign_set_rhs2 (stmt, op2); -+ if (new_rhs_ops > 2) -+ gimple_assign_set_rhs3 (stmt, op3); - } - - -@@ -2378,6 +2395,8 @@ - return 1; - else if (rhs_class == GIMPLE_BINARY_RHS) - return 2; -+ else if (rhs_class == GIMPLE_TERNARY_RHS) -+ return 3; - else - gcc_unreachable (); - } -@@ -2394,6 +2413,8 @@ - || (SYM) == TRUTH_OR_EXPR \ - || (SYM) == TRUTH_XOR_EXPR) ? GIMPLE_BINARY_RHS \ - : (SYM) == TRUTH_NOT_EXPR ? GIMPLE_UNARY_RHS \ -+ : ((SYM) == WIDEN_MULT_PLUS_EXPR \ -+ || (SYM) == WIDEN_MULT_MINUS_EXPR) ? GIMPLE_TERNARY_RHS \ - : ((SYM) == COND_EXPR \ - || (SYM) == CONSTRUCTOR \ - || (SYM) == OBJ_TYPE_REF \ -Index: gcc-4_5-branch/gcc/gimple.h -=================================================================== ---- gcc-4_5-branch.orig/gcc/gimple.h 2011-07-22 16:59:12.000000000 -0700 -+++ gcc-4_5-branch/gcc/gimple.h 2011-07-22 16:59:28.591747691 -0700 -@@ -80,6 +80,7 @@ - enum gimple_rhs_class - { - GIMPLE_INVALID_RHS, /* The expression cannot be used on the RHS. */ -+ GIMPLE_TERNARY_RHS, /* The expression is a ternary operation. */ - GIMPLE_BINARY_RHS, /* The expression is a binary operation. */ - GIMPLE_UNARY_RHS, /* The expression is a unary operation. */ - GIMPLE_SINGLE_RHS /* The expression is a single object (an SSA -@@ -786,12 +787,14 @@ - gimple gimple_build_assign_stat (tree, tree MEM_STAT_DECL); - #define gimple_build_assign(l,r) gimple_build_assign_stat (l, r MEM_STAT_INFO) - --void extract_ops_from_tree (tree, enum tree_code *, tree *, tree *); -+void extract_ops_from_tree_1 (tree, enum tree_code *, tree *, tree *, tree *); - - gimple gimple_build_assign_with_ops_stat (enum tree_code, tree, tree, -- tree MEM_STAT_DECL); --#define gimple_build_assign_with_ops(c,o1,o2,o3) \ -- gimple_build_assign_with_ops_stat (c, o1, o2, o3 MEM_STAT_INFO) -+ tree, tree MEM_STAT_DECL); -+#define gimple_build_assign_with_ops(c,o1,o2,o3) \ -+ gimple_build_assign_with_ops_stat (c, o1, o2, o3, NULL_TREE MEM_STAT_INFO) -+#define gimple_build_assign_with_ops3(c,o1,o2,o3,o4) \ -+ gimple_build_assign_with_ops_stat (c, o1, o2, o3, o4 MEM_STAT_INFO) - - gimple gimple_build_debug_bind_stat (tree, tree, gimple MEM_STAT_DECL); - #define gimple_build_debug_bind(var,val,stmt) \ -@@ -850,8 +853,8 @@ - bool gimple_assign_unary_nop_p (gimple); - void gimple_set_bb (gimple, struct basic_block_def *); - void gimple_assign_set_rhs_from_tree (gimple_stmt_iterator *, tree); --void gimple_assign_set_rhs_with_ops (gimple_stmt_iterator *, enum tree_code, -- tree, tree); -+void gimple_assign_set_rhs_with_ops_1 (gimple_stmt_iterator *, enum tree_code, -+ tree, tree, tree); - tree gimple_get_lhs (const_gimple); - void gimple_set_lhs (gimple, tree); - void gimple_replace_lhs (gimple, tree); -@@ -1793,6 +1796,63 @@ - gimple_set_op (gs, 2, rhs); - } - -+/* Return the third operand on the RHS of assignment statement GS. -+ If GS does not have two operands, NULL is returned instead. */ -+ -+static inline tree -+gimple_assign_rhs3 (const_gimple gs) -+{ -+ GIMPLE_CHECK (gs, GIMPLE_ASSIGN); -+ -+ if (gimple_num_ops (gs) >= 4) -+ return gimple_op (gs, 3); -+ else -+ return NULL_TREE; -+} -+ -+/* Return a pointer to the third operand on the RHS of assignment -+ statement GS. */ -+ -+static inline tree * -+gimple_assign_rhs3_ptr (const_gimple gs) -+{ -+ GIMPLE_CHECK (gs, GIMPLE_ASSIGN); -+ return gimple_op_ptr (gs, 3); -+} -+ -+ -+/* Set RHS to be the third operand on the RHS of assignment statement GS. */ -+ -+static inline void -+gimple_assign_set_rhs3 (gimple gs, tree rhs) -+{ -+ GIMPLE_CHECK (gs, GIMPLE_ASSIGN); -+ -+ gimple_set_op (gs, 3, rhs); -+} -+ -+/* A wrapper around gimple_assign_set_rhs_with_ops_1, for callers which expect -+ to see only a maximum of two operands. */ -+ -+static inline void -+gimple_assign_set_rhs_with_ops (gimple_stmt_iterator *gsi, enum tree_code code, -+ tree op1, tree op2) -+{ -+ gimple_assign_set_rhs_with_ops_1 (gsi, code, op1, op2, NULL); -+} -+ -+/* A wrapper around extract_ops_from_tree_1, for callers which expect -+ to see only a maximum of two operands. */ -+ -+static inline void -+extract_ops_from_tree (tree expr, enum tree_code *code, tree *op0, -+ tree *op1) -+{ -+ tree op2; -+ extract_ops_from_tree_1 (expr, code, op0, op1, &op2); -+ gcc_assert (op2 == NULL_TREE); -+} -+ - /* Returns true if GS is a nontemporal move. */ - - static inline bool -Index: gcc-4_5-branch/gcc/optabs.c -=================================================================== ---- gcc-4_5-branch.orig/gcc/optabs.c 2011-07-22 16:58:48.000000000 -0700 -+++ gcc-4_5-branch/gcc/optabs.c 2011-07-22 16:59:28.601747691 -0700 -@@ -408,6 +408,20 @@ - case DOT_PROD_EXPR: - return TYPE_UNSIGNED (type) ? udot_prod_optab : sdot_prod_optab; - -+ case WIDEN_MULT_PLUS_EXPR: -+ return (TYPE_UNSIGNED (type) -+ ? (TYPE_SATURATING (type) -+ ? usmadd_widen_optab : umadd_widen_optab) -+ : (TYPE_SATURATING (type) -+ ? ssmadd_widen_optab : smadd_widen_optab)); -+ -+ case WIDEN_MULT_MINUS_EXPR: -+ return (TYPE_UNSIGNED (type) -+ ? (TYPE_SATURATING (type) -+ ? usmsub_widen_optab : umsub_widen_optab) -+ : (TYPE_SATURATING (type) -+ ? ssmsub_widen_optab : smsub_widen_optab)); -+ - case REDUC_MAX_EXPR: - return TYPE_UNSIGNED (type) ? reduc_umax_optab : reduc_smax_optab; - -@@ -547,7 +561,12 @@ - tmode0 = TYPE_MODE (TREE_TYPE (oprnd0)); - widen_pattern_optab = - optab_for_tree_code (ops->code, TREE_TYPE (oprnd0), optab_default); -- icode = (int) optab_handler (widen_pattern_optab, tmode0)->insn_code; -+ if (ops->code == WIDEN_MULT_PLUS_EXPR -+ || ops->code == WIDEN_MULT_MINUS_EXPR) -+ icode = (int) optab_handler (widen_pattern_optab, -+ TYPE_MODE (TREE_TYPE (ops->op2)))->insn_code; -+ else -+ icode = (int) optab_handler (widen_pattern_optab, tmode0)->insn_code; - gcc_assert (icode != CODE_FOR_nothing); - xmode0 = insn_data[icode].operand[1].mode; - -Index: gcc-4_5-branch/gcc/testsuite/gcc.target/arm/wmul-1.c -=================================================================== ---- gcc-4_5-branch.orig/gcc/testsuite/gcc.target/arm/wmul-1.c 2011-07-22 16:59:24.000000000 -0700 -+++ gcc-4_5-branch/gcc/testsuite/gcc.target/arm/wmul-1.c 2011-07-22 16:59:28.601747691 -0700 -@@ -15,4 +15,4 @@ - return sqr; - } - --/* { dg-final { scan-assembler-times "smulbb" 2 } } */ -+/* { dg-final { scan-assembler-times "smlabb" 2 } } */ -Index: gcc-4_5-branch/gcc/tree-cfg.c -=================================================================== ---- gcc-4_5-branch.orig/gcc/tree-cfg.c 2011-07-22 16:59:24.000000000 -0700 -+++ gcc-4_5-branch/gcc/tree-cfg.c 2011-07-22 16:59:28.601747691 -0700 -@@ -3484,6 +3484,65 @@ - return false; - } - -+/* Verify a gimple assignment statement STMT with a ternary rhs. -+ Returns true if anything is wrong. */ -+ -+static bool -+verify_gimple_assign_ternary (gimple stmt) -+{ -+ enum tree_code rhs_code = gimple_assign_rhs_code (stmt); -+ tree lhs = gimple_assign_lhs (stmt); -+ tree lhs_type = TREE_TYPE (lhs); -+ tree rhs1 = gimple_assign_rhs1 (stmt); -+ tree rhs1_type = TREE_TYPE (rhs1); -+ tree rhs2 = gimple_assign_rhs2 (stmt); -+ tree rhs2_type = TREE_TYPE (rhs2); -+ tree rhs3 = gimple_assign_rhs3 (stmt); -+ tree rhs3_type = TREE_TYPE (rhs3); -+ -+ if (!is_gimple_reg (lhs) -+ && !(optimize == 0 -+ && TREE_CODE (lhs_type) == COMPLEX_TYPE)) -+ { -+ error ("non-register as LHS of ternary operation"); -+ return true; -+ } -+ -+ if (!is_gimple_val (rhs1) -+ || !is_gimple_val (rhs2) -+ || !is_gimple_val (rhs3)) -+ { -+ error ("invalid operands in ternary operation"); -+ return true; -+ } -+ -+ /* First handle operations that involve different types. */ -+ switch (rhs_code) -+ { -+ case WIDEN_MULT_PLUS_EXPR: -+ case WIDEN_MULT_MINUS_EXPR: -+ if ((!INTEGRAL_TYPE_P (rhs1_type) -+ && !FIXED_POINT_TYPE_P (rhs1_type)) -+ || !useless_type_conversion_p (rhs1_type, rhs2_type) -+ || !useless_type_conversion_p (lhs_type, rhs3_type) -+ || 2 * TYPE_PRECISION (rhs1_type) != TYPE_PRECISION (lhs_type) -+ || TYPE_PRECISION (rhs1_type) != TYPE_PRECISION (rhs2_type)) -+ { -+ error ("type mismatch in widening multiply-accumulate expression"); -+ debug_generic_expr (lhs_type); -+ debug_generic_expr (rhs1_type); -+ debug_generic_expr (rhs2_type); -+ debug_generic_expr (rhs3_type); -+ return true; -+ } -+ break; -+ -+ default: -+ gcc_unreachable (); -+ } -+ return false; -+} -+ - /* Verify a gimple assignment statement STMT with a single rhs. - Returns true if anything is wrong. */ - -@@ -3616,6 +3675,9 @@ - case GIMPLE_BINARY_RHS: - return verify_gimple_assign_binary (stmt); - -+ case GIMPLE_TERNARY_RHS: -+ return verify_gimple_assign_ternary (stmt); -+ - default: - gcc_unreachable (); - } -Index: gcc-4_5-branch/gcc/tree-inline.c -=================================================================== ---- gcc-4_5-branch.orig/gcc/tree-inline.c 2011-07-22 16:59:24.000000000 -0700 -+++ gcc-4_5-branch/gcc/tree-inline.c 2011-07-22 16:59:28.601747691 -0700 -@@ -3207,6 +3207,8 @@ - case WIDEN_SUM_EXPR: - case WIDEN_MULT_EXPR: - case DOT_PROD_EXPR: -+ case WIDEN_MULT_PLUS_EXPR: -+ case WIDEN_MULT_MINUS_EXPR: - - case VEC_WIDEN_MULT_HI_EXPR: - case VEC_WIDEN_MULT_LO_EXPR: -Index: gcc-4_5-branch/gcc/tree-pretty-print.c -=================================================================== ---- gcc-4_5-branch.orig/gcc/tree-pretty-print.c 2011-07-22 16:58:48.000000000 -0700 -+++ gcc-4_5-branch/gcc/tree-pretty-print.c 2011-07-22 16:59:28.611747691 -0700 -@@ -1939,6 +1939,26 @@ - pp_string (buffer, " > "); - break; - -+ case WIDEN_MULT_PLUS_EXPR: -+ pp_string (buffer, " WIDEN_MULT_PLUS_EXPR < "); -+ dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); -+ pp_string (buffer, ", "); -+ dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false); -+ pp_string (buffer, ", "); -+ dump_generic_node (buffer, TREE_OPERAND (node, 2), spc, flags, false); -+ pp_string (buffer, " > "); -+ break; -+ -+ case WIDEN_MULT_MINUS_EXPR: -+ pp_string (buffer, " WIDEN_MULT_MINUS_EXPR < "); -+ dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); -+ pp_string (buffer, ", "); -+ dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false); -+ pp_string (buffer, ", "); -+ dump_generic_node (buffer, TREE_OPERAND (node, 2), spc, flags, false); -+ pp_string (buffer, " > "); -+ break; -+ - case OMP_PARALLEL: - pp_string (buffer, "#pragma omp parallel"); - dump_omp_clauses (buffer, OMP_PARALLEL_CLAUSES (node), spc, flags); -@@ -2432,6 +2452,8 @@ - case VEC_WIDEN_MULT_LO_EXPR: - case WIDEN_MULT_EXPR: - case DOT_PROD_EXPR: -+ case WIDEN_MULT_PLUS_EXPR: -+ case WIDEN_MULT_MINUS_EXPR: - case MULT_EXPR: - case TRUNC_DIV_EXPR: - case CEIL_DIV_EXPR: -Index: gcc-4_5-branch/gcc/tree-ssa-ccp.c -=================================================================== ---- gcc-4_5-branch.orig/gcc/tree-ssa-ccp.c 2011-07-22 16:59:12.000000000 -0700 -+++ gcc-4_5-branch/gcc/tree-ssa-ccp.c 2011-07-22 16:59:28.611747691 -0700 -@@ -915,6 +915,23 @@ - TREE_TYPE (TREE_OPERAND (addr, 0)))); - } - -+/* Get operand number OPNR from the rhs of STMT. Before returning it, -+ simplify it to a constant if possible. */ -+ -+static tree -+get_rhs_assign_op_for_ccp (gimple stmt, int opnr) -+{ -+ tree op = gimple_op (stmt, opnr); -+ -+ if (TREE_CODE (op) == SSA_NAME) -+ { -+ prop_value_t *val = get_value (op); -+ if (val->lattice_val == CONSTANT) -+ op = get_value (op)->value; -+ } -+ return op; -+} -+ - /* CCP specific front-end to the non-destructive constant folding - routines. - -@@ -1037,15 +1054,7 @@ - Note that we know the single operand must be a constant, - so this should almost always return a simplified RHS. */ - tree lhs = gimple_assign_lhs (stmt); -- tree op0 = gimple_assign_rhs1 (stmt); -- -- /* Simplify the operand down to a constant. */ -- if (TREE_CODE (op0) == SSA_NAME) -- { -- prop_value_t *val = get_value (op0); -- if (val->lattice_val == CONSTANT) -- op0 = get_value (op0)->value; -- } -+ tree op0 = get_rhs_assign_op_for_ccp (stmt, 1); - - /* Conversions are useless for CCP purposes if they are - value-preserving. Thus the restrictions that -@@ -1082,23 +1091,8 @@ - case GIMPLE_BINARY_RHS: - { - /* Handle binary operators that can appear in GIMPLE form. */ -- tree op0 = gimple_assign_rhs1 (stmt); -- tree op1 = gimple_assign_rhs2 (stmt); -- -- /* Simplify the operands down to constants when appropriate. */ -- if (TREE_CODE (op0) == SSA_NAME) -- { -- prop_value_t *val = get_value (op0); -- if (val->lattice_val == CONSTANT) -- op0 = val->value; -- } -- -- if (TREE_CODE (op1) == SSA_NAME) -- { -- prop_value_t *val = get_value (op1); -- if (val->lattice_val == CONSTANT) -- op1 = val->value; -- } -+ tree op0 = get_rhs_assign_op_for_ccp (stmt, 1); -+ tree op1 = get_rhs_assign_op_for_ccp (stmt, 2); - - /* Fold &foo + CST into an invariant reference if possible. */ - if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR -@@ -1115,6 +1109,17 @@ - gimple_expr_type (stmt), op0, op1); - } - -+ case GIMPLE_TERNARY_RHS: -+ { -+ /* Handle binary operators that can appear in GIMPLE form. */ -+ tree op0 = get_rhs_assign_op_for_ccp (stmt, 1); -+ tree op1 = get_rhs_assign_op_for_ccp (stmt, 2); -+ tree op2 = get_rhs_assign_op_for_ccp (stmt, 3); -+ -+ return fold_ternary_loc (loc, subcode, -+ gimple_expr_type (stmt), op0, op1, op2); -+ } -+ - default: - gcc_unreachable (); - } -@@ -2959,6 +2964,33 @@ - } - break; - -+ case GIMPLE_TERNARY_RHS: -+ result = fold_ternary_loc (loc, subcode, -+ TREE_TYPE (gimple_assign_lhs (stmt)), -+ gimple_assign_rhs1 (stmt), -+ gimple_assign_rhs2 (stmt), -+ gimple_assign_rhs3 (stmt)); -+ -+ if (result) -+ { -+ STRIP_USELESS_TYPE_CONVERSION (result); -+ if (valid_gimple_rhs_p (result)) -+ return result; -+ -+ /* Fold might have produced non-GIMPLE, so if we trust it blindly -+ we lose canonicalization opportunities. Do not go again -+ through fold here though, or the same non-GIMPLE will be -+ produced. */ -+ if (commutative_ternary_tree_code (subcode) -+ && tree_swap_operands_p (gimple_assign_rhs1 (stmt), -+ gimple_assign_rhs2 (stmt), false)) -+ return build3 (subcode, TREE_TYPE (gimple_assign_lhs (stmt)), -+ gimple_assign_rhs2 (stmt), -+ gimple_assign_rhs1 (stmt), -+ gimple_assign_rhs3 (stmt)); -+ } -+ break; -+ - case GIMPLE_INVALID_RHS: - gcc_unreachable (); - } -Index: gcc-4_5-branch/gcc/tree-ssa-dom.c -=================================================================== ---- gcc-4_5-branch.orig/gcc/tree-ssa-dom.c 2011-07-22 16:58:48.000000000 -0700 -+++ gcc-4_5-branch/gcc/tree-ssa-dom.c 2011-07-22 17:23:51.501747355 -0700 -@@ -54,6 +54,7 @@ - EXPR_SINGLE, - EXPR_UNARY, - EXPR_BINARY, -+ EXPR_TERNARY, - EXPR_CALL - }; - -@@ -64,7 +65,8 @@ - union { - struct { tree rhs; } single; - struct { enum tree_code op; tree opnd; } unary; -- struct { enum tree_code op; tree opnd0; tree opnd1; } binary; -+ struct { enum tree_code op; tree opnd0, opnd1; } binary; -+ struct { enum tree_code op; tree opnd0, opnd1, opnd2; } ternary; - struct { tree fn; bool pure; size_t nargs; tree *args; } call; - } ops; - }; -@@ -229,6 +231,14 @@ - expr->ops.binary.opnd0 = gimple_assign_rhs1 (stmt); - expr->ops.binary.opnd1 = gimple_assign_rhs2 (stmt); - break; -+ case GIMPLE_TERNARY_RHS: -+ expr->kind = EXPR_TERNARY; -+ expr->type = TREE_TYPE (gimple_assign_lhs (stmt)); -+ expr->ops.ternary.op = subcode; -+ expr->ops.ternary.opnd0 = gimple_assign_rhs1 (stmt); -+ expr->ops.ternary.opnd1 = gimple_assign_rhs2 (stmt); -+ expr->ops.ternary.opnd2 = gimple_assign_rhs3 (stmt); -+ break; - default: - gcc_unreachable (); - } -@@ -373,23 +383,40 @@ - expr1->ops.unary.opnd, 0); - - case EXPR_BINARY: -- { -- if (expr0->ops.binary.op != expr1->ops.binary.op) -- return false; -+ if (expr0->ops.binary.op != expr1->ops.binary.op) -+ return false; - -- if (operand_equal_p (expr0->ops.binary.opnd0, -- expr1->ops.binary.opnd0, 0) -- && operand_equal_p (expr0->ops.binary.opnd1, -- expr1->ops.binary.opnd1, 0)) -- return true; -- -- /* For commutative ops, allow the other order. */ -- return (commutative_tree_code (expr0->ops.binary.op) -- && operand_equal_p (expr0->ops.binary.opnd0, -- expr1->ops.binary.opnd1, 0) -- && operand_equal_p (expr0->ops.binary.opnd1, -- expr1->ops.binary.opnd0, 0)); -- } -+ if (operand_equal_p (expr0->ops.binary.opnd0, -+ expr1->ops.binary.opnd0, 0) -+ && operand_equal_p (expr0->ops.binary.opnd1, -+ expr1->ops.binary.opnd1, 0)) -+ return true; -+ -+ /* For commutative ops, allow the other order. */ -+ return (commutative_tree_code (expr0->ops.binary.op) -+ && operand_equal_p (expr0->ops.binary.opnd0, -+ expr1->ops.binary.opnd1, 0) -+ && operand_equal_p (expr0->ops.binary.opnd1, -+ expr1->ops.binary.opnd0, 0)); -+ -+ case EXPR_TERNARY: -+ if (expr0->ops.ternary.op != expr1->ops.ternary.op -+ || !operand_equal_p (expr0->ops.ternary.opnd2, -+ expr1->ops.ternary.opnd2, 0)) -+ return false; -+ -+ if (operand_equal_p (expr0->ops.ternary.opnd0, -+ expr1->ops.ternary.opnd0, 0) -+ && operand_equal_p (expr0->ops.ternary.opnd1, -+ expr1->ops.ternary.opnd1, 0)) -+ return true; -+ -+ /* For commutative ops, allow the other order. */ -+ return (commutative_ternary_tree_code (expr0->ops.ternary.op) -+ && operand_equal_p (expr0->ops.ternary.opnd0, -+ expr1->ops.ternary.opnd1, 0) -+ && operand_equal_p (expr0->ops.ternary.opnd1, -+ expr1->ops.ternary.opnd0, 0)); - - case EXPR_CALL: - { -@@ -452,8 +479,8 @@ - case EXPR_BINARY: - val = iterative_hash_object (expr->ops.binary.op, val); - if (commutative_tree_code (expr->ops.binary.op)) -- val = iterative_hash_exprs_commutative (expr->ops.binary.opnd0, -- expr->ops.binary.opnd1, val); -+ val = iterative_hash_exprs_commutative (expr->ops.binary.opnd0, -+ expr->ops.binary.opnd1, val); - else - { - val = iterative_hash_expr (expr->ops.binary.opnd0, val); -@@ -461,6 +488,19 @@ - } - break; - -+ case EXPR_TERNARY: -+ val = iterative_hash_object (expr->ops.ternary.op, val); -+ if (commutative_ternary_tree_code (expr->ops.ternary.op)) -+ val = iterative_hash_exprs_commutative (expr->ops.ternary.opnd0, -+ expr->ops.ternary.opnd1, val); -+ else -+ { -+ val = iterative_hash_expr (expr->ops.ternary.opnd0, val); -+ val = iterative_hash_expr (expr->ops.ternary.opnd1, val); -+ } -+ val = iterative_hash_expr (expr->ops.ternary.opnd2, val); -+ break; -+ - case EXPR_CALL: - { - size_t i; -@@ -513,6 +553,16 @@ - print_generic_expr (stream, element->expr.ops.binary.opnd1, 0); - break; - -+ case EXPR_TERNARY: -+ fprintf (stream, " %s <", tree_code_name[element->expr.ops.ternary.op]); -+ print_generic_expr (stream, element->expr.ops.ternary.opnd0, 0); -+ fputs (", ", stream); -+ print_generic_expr (stream, element->expr.ops.ternary.opnd1, 0); -+ fputs (", ", stream); -+ print_generic_expr (stream, element->expr.ops.ternary.opnd2, 0); -+ fputs (">", stream); -+ break; -+ - case EXPR_CALL: - { - size_t i; -Index: gcc-4_5-branch/gcc/tree-ssa-math-opts.c -=================================================================== ---- gcc-4_5-branch.orig/gcc/tree-ssa-math-opts.c 2011-07-22 16:59:24.000000000 -0700 -+++ gcc-4_5-branch/gcc/tree-ssa-math-opts.c 2011-07-22 16:59:28.611747691 -0700 -@@ -1270,6 +1270,235 @@ - } - }; - -+/* Return true if RHS is a suitable operand for a widening multiplication. -+ There are two cases: -+ -+ - RHS makes some value twice as wide. Store that value in *NEW_RHS_OUT -+ if so, and store its type in *TYPE_OUT. -+ -+ - RHS is an integer constant. Store that value in *NEW_RHS_OUT if so, -+ but leave *TYPE_OUT untouched. */ -+ -+static bool -+is_widening_mult_rhs_p (tree rhs, tree *type_out, tree *new_rhs_out) -+{ -+ gimple stmt; -+ tree type, type1, rhs1; -+ enum tree_code rhs_code; -+ -+ if (TREE_CODE (rhs) == SSA_NAME) -+ { -+ type = TREE_TYPE (rhs); -+ stmt = SSA_NAME_DEF_STMT (rhs); -+ if (!is_gimple_assign (stmt)) -+ return false; -+ -+ rhs_code = gimple_assign_rhs_code (stmt); -+ if (TREE_CODE (type) == INTEGER_TYPE -+ ? !CONVERT_EXPR_CODE_P (rhs_code) -+ : rhs_code != FIXED_CONVERT_EXPR) -+ return false; -+ -+ rhs1 = gimple_assign_rhs1 (stmt); -+ type1 = TREE_TYPE (rhs1); -+ if (TREE_CODE (type1) != TREE_CODE (type) -+ || TYPE_PRECISION (type1) * 2 != TYPE_PRECISION (type)) -+ return false; -+ -+ *new_rhs_out = rhs1; -+ *type_out = type1; -+ return true; -+ } -+ -+ if (TREE_CODE (rhs) == INTEGER_CST) -+ { -+ *new_rhs_out = rhs; -+ *type_out = NULL; -+ return true; -+ } -+ -+ return false; -+} -+ -+/* Return true if STMT performs a widening multiplication. If so, -+ store the unwidened types of the operands in *TYPE1_OUT and *TYPE2_OUT -+ respectively. Also fill *RHS1_OUT and *RHS2_OUT such that converting -+ those operands to types *TYPE1_OUT and *TYPE2_OUT would give the -+ operands of the multiplication. */ -+ -+static bool -+is_widening_mult_p (gimple stmt, -+ tree *type1_out, tree *rhs1_out, -+ tree *type2_out, tree *rhs2_out) -+{ -+ tree type; -+ -+ type = TREE_TYPE (gimple_assign_lhs (stmt)); -+ if (TREE_CODE (type) != INTEGER_TYPE -+ && TREE_CODE (type) != FIXED_POINT_TYPE) -+ return false; -+ -+ if (!is_widening_mult_rhs_p (gimple_assign_rhs1 (stmt), type1_out, rhs1_out)) -+ return false; -+ -+ if (!is_widening_mult_rhs_p (gimple_assign_rhs2 (stmt), type2_out, rhs2_out)) -+ return false; -+ -+ if (*type1_out == NULL) -+ { -+ if (*type2_out == NULL || !int_fits_type_p (*rhs1_out, *type2_out)) -+ return false; -+ *type1_out = *type2_out; -+ } -+ -+ if (*type2_out == NULL) -+ { -+ if (!int_fits_type_p (*rhs2_out, *type1_out)) -+ return false; -+ *type2_out = *type1_out; -+ } -+ -+ return true; -+} -+ -+/* Process a single gimple statement STMT, which has a MULT_EXPR as -+ its rhs, and try to convert it into a WIDEN_MULT_EXPR. The return -+ value is true iff we converted the statement. */ -+ -+static bool -+convert_mult_to_widen (gimple stmt) -+{ -+ tree lhs, rhs1, rhs2, type, type1, type2; -+ enum insn_code handler; -+ -+ lhs = gimple_assign_lhs (stmt); -+ type = TREE_TYPE (lhs); -+ if (TREE_CODE (type) != INTEGER_TYPE) -+ return false; -+ -+ if (!is_widening_mult_p (stmt, &type1, &rhs1, &type2, &rhs2)) -+ return false; -+ -+ if (TYPE_UNSIGNED (type1) && TYPE_UNSIGNED (type2)) -+ handler = optab_handler (umul_widen_optab, TYPE_MODE (type))->insn_code; -+ else if (!TYPE_UNSIGNED (type1) && !TYPE_UNSIGNED (type2)) -+ handler = optab_handler (smul_widen_optab, TYPE_MODE (type))->insn_code; -+ else -+ handler = optab_handler (usmul_widen_optab, TYPE_MODE (type))->insn_code; -+ -+ if (handler == CODE_FOR_nothing) -+ return false; -+ -+ gimple_assign_set_rhs1 (stmt, fold_convert (type1, rhs1)); -+ gimple_assign_set_rhs2 (stmt, fold_convert (type2, rhs2)); -+ gimple_assign_set_rhs_code (stmt, WIDEN_MULT_EXPR); -+ update_stmt (stmt); -+ return true; -+} -+ -+/* Process a single gimple statement STMT, which is found at the -+ iterator GSI and has a either a PLUS_EXPR or a MINUS_EXPR as its -+ rhs (given by CODE), and try to convert it into a -+ WIDEN_MULT_PLUS_EXPR or a WIDEN_MULT_MINUS_EXPR. The return value -+ is true iff we converted the statement. */ -+ -+static bool -+convert_plusminus_to_widen (gimple_stmt_iterator *gsi, gimple stmt, -+ enum tree_code code) -+{ -+ gimple rhs1_stmt = NULL, rhs2_stmt = NULL; -+ tree type, type1, type2; -+ tree lhs, rhs1, rhs2, mult_rhs1, mult_rhs2, add_rhs; -+ enum tree_code rhs1_code = ERROR_MARK, rhs2_code = ERROR_MARK; -+ optab this_optab; -+ enum tree_code wmult_code; -+ -+ lhs = gimple_assign_lhs (stmt); -+ type = TREE_TYPE (lhs); -+ if (TREE_CODE (type) != INTEGER_TYPE -+ && TREE_CODE (type) != FIXED_POINT_TYPE) -+ return false; -+ -+ if (code == MINUS_EXPR) -+ wmult_code = WIDEN_MULT_MINUS_EXPR; -+ else -+ wmult_code = WIDEN_MULT_PLUS_EXPR; -+ -+ rhs1 = gimple_assign_rhs1 (stmt); -+ rhs2 = gimple_assign_rhs2 (stmt); -+ -+ if (TREE_CODE (rhs1) == SSA_NAME) -+ { -+ rhs1_stmt = SSA_NAME_DEF_STMT (rhs1); -+ if (is_gimple_assign (rhs1_stmt)) -+ rhs1_code = gimple_assign_rhs_code (rhs1_stmt); -+ } -+ else -+ return false; -+ -+ if (TREE_CODE (rhs2) == SSA_NAME) -+ { -+ rhs2_stmt = SSA_NAME_DEF_STMT (rhs2); -+ if (is_gimple_assign (rhs2_stmt)) -+ rhs2_code = gimple_assign_rhs_code (rhs2_stmt); -+ } -+ else -+ return false; -+ -+ if (code == PLUS_EXPR && rhs1_code == MULT_EXPR) -+ { -+ if (!is_widening_mult_p (rhs1_stmt, &type1, &mult_rhs1, -+ &type2, &mult_rhs2)) -+ return false; -+ add_rhs = rhs2; -+ } -+ else if (rhs2_code == MULT_EXPR) -+ { -+ if (!is_widening_mult_p (rhs2_stmt, &type1, &mult_rhs1, -+ &type2, &mult_rhs2)) -+ return false; -+ add_rhs = rhs1; -+ } -+ else if (code == PLUS_EXPR && rhs1_code == WIDEN_MULT_EXPR) -+ { -+ mult_rhs1 = gimple_assign_rhs1 (rhs1_stmt); -+ mult_rhs2 = gimple_assign_rhs2 (rhs1_stmt); -+ type1 = TREE_TYPE (mult_rhs1); -+ type2 = TREE_TYPE (mult_rhs2); -+ add_rhs = rhs2; -+ } -+ else if (rhs2_code == WIDEN_MULT_EXPR) -+ { -+ mult_rhs1 = gimple_assign_rhs1 (rhs2_stmt); -+ mult_rhs2 = gimple_assign_rhs2 (rhs2_stmt); -+ type1 = TREE_TYPE (mult_rhs1); -+ type2 = TREE_TYPE (mult_rhs2); -+ add_rhs = rhs1; -+ } -+ else -+ return false; -+ -+ if (TYPE_UNSIGNED (type1) != TYPE_UNSIGNED (type2)) -+ return false; -+ -+ /* Verify that the machine can perform a widening multiply -+ accumulate in this mode/signedness combination, otherwise -+ this transformation is likely to pessimize code. */ -+ this_optab = optab_for_tree_code (wmult_code, type1, optab_default); -+ if (optab_handler (this_optab, TYPE_MODE (type))->insn_code -+ == CODE_FOR_nothing) -+ return false; -+ -+ /* ??? May need some type verification here? */ -+ -+ gimple_assign_set_rhs_with_ops_1 (gsi, wmult_code, -+ fold_convert (type1, mult_rhs1), -+ fold_convert (type2, mult_rhs2), -+ add_rhs); -+ update_stmt (gsi_stmt (*gsi)); -+ return true; -+} -+ - /* Find integer multiplications where the operands are extended from - smaller types, and replace the MULT_EXPR with a WIDEN_MULT_EXPR - where appropriate. */ -@@ -1287,94 +1516,19 @@ - for (gsi = gsi_after_labels (bb); !gsi_end_p (gsi); gsi_next (&gsi)) - { - gimple stmt = gsi_stmt (gsi); -- gimple rhs1_stmt = NULL, rhs2_stmt = NULL; -- tree type, type1 = NULL, type2 = NULL; -- tree rhs1, rhs2, rhs1_convop = NULL, rhs2_convop = NULL; -- enum tree_code rhs1_code, rhs2_code; -+ enum tree_code code; - -- if (!is_gimple_assign (stmt) -- || gimple_assign_rhs_code (stmt) != MULT_EXPR) -+ if (!is_gimple_assign (stmt)) - continue; - -- type = TREE_TYPE (gimple_assign_lhs (stmt)); -- -- if (TREE_CODE (type) != INTEGER_TYPE) -- continue; -- -- rhs1 = gimple_assign_rhs1 (stmt); -- rhs2 = gimple_assign_rhs2 (stmt); -- -- if (TREE_CODE (rhs1) == SSA_NAME) -- { -- rhs1_stmt = SSA_NAME_DEF_STMT (rhs1); -- if (!is_gimple_assign (rhs1_stmt)) -- continue; -- rhs1_code = gimple_assign_rhs_code (rhs1_stmt); -- if (!CONVERT_EXPR_CODE_P (rhs1_code)) -- continue; -- rhs1_convop = gimple_assign_rhs1 (rhs1_stmt); -- type1 = TREE_TYPE (rhs1_convop); -- if (TYPE_PRECISION (type1) * 2 != TYPE_PRECISION (type)) -- continue; -- } -- else if (TREE_CODE (rhs1) != INTEGER_CST) -- continue; -- -- if (TREE_CODE (rhs2) == SSA_NAME) -- { -- rhs2_stmt = SSA_NAME_DEF_STMT (rhs2); -- if (!is_gimple_assign (rhs2_stmt)) -- continue; -- rhs2_code = gimple_assign_rhs_code (rhs2_stmt); -- if (!CONVERT_EXPR_CODE_P (rhs2_code)) -- continue; -- rhs2_convop = gimple_assign_rhs1 (rhs2_stmt); -- type2 = TREE_TYPE (rhs2_convop); -- if (TYPE_PRECISION (type2) * 2 != TYPE_PRECISION (type)) -- continue; -- } -- else if (TREE_CODE (rhs2) != INTEGER_CST) -- continue; -- -- if (rhs1_stmt == NULL && rhs2_stmt == NULL) -- continue; -- -- /* Verify that the machine can perform a widening multiply in this -- mode/signedness combination, otherwise this transformation is -- likely to pessimize code. */ -- if ((rhs1_stmt == NULL || TYPE_UNSIGNED (type1)) -- && (rhs2_stmt == NULL || TYPE_UNSIGNED (type2)) -- && (optab_handler (umul_widen_optab, TYPE_MODE (type)) -- ->insn_code == CODE_FOR_nothing)) -- continue; -- else if ((rhs1_stmt == NULL || !TYPE_UNSIGNED (type1)) -- && (rhs2_stmt == NULL || !TYPE_UNSIGNED (type2)) -- && (optab_handler (smul_widen_optab, TYPE_MODE (type)) -- ->insn_code == CODE_FOR_nothing)) -- continue; -- else if (rhs1_stmt != NULL && rhs2_stmt != 0 -- && (TYPE_UNSIGNED (type1) != TYPE_UNSIGNED (type2)) -- && (optab_handler (usmul_widen_optab, TYPE_MODE (type)) -- ->insn_code == CODE_FOR_nothing)) -- continue; -- -- if ((rhs1_stmt == NULL && !int_fits_type_p (rhs1, type2)) -- || (rhs2_stmt == NULL && !int_fits_type_p (rhs2, type1))) -- continue; -- -- if (rhs1_stmt == NULL) -- gimple_assign_set_rhs1 (stmt, fold_convert (type2, rhs1)); -- else -- gimple_assign_set_rhs1 (stmt, rhs1_convop); -- if (rhs2_stmt == NULL) -- gimple_assign_set_rhs2 (stmt, fold_convert (type1, rhs2)); -- else -- gimple_assign_set_rhs2 (stmt, rhs2_convop); -- gimple_assign_set_rhs_code (stmt, WIDEN_MULT_EXPR); -- update_stmt (stmt); -- changed = true; -+ code = gimple_assign_rhs_code (stmt); -+ if (code == MULT_EXPR) -+ changed |= convert_mult_to_widen (stmt); -+ else if (code == PLUS_EXPR || code == MINUS_EXPR) -+ changed |= convert_plusminus_to_widen (&gsi, stmt, code); - } - } -+ - return (changed ? TODO_dump_func | TODO_update_ssa | TODO_verify_ssa - | TODO_verify_stmts : 0); - } -Index: gcc-4_5-branch/gcc/tree-ssa-operands.c -=================================================================== ---- gcc-4_5-branch.orig/gcc/tree-ssa-operands.c 2011-07-22 16:58:48.000000000 -0700 -+++ gcc-4_5-branch/gcc/tree-ssa-operands.c 2011-07-22 16:59:28.611747691 -0700 -@@ -994,11 +994,13 @@ - - case DOT_PROD_EXPR: - case REALIGN_LOAD_EXPR: -+ case WIDEN_MULT_PLUS_EXPR: -+ case WIDEN_MULT_MINUS_EXPR: - { - get_expr_operands (stmt, &TREE_OPERAND (expr, 0), flags); -- get_expr_operands (stmt, &TREE_OPERAND (expr, 1), flags); -- get_expr_operands (stmt, &TREE_OPERAND (expr, 2), flags); -- return; -+ get_expr_operands (stmt, &TREE_OPERAND (expr, 1), flags); -+ get_expr_operands (stmt, &TREE_OPERAND (expr, 2), flags); -+ return; - } - - case FUNCTION_DECL: -Index: gcc-4_5-branch/gcc/tree-ssa-sccvn.c -=================================================================== ---- gcc-4_5-branch.orig/gcc/tree-ssa-sccvn.c 2011-07-22 16:58:48.000000000 -0700 -+++ gcc-4_5-branch/gcc/tree-ssa-sccvn.c 2011-07-22 16:59:28.611747691 -0700 -@@ -2298,6 +2298,10 @@ - case GIMPLE_BINARY_RHS: - return (is_gimple_min_invariant (gimple_assign_rhs1 (stmt)) - || is_gimple_min_invariant (gimple_assign_rhs2 (stmt))); -+ case GIMPLE_TERNARY_RHS: -+ return (is_gimple_min_invariant (gimple_assign_rhs1 (stmt)) -+ || is_gimple_min_invariant (gimple_assign_rhs2 (stmt)) -+ || is_gimple_min_invariant (gimple_assign_rhs3 (stmt))); - case GIMPLE_SINGLE_RHS: - /* Constants inside reference ops are rarely interesting, but - it can take a lot of looking to find them. */ -Index: gcc-4_5-branch/gcc/tree-ssa-threadedge.c -=================================================================== ---- gcc-4_5-branch.orig/gcc/tree-ssa-threadedge.c 2011-07-22 16:58:48.000000000 -0700 -+++ gcc-4_5-branch/gcc/tree-ssa-threadedge.c 2011-07-22 16:59:28.611747691 -0700 -@@ -247,14 +247,14 @@ - - return fold (rhs); - } -- break; -+ - case GIMPLE_UNARY_RHS: - { - tree lhs = gimple_assign_lhs (stmt); - tree op0 = gimple_assign_rhs1 (stmt); - return fold_unary (subcode, TREE_TYPE (lhs), op0); - } -- break; -+ - case GIMPLE_BINARY_RHS: - { - tree lhs = gimple_assign_lhs (stmt); -@@ -262,7 +262,16 @@ - tree op1 = gimple_assign_rhs2 (stmt); - return fold_binary (subcode, TREE_TYPE (lhs), op0, op1); - } -- break; -+ -+ case GIMPLE_TERNARY_RHS: -+ { -+ tree lhs = gimple_assign_lhs (stmt); -+ tree op0 = gimple_assign_rhs1 (stmt); -+ tree op1 = gimple_assign_rhs2 (stmt); -+ tree op2 = gimple_assign_rhs3 (stmt); -+ return fold_ternary (subcode, TREE_TYPE (lhs), op0, op1, op2); -+ } -+ - default: - gcc_unreachable (); - } -Index: gcc-4_5-branch/gcc/tree-vrp.c -=================================================================== ---- gcc-4_5-branch.orig/gcc/tree-vrp.c 2011-07-22 16:58:48.000000000 -0700 -+++ gcc-4_5-branch/gcc/tree-vrp.c 2011-07-22 16:59:28.621747691 -0700 -@@ -864,6 +864,8 @@ - gimple_assign_rhs1 (stmt), - gimple_assign_rhs2 (stmt), - strict_overflow_p); -+ case GIMPLE_TERNARY_RHS: -+ return false; - case GIMPLE_SINGLE_RHS: - return tree_single_nonnegative_warnv_p (gimple_assign_rhs1 (stmt), - strict_overflow_p); -@@ -935,6 +937,8 @@ - gimple_assign_rhs1 (stmt), - gimple_assign_rhs2 (stmt), - strict_overflow_p); -+ case GIMPLE_TERNARY_RHS: -+ return false; - case GIMPLE_SINGLE_RHS: - return tree_single_nonzero_warnv_p (gimple_assign_rhs1 (stmt), - strict_overflow_p); -Index: gcc-4_5-branch/gcc/tree.c -=================================================================== ---- gcc-4_5-branch.orig/gcc/tree.c 2011-07-22 16:59:13.000000000 -0700 -+++ gcc-4_5-branch/gcc/tree.c 2011-07-22 16:59:28.621747691 -0700 -@@ -6548,6 +6548,23 @@ - return false; - } - -+/* Return true if CODE represents a ternary tree code for which the -+ first two operands are commutative. Otherwise return false. */ -+bool -+commutative_ternary_tree_code (enum tree_code code) -+{ -+ switch (code) -+ { -+ case WIDEN_MULT_PLUS_EXPR: -+ case WIDEN_MULT_MINUS_EXPR: -+ return true; -+ -+ default: -+ break; -+ } -+ return false; -+} -+ - /* Generate a hash value for an expression. This can be used iteratively - by passing a previous result as the VAL argument. - -Index: gcc-4_5-branch/gcc/tree.def -=================================================================== ---- gcc-4_5-branch.orig/gcc/tree.def 2011-07-22 16:58:48.000000000 -0700 -+++ gcc-4_5-branch/gcc/tree.def 2011-07-22 16:59:28.631747691 -0700 -@@ -1083,6 +1083,18 @@ - the arguments from type t1 to type t2, and then multiplying them. */ - DEFTREECODE (WIDEN_MULT_EXPR, "widen_mult_expr", tcc_binary, 2) - -+/* Widening multiply-accumulate. -+ The first two arguments are of type t1. -+ The third argument and the result are of type t2, such as t2 is at least -+ twice the size of t1. t1 and t2 must be integral or fixed-point types. -+ The expression is equivalent to a WIDEN_MULT_EXPR operation -+ of the first two operands followed by an add or subtract of the third -+ operand. */ -+DEFTREECODE (WIDEN_MULT_PLUS_EXPR, "widen_mult_plus_expr", tcc_expression, 3) -+/* This is like the above, except in the final expression the multiply result -+ is subtracted from t3. */ -+DEFTREECODE (WIDEN_MULT_MINUS_EXPR, "widen_mult_plus_expr", tcc_expression, 3) -+ - /* Whole vector left/right shift in bits. - Operand 0 is a vector to be shifted. - Operand 1 is an integer shift amount in bits. */ -Index: gcc-4_5-branch/gcc/tree.h -=================================================================== ---- gcc-4_5-branch.orig/gcc/tree.h 2011-07-22 16:59:13.000000000 -0700 -+++ gcc-4_5-branch/gcc/tree.h 2011-07-22 16:59:28.631747691 -0700 -@@ -4687,6 +4687,7 @@ - extern int type_num_arguments (const_tree); - extern bool associative_tree_code (enum tree_code); - extern bool commutative_tree_code (enum tree_code); -+extern bool commutative_ternary_tree_code (enum tree_code); - extern tree upper_bound_in_type (tree, tree); - extern tree lower_bound_in_type (tree, tree); - extern int operand_equal_for_phi_arg_p (const_tree, const_tree); |