2010-05-06 Andrew Church * expr.c: Allow a PLUS_EXPR with a MULT_EXPR operand to be optimized to a multiply-add instruction regardless of whether the MULT_EXPR is the first or the second operand. --- gcc-4.4.3-orig/gcc/expr.c 2010-01-16 18:44:57 +0900 +++ gcc-4.4.3/gcc/expr.c 2010-05-06 04:32:32 +0900 @@ -8363,51 +8363,62 @@ TREE_OPERAND (exp, 1)))); 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) - && TREE_CODE (TREE_OPERAND (exp, 0)) == MULT_EXPR) + /* Check if this is a case for multiplication and addition. + Addition is commutative, so the multiplication expression + could be either operand 0 or operand 1. */ + if (TREE_CODE (type) == INTEGER_TYPE + || TREE_CODE (type) == FIXED_POINT_TYPE) { - tree subsubexp0, subsubexp1; - enum tree_code code0, code1, this_code; - - subexp0 = TREE_OPERAND (exp, 0); - subsubexp0 = TREE_OPERAND (subexp0, 0); - subsubexp1 = TREE_OPERAND (subexp0, 1); - code0 = TREE_CODE (subsubexp0); - code1 = TREE_CODE (subsubexp1); - this_code = TREE_CODE (type) == INTEGER_TYPE ? NOP_EXPR - : FIXED_CONVERT_EXPR; - if (code0 == this_code && code1 == this_code - && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp0, 0))) - < TYPE_PRECISION (TREE_TYPE (subsubexp0))) - && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp0, 0))) - == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp1, 0)))) - && (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subsubexp0, 0))) - == TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subsubexp1, 0))))) + int mult_operand, add_operand; + if (TREE_CODE (TREE_OPERAND (exp, 0)) == MULT_EXPR) + mult_operand = 0, add_operand = 1; + else if (TREE_CODE (TREE_OPERAND (exp, 1)) == MULT_EXPR) + mult_operand = 1, add_operand = 0; + else + mult_operand = add_operand = -1; + if (mult_operand >= 0) { - tree op0type = TREE_TYPE (TREE_OPERAND (subsubexp0, 0)); - 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)) + tree subsubexp0, subsubexp1; + enum tree_code code0, code1, this_code; + + subexp0 = TREE_OPERAND (exp, mult_operand); + subsubexp0 = TREE_OPERAND (subexp0, 0); + subsubexp1 = TREE_OPERAND (subexp0, 1); + code0 = TREE_CODE (subsubexp0); + code1 = TREE_CODE (subsubexp1); + this_code = TREE_CODE (type) == INTEGER_TYPE ? NOP_EXPR + : FIXED_CONVERT_EXPR; + if (code0 == this_code && code1 == this_code + && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp0, 0))) + < TYPE_PRECISION (TREE_TYPE (subsubexp0))) + && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp0, 0))) + == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp1, 0)))) + && (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subsubexp0, 0))) + == TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subsubexp1, 0))))) { - expand_operands (TREE_OPERAND (subsubexp0, 0), - TREE_OPERAND (subsubexp1, 0), - NULL_RTX, &op0, &op1, EXPAND_NORMAL); - op2 = expand_expr (TREE_OPERAND (exp, 1), subtarget, - VOIDmode, EXPAND_NORMAL); - temp = expand_ternary_op (mode, this_optab, op0, op1, op2, - target, unsignedp); - gcc_assert (temp); - return REDUCE_BIT_FIELD (temp); + tree op0type = TREE_TYPE (TREE_OPERAND (subsubexp0, 0)); + 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 (TREE_OPERAND (subsubexp0, 0), + TREE_OPERAND (subsubexp1, 0), + NULL_RTX, &op0, &op1, EXPAND_NORMAL); + op2 = expand_expr (TREE_OPERAND (exp, add_operand), + subtarget, VOIDmode, EXPAND_NORMAL); + temp = expand_ternary_op (mode, this_optab, op0, op1, + op2, target, unsignedp); + gcc_assert (temp); + return REDUCE_BIT_FIELD (temp); + } } } }