Commit 5dfe80ba by Andrew Stubbs Committed by Andrew Stubbs

arm.md (maddhidi4): Remove '*' from name.

2011-08-19  Andrew Stubbs  <ams@codesourcery.com>

	gcc/
	* config/arm/arm.md (maddhidi4): Remove '*' from name.
	* expr.c (expand_expr_real_2): Use find_widening_optab_handler.
	* optabs.c (find_widening_optab_handler_and_mode): New function.
	(expand_widen_pattern_expr): Use find_widening_optab_handler.
	(expand_binop_directly): Likewise.
	(expand_binop): Likewise.
	* optabs.h (find_widening_optab_handler): New macro define.
	(find_widening_optab_handler_and_mode): New prototype.
	* tree-cfg.c (verify_gimple_assign_binary): Adjust WIDEN_MULT_EXPR
	type precision rules.
	(verify_gimple_assign_ternary): Likewise for WIDEN_MULT_PLUS_EXPR.
	* tree-ssa-math-opts.c (build_and_insert_cast): New function.
	(is_widening_mult_rhs_p): Allow widening by more than one mode.
	Explicitly disallow mis-matched input types.
	(convert_mult_to_widen): Use find_widening_optab_handler, and cast
	input types to fit the new handler.
	(convert_plusminus_to_widen): Likewise.

	gcc/testsuite/
	* gcc.target/arm/wmul-bitfield-1.c: New file.

From-SVN: r177902
parent a484f6ba
2011-08-19 Andrew Stubbs <ams@codesourcery.com> 2011-08-19 Andrew Stubbs <ams@codesourcery.com>
* config/arm/arm.md (maddhidi4): Remove '*' from name.
* expr.c (expand_expr_real_2): Use find_widening_optab_handler.
* optabs.c (find_widening_optab_handler_and_mode): New function.
(expand_widen_pattern_expr): Use find_widening_optab_handler.
(expand_binop_directly): Likewise.
(expand_binop): Likewise.
* optabs.h (find_widening_optab_handler): New macro define.
(find_widening_optab_handler_and_mode): New prototype.
* tree-cfg.c (verify_gimple_assign_binary): Adjust WIDEN_MULT_EXPR
type precision rules.
(verify_gimple_assign_ternary): Likewise for WIDEN_MULT_PLUS_EXPR.
* tree-ssa-math-opts.c (build_and_insert_cast): New function.
(is_widening_mult_rhs_p): Allow widening by more than one mode.
Explicitly disallow mis-matched input types.
(convert_mult_to_widen): Use find_widening_optab_handler, and cast
input types to fit the new handler.
(convert_plusminus_to_widen): Likewise.
2011-08-19 Andrew Stubbs <ams@codesourcery.com>
* expr.c (expand_expr_real_2): Use widening_optab_handler. * expr.c (expand_expr_real_2): Use widening_optab_handler.
* genopinit.c (optabs): Use set_widening_optab_handler for $N. * genopinit.c (optabs): Use set_widening_optab_handler for $N.
(gen_insn): $N now means $a must be wider than $b, not consecutive. (gen_insn): $N now means $a must be wider than $b, not consecutive.
......
...@@ -1857,7 +1857,7 @@ ...@@ -1857,7 +1857,7 @@
(set_attr "predicable" "yes")] (set_attr "predicable" "yes")]
) )
(define_insn "*maddhidi4" (define_insn "maddhidi4"
[(set (match_operand:DI 0 "s_register_operand" "=r") [(set (match_operand:DI 0 "s_register_operand" "=r")
(plus:DI (plus:DI
(mult:DI (sign_extend:DI (mult:DI (sign_extend:DI
......
...@@ -8003,9 +8003,7 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode, ...@@ -8003,9 +8003,7 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
{ {
enum machine_mode innermode = TYPE_MODE (TREE_TYPE (treeop0)); enum machine_mode innermode = TYPE_MODE (TREE_TYPE (treeop0));
this_optab = usmul_widen_optab; this_optab = usmul_widen_optab;
if (mode == GET_MODE_2XWIDER_MODE (innermode)) if (find_widening_optab_handler (this_optab, mode, innermode, 0)
{
if (widening_optab_handler (this_optab, mode, innermode)
!= CODE_FOR_nothing) != CODE_FOR_nothing)
{ {
if (TYPE_UNSIGNED (TREE_TYPE (treeop0))) if (TYPE_UNSIGNED (TREE_TYPE (treeop0)))
...@@ -8017,7 +8015,6 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode, ...@@ -8017,7 +8015,6 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
goto binop3; goto binop3;
} }
} }
}
/* Check for a multiplication with matching signedness. */ /* Check for a multiplication with matching signedness. */
else if ((TREE_CODE (treeop1) == INTEGER_CST else if ((TREE_CODE (treeop1) == INTEGER_CST
&& int_fits_type_p (treeop1, TREE_TYPE (treeop0))) && int_fits_type_p (treeop1, TREE_TYPE (treeop0)))
...@@ -8030,10 +8027,9 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode, ...@@ -8030,10 +8027,9 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
optab other_optab = zextend_p ? smul_widen_optab : umul_widen_optab; optab other_optab = zextend_p ? smul_widen_optab : umul_widen_optab;
this_optab = zextend_p ? umul_widen_optab : smul_widen_optab; this_optab = zextend_p ? umul_widen_optab : smul_widen_optab;
if (mode == GET_MODE_2XWIDER_MODE (innermode) if (TREE_CODE (treeop0) != INTEGER_CST)
&& TREE_CODE (treeop0) != INTEGER_CST)
{ {
if (widening_optab_handler (this_optab, mode, innermode) if (find_widening_optab_handler (this_optab, mode, innermode, 0)
!= CODE_FOR_nothing) != CODE_FOR_nothing)
{ {
expand_operands (treeop0, treeop1, NULL_RTX, &op0, &op1, expand_operands (treeop0, treeop1, NULL_RTX, &op0, &op1,
...@@ -8042,7 +8038,7 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode, ...@@ -8042,7 +8038,7 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
unsignedp, this_optab); unsignedp, this_optab);
return REDUCE_BIT_FIELD (temp); return REDUCE_BIT_FIELD (temp);
} }
if (widening_optab_handler (other_optab, mode, innermode) if (find_widening_optab_handler (other_optab, mode, innermode, 0)
!= CODE_FOR_nothing != CODE_FOR_nothing
&& innermode == word_mode) && innermode == word_mode)
{ {
......
...@@ -249,6 +249,37 @@ widened_mode (enum machine_mode to_mode, rtx op0, rtx op1) ...@@ -249,6 +249,37 @@ widened_mode (enum machine_mode to_mode, rtx op0, rtx op1)
return result; return result;
} }
/* Find a widening optab even if it doesn't widen as much as we want.
E.g. if from_mode is HImode, and to_mode is DImode, and there is no
direct HI->SI insn, then return SI->DI, if that exists.
If PERMIT_NON_WIDENING is non-zero then this can be used with
non-widening optabs also. */
enum insn_code
find_widening_optab_handler_and_mode (optab op, enum machine_mode to_mode,
enum machine_mode from_mode,
int permit_non_widening,
enum machine_mode *found_mode)
{
for (; (permit_non_widening || from_mode != to_mode)
&& GET_MODE_SIZE (from_mode) <= GET_MODE_SIZE (to_mode)
&& from_mode != VOIDmode;
from_mode = GET_MODE_WIDER_MODE (from_mode))
{
enum insn_code handler = widening_optab_handler (op, to_mode,
from_mode);
if (handler != CODE_FOR_nothing)
{
if (found_mode)
*found_mode = from_mode;
return handler;
}
}
return CODE_FOR_nothing;
}
/* Widen OP to MODE and return the rtx for the widened operand. UNSIGNEDP /* Widen OP to MODE and return the rtx for the widened operand. UNSIGNEDP
says whether OP is signed or unsigned. NO_EXTEND is nonzero if we need says whether OP is signed or unsigned. NO_EXTEND is nonzero if we need
not actually do a sign-extend or zero-extend, but can leave the not actually do a sign-extend or zero-extend, but can leave the
...@@ -539,8 +570,9 @@ expand_widen_pattern_expr (sepops ops, rtx op0, rtx op1, rtx wide_op, ...@@ -539,8 +570,9 @@ expand_widen_pattern_expr (sepops ops, rtx op0, rtx op1, rtx wide_op,
optab_for_tree_code (ops->code, TREE_TYPE (oprnd0), optab_default); optab_for_tree_code (ops->code, TREE_TYPE (oprnd0), optab_default);
if (ops->code == WIDEN_MULT_PLUS_EXPR if (ops->code == WIDEN_MULT_PLUS_EXPR
|| ops->code == WIDEN_MULT_MINUS_EXPR) || ops->code == WIDEN_MULT_MINUS_EXPR)
icode = widening_optab_handler (widen_pattern_optab, icode = find_widening_optab_handler (widen_pattern_optab,
TYPE_MODE (TREE_TYPE (ops->op2)), tmode0); TYPE_MODE (TREE_TYPE (ops->op2)),
tmode0, 0);
else else
icode = optab_handler (widen_pattern_optab, tmode0); icode = optab_handler (widen_pattern_optab, tmode0);
gcc_assert (icode != CODE_FOR_nothing); gcc_assert (icode != CODE_FOR_nothing);
...@@ -1267,7 +1299,8 @@ expand_binop_directly (enum machine_mode mode, optab binoptab, ...@@ -1267,7 +1299,8 @@ expand_binop_directly (enum machine_mode mode, optab binoptab,
rtx last) rtx last)
{ {
enum machine_mode from_mode = widened_mode (mode, op0, op1); enum machine_mode from_mode = widened_mode (mode, op0, op1);
enum insn_code icode = widening_optab_handler (binoptab, mode, from_mode); enum insn_code icode = find_widening_optab_handler (binoptab, mode,
from_mode, 1);
enum machine_mode xmode0 = insn_data[(int) icode].operand[1].mode; enum machine_mode xmode0 = insn_data[(int) icode].operand[1].mode;
enum machine_mode xmode1 = insn_data[(int) icode].operand[2].mode; enum machine_mode xmode1 = insn_data[(int) icode].operand[2].mode;
enum machine_mode mode0, mode1, tmp_mode; enum machine_mode mode0, mode1, tmp_mode;
...@@ -1414,8 +1447,8 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1, ...@@ -1414,8 +1447,8 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
/* If we can do it with a three-operand insn, do so. */ /* If we can do it with a three-operand insn, do so. */
if (methods != OPTAB_MUST_WIDEN if (methods != OPTAB_MUST_WIDEN
&& widening_optab_handler (binoptab, mode, && find_widening_optab_handler (binoptab, mode,
widened_mode (mode, op0, op1)) widened_mode (mode, op0, op1), 1)
!= CODE_FOR_nothing) != CODE_FOR_nothing)
{ {
temp = expand_binop_directly (mode, binoptab, op0, op1, target, temp = expand_binop_directly (mode, binoptab, op0, op1, target,
...@@ -1488,10 +1521,11 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1, ...@@ -1488,10 +1521,11 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
if (optab_handler (binoptab, wider_mode) != CODE_FOR_nothing if (optab_handler (binoptab, wider_mode) != CODE_FOR_nothing
|| (binoptab == smul_optab || (binoptab == smul_optab
&& GET_MODE_WIDER_MODE (wider_mode) != VOIDmode && GET_MODE_WIDER_MODE (wider_mode) != VOIDmode
&& (widening_optab_handler ((unsignedp ? umul_widen_optab && (find_widening_optab_handler ((unsignedp
? umul_widen_optab
: smul_widen_optab), : smul_widen_optab),
GET_MODE_WIDER_MODE (wider_mode), GET_MODE_WIDER_MODE (wider_mode),
mode) mode, 0)
!= CODE_FOR_nothing))) != CODE_FOR_nothing)))
{ {
rtx xop0 = op0, xop1 = op1; rtx xop0 = op0, xop1 = op1;
...@@ -2026,8 +2060,7 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1, ...@@ -2026,8 +2060,7 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
wider_mode != VOIDmode; wider_mode != VOIDmode;
wider_mode = GET_MODE_WIDER_MODE (wider_mode)) wider_mode = GET_MODE_WIDER_MODE (wider_mode))
{ {
if (optab_handler (binoptab, wider_mode) != CODE_FOR_nothing if (find_widening_optab_handler (binoptab, wider_mode, mode, 1)
|| widening_optab_handler (binoptab, wider_mode, mode)
!= CODE_FOR_nothing != CODE_FOR_nothing
|| (methods == OPTAB_LIB || (methods == OPTAB_LIB
&& optab_libfunc (binoptab, wider_mode))) && optab_libfunc (binoptab, wider_mode)))
......
...@@ -807,6 +807,15 @@ extern rtx expand_copysign (rtx, rtx, rtx); ...@@ -807,6 +807,15 @@ extern rtx expand_copysign (rtx, rtx, rtx);
extern void emit_unop_insn (enum insn_code, rtx, rtx, enum rtx_code); extern void emit_unop_insn (enum insn_code, rtx, rtx, enum rtx_code);
extern bool maybe_emit_unop_insn (enum insn_code, rtx, rtx, enum rtx_code); extern bool maybe_emit_unop_insn (enum insn_code, rtx, rtx, enum rtx_code);
/* Find a widening optab even if it doesn't widen as much as we want. */
#define find_widening_optab_handler(A,B,C,D) \
find_widening_optab_handler_and_mode (A, B, C, D, NULL)
extern enum insn_code find_widening_optab_handler_and_mode (optab,
enum machine_mode,
enum machine_mode,
int,
enum machine_mode *);
/* An extra flag to control optab_for_tree_code's behavior. This is needed to /* An extra flag to control optab_for_tree_code's behavior. This is needed to
distinguish between machines with a vector shift that takes a scalar for the distinguish between machines with a vector shift that takes a scalar for the
shift amount vs. machines that take a vector for the shift amount. */ shift amount vs. machines that take a vector for the shift amount. */
......
2011-08-19 Andrew Stubbs <ams@codesourcery.com>
* gcc.target/arm/wmul-bitfield-1.c: New file.
2011-08-19 Joseph Myers <joseph@codesourcery.com> 2011-08-19 Joseph Myers <joseph@codesourcery.com>
* gcc.dg/c90-noreturn-1.c, gcc.dg/c99-noreturn-1.c: New tests. * gcc.dg/c90-noreturn-1.c, gcc.dg/c99-noreturn-1.c: New tests.
......
/* { dg-do compile } */
/* { dg-options "-O2" } */
/* { dg-require-effective-target arm_dsp } */
struct bf
{
int a : 3;
int b : 15;
int c : 3;
};
long long
foo (long long a, struct bf b, struct bf c)
{
return a + b.b * c.b;
}
/* { dg-final { scan-assembler "smlalbb" } } */
...@@ -3564,7 +3564,7 @@ do_pointer_plus_expr_check: ...@@ -3564,7 +3564,7 @@ do_pointer_plus_expr_check:
case WIDEN_MULT_EXPR: case WIDEN_MULT_EXPR:
if (TREE_CODE (lhs_type) != INTEGER_TYPE) if (TREE_CODE (lhs_type) != INTEGER_TYPE)
return true; return true;
return ((2 * TYPE_PRECISION (rhs1_type) != TYPE_PRECISION (lhs_type)) return ((2 * TYPE_PRECISION (rhs1_type) > TYPE_PRECISION (lhs_type))
|| (TYPE_PRECISION (rhs1_type) != TYPE_PRECISION (rhs2_type))); || (TYPE_PRECISION (rhs1_type) != TYPE_PRECISION (rhs2_type)));
case WIDEN_SUM_EXPR: case WIDEN_SUM_EXPR:
...@@ -3655,7 +3655,7 @@ verify_gimple_assign_ternary (gimple stmt) ...@@ -3655,7 +3655,7 @@ verify_gimple_assign_ternary (gimple stmt)
&& !FIXED_POINT_TYPE_P (rhs1_type)) && !FIXED_POINT_TYPE_P (rhs1_type))
|| !useless_type_conversion_p (rhs1_type, rhs2_type) || !useless_type_conversion_p (rhs1_type, rhs2_type)
|| !useless_type_conversion_p (lhs_type, rhs3_type) || !useless_type_conversion_p (lhs_type, rhs3_type)
|| 2 * TYPE_PRECISION (rhs1_type) != TYPE_PRECISION (lhs_type) || 2 * TYPE_PRECISION (rhs1_type) > TYPE_PRECISION (lhs_type)
|| TYPE_PRECISION (rhs1_type) != TYPE_PRECISION (rhs2_type)) || TYPE_PRECISION (rhs1_type) != TYPE_PRECISION (rhs2_type))
{ {
error ("type mismatch in widening multiply-accumulate expression"); error ("type mismatch in widening multiply-accumulate expression");
......
...@@ -1086,6 +1086,16 @@ build_and_insert_ref (gimple_stmt_iterator *gsi, location_t loc, tree type, ...@@ -1086,6 +1086,16 @@ build_and_insert_ref (gimple_stmt_iterator *gsi, location_t loc, tree type,
return result; return result;
} }
/* Build a gimple assignment to cast VAL to TARGET. Insert the statement
prior to GSI's current position, and return the fresh SSA name. */
static tree
build_and_insert_cast (gimple_stmt_iterator *gsi, location_t loc,
tree target, tree val)
{
return build_and_insert_binop (gsi, loc, target, CONVERT_EXPR, val, NULL);
}
/* ARG0 and ARG1 are the two arguments to a pow builtin call in GSI /* ARG0 and ARG1 are the two arguments to a pow builtin call in GSI
with location info LOC. If possible, create an equivalent and with location info LOC. If possible, create an equivalent and
less expensive sequence of statements prior to GSI, and return an less expensive sequence of statements prior to GSI, and return an
...@@ -1959,8 +1969,8 @@ struct gimple_opt_pass pass_optimize_bswap = ...@@ -1959,8 +1969,8 @@ struct gimple_opt_pass pass_optimize_bswap =
/* Return true if RHS is a suitable operand for a widening multiplication. /* Return true if RHS is a suitable operand for a widening multiplication.
There are two cases: There are two cases:
- RHS makes some value twice as wide. Store that value in *NEW_RHS_OUT - RHS makes some value at least twice as wide. Store that value
if so, and store its type in *TYPE_OUT. 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, - RHS is an integer constant. Store that value in *NEW_RHS_OUT if so,
but leave *TYPE_OUT untouched. */ but leave *TYPE_OUT untouched. */
...@@ -1988,7 +1998,7 @@ is_widening_mult_rhs_p (tree rhs, tree *type_out, tree *new_rhs_out) ...@@ -1988,7 +1998,7 @@ is_widening_mult_rhs_p (tree rhs, tree *type_out, tree *new_rhs_out)
rhs1 = gimple_assign_rhs1 (stmt); rhs1 = gimple_assign_rhs1 (stmt);
type1 = TREE_TYPE (rhs1); type1 = TREE_TYPE (rhs1);
if (TREE_CODE (type1) != TREE_CODE (type) if (TREE_CODE (type1) != TREE_CODE (type)
|| TYPE_PRECISION (type1) * 2 != TYPE_PRECISION (type)) || TYPE_PRECISION (type1) * 2 > TYPE_PRECISION (type))
return false; return false;
*new_rhs_out = rhs1; *new_rhs_out = rhs1;
...@@ -2044,6 +2054,10 @@ is_widening_mult_p (gimple stmt, ...@@ -2044,6 +2054,10 @@ is_widening_mult_p (gimple stmt,
*type2_out = *type1_out; *type2_out = *type1_out;
} }
/* FIXME: remove this restriction. */
if (TYPE_PRECISION (*type1_out) != TYPE_PRECISION (*type2_out))
return false;
return true; return true;
} }
...@@ -2052,12 +2066,14 @@ is_widening_mult_p (gimple stmt, ...@@ -2052,12 +2066,14 @@ is_widening_mult_p (gimple stmt,
value is true iff we converted the statement. */ value is true iff we converted the statement. */
static bool static bool
convert_mult_to_widen (gimple stmt) convert_mult_to_widen (gimple stmt, gimple_stmt_iterator *gsi)
{ {
tree lhs, rhs1, rhs2, type, type1, type2; tree lhs, rhs1, rhs2, type, type1, type2, tmp;
enum insn_code handler; enum insn_code handler;
enum machine_mode to_mode, from_mode; enum machine_mode to_mode, from_mode, actual_mode;
optab op; optab op;
int actual_precision;
location_t loc = gimple_location (stmt);
lhs = gimple_assign_lhs (stmt); lhs = gimple_assign_lhs (stmt);
type = TREE_TYPE (lhs); type = TREE_TYPE (lhs);
...@@ -2077,13 +2093,32 @@ convert_mult_to_widen (gimple stmt) ...@@ -2077,13 +2093,32 @@ convert_mult_to_widen (gimple stmt)
else else
op = usmul_widen_optab; op = usmul_widen_optab;
handler = widening_optab_handler (op, to_mode, from_mode); handler = find_widening_optab_handler_and_mode (op, to_mode, from_mode,
0, &actual_mode);
if (handler == CODE_FOR_nothing) if (handler == CODE_FOR_nothing)
return false; return false;
gimple_assign_set_rhs1 (stmt, fold_convert (type1, rhs1)); /* Ensure that the inputs to the handler are in the correct precison
gimple_assign_set_rhs2 (stmt, fold_convert (type2, rhs2)); for the opcode. This will be the full mode size. */
actual_precision = GET_MODE_PRECISION (actual_mode);
if (actual_precision != TYPE_PRECISION (type1))
{
tmp = create_tmp_var (build_nonstandard_integer_type
(actual_precision, TYPE_UNSIGNED (type1)),
NULL);
rhs1 = build_and_insert_cast (gsi, loc, tmp, rhs1);
/* Reuse the same type info, if possible. */
if (TYPE_UNSIGNED (type1) != TYPE_UNSIGNED (type2))
tmp = create_tmp_var (build_nonstandard_integer_type
(actual_precision, TYPE_UNSIGNED (type2)),
NULL);
rhs2 = build_and_insert_cast (gsi, loc, tmp, rhs2);
}
gimple_assign_set_rhs1 (stmt, rhs1);
gimple_assign_set_rhs2 (stmt, rhs2);
gimple_assign_set_rhs_code (stmt, WIDEN_MULT_EXPR); gimple_assign_set_rhs_code (stmt, WIDEN_MULT_EXPR);
update_stmt (stmt); update_stmt (stmt);
widen_mul_stats.widen_mults_inserted++; widen_mul_stats.widen_mults_inserted++;
...@@ -2101,11 +2136,15 @@ convert_plusminus_to_widen (gimple_stmt_iterator *gsi, gimple stmt, ...@@ -2101,11 +2136,15 @@ convert_plusminus_to_widen (gimple_stmt_iterator *gsi, gimple stmt,
enum tree_code code) enum tree_code code)
{ {
gimple rhs1_stmt = NULL, rhs2_stmt = NULL; gimple rhs1_stmt = NULL, rhs2_stmt = NULL;
tree type, type1, type2; tree type, type1, type2, tmp;
tree lhs, rhs1, rhs2, mult_rhs1, mult_rhs2, add_rhs; tree lhs, rhs1, rhs2, mult_rhs1, mult_rhs2, add_rhs;
enum tree_code rhs1_code = ERROR_MARK, rhs2_code = ERROR_MARK; enum tree_code rhs1_code = ERROR_MARK, rhs2_code = ERROR_MARK;
optab this_optab; optab this_optab;
enum tree_code wmult_code; enum tree_code wmult_code;
enum insn_code handler;
enum machine_mode to_mode, from_mode, actual_mode;
location_t loc = gimple_location (stmt);
int actual_precision;
lhs = gimple_assign_lhs (stmt); lhs = gimple_assign_lhs (stmt);
type = TREE_TYPE (lhs); type = TREE_TYPE (lhs);
...@@ -2139,39 +2178,33 @@ convert_plusminus_to_widen (gimple_stmt_iterator *gsi, gimple stmt, ...@@ -2139,39 +2178,33 @@ convert_plusminus_to_widen (gimple_stmt_iterator *gsi, gimple stmt,
else else
return false; return false;
if (code == PLUS_EXPR && rhs1_code == MULT_EXPR) /* If code is WIDEN_MULT_EXPR then it would seem unnecessary to call
is_widening_mult_p, but we still need the rhs returns.
It might also appear that it would be sufficient to use the existing
operands of the widening multiply, but that would limit the choice of
multiply-and-accumulate instructions. */
if (code == PLUS_EXPR
&& (rhs1_code == MULT_EXPR || rhs1_code == WIDEN_MULT_EXPR))
{ {
if (!is_widening_mult_p (rhs1_stmt, &type1, &mult_rhs1, if (!is_widening_mult_p (rhs1_stmt, &type1, &mult_rhs1,
&type2, &mult_rhs2)) &type2, &mult_rhs2))
return false; return false;
add_rhs = rhs2; add_rhs = rhs2;
} }
else if (rhs2_code == MULT_EXPR) else if (rhs2_code == MULT_EXPR || rhs2_code == WIDEN_MULT_EXPR)
{ {
if (!is_widening_mult_p (rhs2_stmt, &type1, &mult_rhs1, if (!is_widening_mult_p (rhs2_stmt, &type1, &mult_rhs1,
&type2, &mult_rhs2)) &type2, &mult_rhs2))
return false; return false;
add_rhs = rhs1; 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 else
return false; return false;
to_mode = TYPE_MODE (type);
from_mode = TYPE_MODE (type1);
if (TYPE_UNSIGNED (type1) != TYPE_UNSIGNED (type2)) if (TYPE_UNSIGNED (type1) != TYPE_UNSIGNED (type2))
return false; return false;
...@@ -2179,15 +2212,26 @@ convert_plusminus_to_widen (gimple_stmt_iterator *gsi, gimple stmt, ...@@ -2179,15 +2212,26 @@ convert_plusminus_to_widen (gimple_stmt_iterator *gsi, gimple stmt,
accumulate in this mode/signedness combination, otherwise accumulate in this mode/signedness combination, otherwise
this transformation is likely to pessimize code. */ this transformation is likely to pessimize code. */
this_optab = optab_for_tree_code (wmult_code, type1, optab_default); this_optab = optab_for_tree_code (wmult_code, type1, optab_default);
if (widening_optab_handler (this_optab, TYPE_MODE (type), TYPE_MODE (type1)) handler = find_widening_optab_handler_and_mode (this_optab, to_mode,
== CODE_FOR_nothing) from_mode, 0, &actual_mode);
if (handler == CODE_FOR_nothing)
return false; return false;
/* ??? May need some type verification here? */ /* Ensure that the inputs to the handler are in the correct precison
for the opcode. This will be the full mode size. */
actual_precision = GET_MODE_PRECISION (actual_mode);
if (actual_precision != TYPE_PRECISION (type1))
{
tmp = create_tmp_var (build_nonstandard_integer_type
(actual_precision, TYPE_UNSIGNED (type1)),
NULL);
mult_rhs1 = build_and_insert_cast (gsi, loc, tmp, mult_rhs1);
mult_rhs2 = build_and_insert_cast (gsi, loc, tmp, mult_rhs2);
}
gimple_assign_set_rhs_with_ops_1 (gsi, wmult_code, gimple_assign_set_rhs_with_ops_1 (gsi, wmult_code, mult_rhs1, mult_rhs2,
fold_convert (type1, mult_rhs1),
fold_convert (type2, mult_rhs2),
add_rhs); add_rhs);
update_stmt (gsi_stmt (*gsi)); update_stmt (gsi_stmt (*gsi));
widen_mul_stats.maccs_inserted++; widen_mul_stats.maccs_inserted++;
...@@ -2399,7 +2443,7 @@ execute_optimize_widening_mul (void) ...@@ -2399,7 +2443,7 @@ execute_optimize_widening_mul (void)
switch (code) switch (code)
{ {
case MULT_EXPR: case MULT_EXPR:
if (!convert_mult_to_widen (stmt) if (!convert_mult_to_widen (stmt, &gsi)
&& convert_mult_to_fma (stmt, && convert_mult_to_fma (stmt,
gimple_assign_rhs1 (stmt), gimple_assign_rhs1 (stmt),
gimple_assign_rhs2 (stmt))) gimple_assign_rhs2 (stmt)))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment