Commit 68b948d3 by Richard Biener Committed by Richard Biener

re PR tree-optimization/45397 (Issues with integer narrowing conversions)

2017-02-27  Richard Biener  <rguenther@suse.de>

	PR tree-optimization/45397
	* tree-ssa-pre.c (eliminate_insert): Handle BIT_AND_EXPR.
	* tree-ssa-sccvn.c (valueized_wider_op): New helper.
	(visit_nary_op): Add pattern matching for CSEing sign-changed
	or truncated operations with wider ones.

	* gcc.dg/tree-ssa/pr45397.c: New testcase.

From-SVN: r245752
parent 69a2e8a1
2017-02-27 Richard Biener <rguenther@suse.de> 2017-02-27 Richard Biener <rguenther@suse.de>
PR tree-optimization/45397
* tree-ssa-pre.c (eliminate_insert): Handle BIT_AND_EXPR.
* tree-ssa-sccvn.c (valueized_wider_op): New helper.
(visit_nary_op): Add pattern matching for CSEing sign-changed
or truncated operations with wider ones.
2017-02-27 Richard Biener <rguenther@suse.de>
PR tree-optimization/79690 PR tree-optimization/79690
* tree-vect-stmts.c (vectorizable_store): Use vector type * tree-vect-stmts.c (vectorizable_store): Use vector type
built from the DR with address-space. built from the DR with address-space.
......
2017-02-27 Richard Biener <rguenther@suse.de> 2017-02-27 Richard Biener <rguenther@suse.de>
PR tree-optimization/45397
* gcc.dg/tree-ssa/pr45397.c: New testcase.
2017-02-27 Richard Biener <rguenther@suse.de>
PR tree-optimization/79690 PR tree-optimization/79690
* gcc.target/i386/pr79690.c: New testcase. * gcc.target/i386/pr79690.c: New testcase.
......
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-phiopt1" } */
int foo_add (const unsigned char *tmp, int i, int val)
{
return (unsigned char)(((tmp[i] + val)>0xFF)?0xFF:(((tmp[i] + val)<0)?0:(tmp[i] + val)));
}
int foo_sub (const unsigned char *tmp, int i, int val)
{
return (unsigned char)(((tmp[i] - val)>0xFF)?0xFF:(((tmp[i] - val)<0)?0:(tmp[i] - val)));
}
int foo_mul (const unsigned char *tmp, int i, int val)
{
return (unsigned char)(((tmp[i] * val)>0xFF)?0xFF:(((tmp[i] * val)<0)?0:(tmp[i] * val)));
}
/* All cases should end up using min/max for the saturated operations and
have no control flow. */
/* { dg-final { scan-tree-dump-times "MAX_EXPR" 3 "phiopt1" } } */
/* { dg-final { scan-tree-dump-times "MIN_EXPR" 3 "phiopt1" } } */
/* { dg-final { scan-tree-dump-not "if " "phiopt1" } } */
...@@ -4103,7 +4103,9 @@ eliminate_insert (gimple_stmt_iterator *gsi, tree val) ...@@ -4103,7 +4103,9 @@ eliminate_insert (gimple_stmt_iterator *gsi, tree val)
if (!is_gimple_assign (stmt) if (!is_gimple_assign (stmt)
|| (!CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (stmt)) || (!CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (stmt))
&& gimple_assign_rhs_code (stmt) != VIEW_CONVERT_EXPR && gimple_assign_rhs_code (stmt) != VIEW_CONVERT_EXPR
&& gimple_assign_rhs_code (stmt) != BIT_FIELD_REF)) && gimple_assign_rhs_code (stmt) != BIT_FIELD_REF
&& (gimple_assign_rhs_code (stmt) != BIT_AND_EXPR
|| TREE_CODE (gimple_assign_rhs2 (stmt)) != INTEGER_CST)))
return NULL_TREE; return NULL_TREE;
tree op = gimple_assign_rhs1 (stmt); tree op = gimple_assign_rhs1 (stmt);
...@@ -4121,6 +4123,9 @@ eliminate_insert (gimple_stmt_iterator *gsi, tree val) ...@@ -4121,6 +4123,9 @@ eliminate_insert (gimple_stmt_iterator *gsi, tree val)
TREE_TYPE (val), leader, TREE_TYPE (val), leader,
TREE_OPERAND (gimple_assign_rhs1 (stmt), 1), TREE_OPERAND (gimple_assign_rhs1 (stmt), 1),
TREE_OPERAND (gimple_assign_rhs1 (stmt), 2)); TREE_OPERAND (gimple_assign_rhs1 (stmt), 2));
else if (gimple_assign_rhs_code (stmt) == BIT_AND_EXPR)
res = gimple_build (&stmts, BIT_AND_EXPR,
TREE_TYPE (val), leader, gimple_assign_rhs2 (stmt));
else else
res = gimple_build (&stmts, gimple_assign_rhs_code (stmt), res = gimple_build (&stmts, gimple_assign_rhs_code (stmt),
TREE_TYPE (val), leader); TREE_TYPE (val), leader);
......
...@@ -3447,23 +3447,125 @@ visit_copy (tree lhs, tree rhs) ...@@ -3447,23 +3447,125 @@ visit_copy (tree lhs, tree rhs)
return set_ssa_val_to (lhs, rhs); return set_ssa_val_to (lhs, rhs);
} }
/* Lookup a value for OP in type WIDE_TYPE where the value in type of OP
is the same. */
static tree
valueized_wider_op (tree wide_type, tree op)
{
if (TREE_CODE (op) == SSA_NAME)
op = SSA_VAL (op);
/* Either we have the op widened available. */
tree ops[3] = {};
ops[0] = op;
tree tem = vn_nary_op_lookup_pieces (1, NOP_EXPR,
wide_type, ops, NULL);
if (tem)
return tem;
/* Or the op is truncated from some existing value. */
if (TREE_CODE (op) == SSA_NAME)
{
gimple *def = SSA_NAME_DEF_STMT (op);
if (is_gimple_assign (def)
&& CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def)))
{
tem = gimple_assign_rhs1 (def);
if (useless_type_conversion_p (wide_type, TREE_TYPE (tem)))
{
if (TREE_CODE (tem) == SSA_NAME)
tem = SSA_VAL (tem);
return tem;
}
}
}
/* For constants simply extend it. */
if (TREE_CODE (op) == INTEGER_CST)
return wide_int_to_tree (wide_type, op);
return NULL_TREE;
}
/* Visit a nary operator RHS, value number it, and return true if the /* Visit a nary operator RHS, value number it, and return true if the
value number of LHS has changed as a result. */ value number of LHS has changed as a result. */
static bool static bool
visit_nary_op (tree lhs, gimple *stmt) visit_nary_op (tree lhs, gassign *stmt)
{ {
bool changed = false;
tree result = vn_nary_op_lookup_stmt (stmt, NULL); tree result = vn_nary_op_lookup_stmt (stmt, NULL);
if (result) if (result)
changed = set_ssa_val_to (lhs, result); return set_ssa_val_to (lhs, result);
else
/* Do some special pattern matching for redundancies of operations
in different types. */
enum tree_code code = gimple_assign_rhs_code (stmt);
tree type = TREE_TYPE (lhs);
tree rhs1 = gimple_assign_rhs1 (stmt);
switch (code)
{ {
changed = set_ssa_val_to (lhs, lhs); CASE_CONVERT:
vn_nary_op_insert_stmt (stmt, lhs); /* Match arithmetic done in a different type where we can easily
substitute the result from some earlier sign-changed or widened
operation. */
if (INTEGRAL_TYPE_P (type)
&& TREE_CODE (rhs1) == SSA_NAME
/* We only handle sign-changes or zero-extension -> & mask. */
&& ((TYPE_UNSIGNED (TREE_TYPE (rhs1))
&& TYPE_PRECISION (type) > TYPE_PRECISION (TREE_TYPE (rhs1)))
|| TYPE_PRECISION (type) == TYPE_PRECISION (TREE_TYPE (rhs1))))
{
gassign *def = dyn_cast <gassign *> (SSA_NAME_DEF_STMT (rhs1));
if (def
&& (gimple_assign_rhs_code (def) == PLUS_EXPR
|| gimple_assign_rhs_code (def) == MINUS_EXPR
|| gimple_assign_rhs_code (def) == MULT_EXPR))
{
tree ops[3] = {};
/* Either we have the op widened available. */
ops[0] = valueized_wider_op (type,
gimple_assign_rhs1 (def));
if (ops[0])
ops[1] = valueized_wider_op (type,
gimple_assign_rhs2 (def));
if (ops[0] && ops[1])
{
ops[0] = vn_nary_op_lookup_pieces
(2, gimple_assign_rhs_code (def), type, ops, NULL);
/* We have wider operation available. */
if (ops[0])
{
unsigned lhs_prec = TYPE_PRECISION (type);
unsigned rhs_prec = TYPE_PRECISION (TREE_TYPE (rhs1));
if (lhs_prec == rhs_prec)
{
ops[1] = NULL_TREE;
result = vn_nary_build_or_lookup (NOP_EXPR,
type, ops);
if (result)
return set_ssa_val_to (lhs, result);
}
else
{
ops[1] = wide_int_to_tree (type,
wi::mask (rhs_prec, false,
lhs_prec));
result = vn_nary_build_or_lookup (BIT_AND_EXPR,
TREE_TYPE (lhs),
ops);
if (result)
return set_ssa_val_to (lhs, result);
}
}
}
}
}
default:;
} }
bool changed = set_ssa_val_to (lhs, lhs);
vn_nary_op_insert_stmt (stmt, lhs);
return changed; return changed;
} }
......
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