match.pd: Add tcc_comparison...

2014-11-13  Richard Biener  <rguenther@suse.de>

	* match.pd: Add tcc_comparison, inverted_tcc_comparison
	and inverted_tcc_comparison_with_nans operator lists.
	Use tcc_comparison in the truth_valued_p predicate definition.
	Restrict logical_inverted_value with bit_xor to integral types.
	Build a boolean true for simplifying x |^ !x because of
	vector types.  Implement patterns from forward_propagate_comparison
	* tree-ssa-forwprop.c (forward_propagate_comparison): Remove.
	(get_prop_dest_stmt): Likewise.
	(pass_forwprop::execute): Do not call it.
	* fold-const.c (fold_unary_loc): Remove the pattern here.

	* gcc.dg/tree-ssa/forwprop-28.c: Adjust.

From-SVN: r217496
This commit is contained in:
Richard Biener 2014-11-13 13:58:59 +00:00 committed by Richard Biener
parent 87b6c18c01
commit f84e7fd6cb
6 changed files with 74 additions and 137 deletions

View File

@ -1,3 +1,16 @@
2014-11-13 Richard Biener <rguenther@suse.de>
* match.pd: Add tcc_comparison, inverted_tcc_comparison
and inverted_tcc_comparison_with_nans operator lists.
Use tcc_comparison in the truth_valued_p predicate definition.
Restrict logical_inverted_value with bit_xor to integral types.
Build a boolean true for simplifying x |^ !x because of
vector types. Implement patterns from forward_propagate_comparison
* tree-ssa-forwprop.c (forward_propagate_comparison): Remove.
(get_prop_dest_stmt): Likewise.
(pass_forwprop::execute): Do not call it.
* fold-const.c (fold_unary_loc): Remove the pattern here.
2014-11-13 Ilya Verbin <ilya.verbin@intel.com> 2014-11-13 Ilya Verbin <ilya.verbin@intel.com>
Andrey Turetskiy <andrey.turetskiy@intel.com> Andrey Turetskiy <andrey.turetskiy@intel.com>

View File

@ -7938,18 +7938,6 @@ fold_unary_loc (location_t loc, enum tree_code code, tree type, tree op0)
if (i == count) if (i == count)
return build_vector (type, elements); return build_vector (type, elements);
} }
else if (COMPARISON_CLASS_P (arg0)
&& (VECTOR_TYPE_P (type)
|| (INTEGRAL_TYPE_P (type) && TYPE_PRECISION (type) == 1)))
{
tree op_type = TREE_TYPE (TREE_OPERAND (arg0, 0));
enum tree_code subcode = invert_tree_comparison (TREE_CODE (arg0),
HONOR_NANS (TYPE_MODE (op_type)));
if (subcode != ERROR_MARK)
return build2_loc (loc, subcode, type, TREE_OPERAND (arg0, 0),
TREE_OPERAND (arg0, 1));
}
return NULL_TREE; return NULL_TREE;

View File

@ -31,6 +31,14 @@ along with GCC; see the file COPYING3. If not see
CONSTANT_CLASS_P CONSTANT_CLASS_P
tree_expr_nonnegative_p) tree_expr_nonnegative_p)
/* Operator lists. */
(define_operator_list tcc_comparison
lt le eq ne ge gt unordered ordered unlt unle ungt unge uneq ltgt)
(define_operator_list inverted_tcc_comparison
ge gt ne eq lt le ordered unordered ge gt le lt ltgt uneq)
(define_operator_list inverted_tcc_comparison_with_nans
unge ungt ne eq unlt unle ordered unordered ge gt le lt ltgt uneq)
/* Simplifications of operations with one constant operand and /* Simplifications of operations with one constant operand and
simplifications to constants or single values. */ simplifications to constants or single values. */
@ -172,7 +180,7 @@ along with GCC; see the file COPYING3. If not see
(match truth_valued_p (match truth_valued_p
@0 @0
(if (INTEGRAL_TYPE_P (type) && TYPE_PRECISION (type) == 1))) (if (INTEGRAL_TYPE_P (type) && TYPE_PRECISION (type) == 1)))
(for op (lt le eq ne ge gt truth_and truth_andif truth_or truth_orif truth_xor) (for op (tcc_comparison truth_and truth_andif truth_or truth_orif truth_xor)
(match truth_valued_p (match truth_valued_p
(op @0 @1))) (op @0 @1)))
(match truth_valued_p (match truth_valued_p
@ -187,7 +195,8 @@ along with GCC; see the file COPYING3. If not see
(ne truth_valued_p@0 integer_onep) (ne truth_valued_p@0 integer_onep)
(if (INTEGRAL_TYPE_P (TREE_TYPE (@0))))) (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)))))
(match (logical_inverted_value @0) (match (logical_inverted_value @0)
(bit_xor truth_valued_p@0 integer_onep)) (bit_xor truth_valued_p@0 integer_onep)
(if (INTEGRAL_TYPE_P (TREE_TYPE (@0)))))
/* X & !X -> 0. */ /* X & !X -> 0. */
(simplify (simplify
@ -197,7 +206,7 @@ along with GCC; see the file COPYING3. If not see
(for op (bit_ior bit_xor) (for op (bit_ior bit_xor)
(simplify (simplify
(op:c truth_valued_p@0 (logical_inverted_value @0)) (op:c truth_valued_p@0 (logical_inverted_value @0))
{ build_one_cst (type); })) { constant_boolean_node (true, type); }))
(for bitop (bit_and bit_ior) (for bitop (bit_and bit_ior)
rbitop (bit_ior bit_and) rbitop (bit_ior bit_and)
@ -632,3 +641,42 @@ along with GCC; see the file COPYING3. If not see
(simplify (simplify
(cond (logical_inverted_value truth_valued_p@0) @1 @2) (cond (logical_inverted_value truth_valued_p@0) @1 @2)
(cond @0 @2 @1)) (cond @0 @2 @1))
/* Simplifications of comparisons. */
/* We can simplify a logical negation of a comparison to the
inverted comparison. As we cannot compute an expression
operator using invert_tree_comparison we have to simulate
that with expression code iteration. */
(for cmp (tcc_comparison)
icmp (inverted_tcc_comparison)
ncmp (inverted_tcc_comparison_with_nans)
/* Ideally we'd like to combine the following two patterns
and handle some more cases by using
(logical_inverted_value (cmp @0 @1))
here but for that genmatch would need to "inline" that.
For now implement what forward_propagate_comparison did. */
(simplify
(bit_not (cmp @0 @1))
(if (VECTOR_TYPE_P (type)
|| (INTEGRAL_TYPE_P (type) && TYPE_PRECISION (type) == 1))
/* Comparison inversion may be impossible for trapping math,
invert_tree_comparison will tell us. But we can't use
a computed operator in the replacement tree thus we have
to play the trick below. */
(with { enum tree_code ic = invert_tree_comparison
(cmp, HONOR_NANS (TYPE_MODE (TREE_TYPE (@0)))); }
(if (ic == icmp)
(icmp @0 @1))
(if (ic == ncmp)
(ncmp @0 @1)))))
(simplify
(bit_xor (cmp @0 @1) integer_onep)
(if (INTEGRAL_TYPE_P (type))
(with { enum tree_code ic = invert_tree_comparison
(cmp, HONOR_NANS (TYPE_MODE (TREE_TYPE (@0)))); }
(if (ic == icmp)
(icmp @0 @1))
(if (ic == ncmp)
(ncmp @0 @1))))))

View File

@ -1,3 +1,7 @@
2014-11-13 Richard Biener <rguenther@suse.de>
* gcc.dg/tree-ssa/forwprop-28.c: Adjust.
2014-11-12 Alexander Ivchenko <alexander.ivchenko@intel.com> 2014-11-12 Alexander Ivchenko <alexander.ivchenko@intel.com>
* lib/target-supports.exp (error_h): New check. * lib/target-supports.exp (error_h): New check.

View File

@ -79,6 +79,11 @@ test_8 (int code)
oof (); oof ();
} }
/* { dg-final { scan-tree-dump-times "simplified to if \\\(\[^ ]* <" 8 "forwprop1"} } */ /* ??? This used to check for 8 times transforming the combined conditional
to a ordered compare. But the transform does not trigger if we transform
the negated code == 22 compare to code != 22 first. It turns out if
we do that we even generate better code on x86 at least. */
/* { dg-final { scan-tree-dump-times "simplified to if \\\(\[^ ]* <" 4 "forwprop1"} } */
/* { dg-final { cleanup-tree-dump "forwprop1" } } */ /* { dg-final { cleanup-tree-dump "forwprop1" } } */

View File

@ -233,38 +233,6 @@ fwprop_invalidate_lattice (tree name)
} }
/* Get the next statement we can propagate NAME's value into skipping
trivial copies. Returns the statement that is suitable as a
propagation destination or NULL_TREE if there is no such one.
This only returns destinations in a single-use chain. FINAL_NAME_P
if non-NULL is written to the ssa name that represents the use. */
static gimple
get_prop_dest_stmt (tree name, tree *final_name_p)
{
use_operand_p use;
gimple use_stmt;
do {
/* If name has multiple uses, bail out. */
if (!single_imm_use (name, &use, &use_stmt))
return NULL;
/* If this is not a trivial copy, we found it. */
if (!gimple_assign_ssa_name_copy_p (use_stmt)
|| gimple_assign_rhs1 (use_stmt) != name)
break;
/* Continue searching uses of the copy destination. */
name = gimple_assign_lhs (use_stmt);
} while (1);
if (final_name_p)
*final_name_p = name;
return use_stmt;
}
/* Get the statement we can propagate from into NAME skipping /* Get the statement we can propagate from into NAME skipping
trivial copies. Returns the statement which defines the trivial copies. Returns the statement which defines the
propagation source or NULL_TREE if there is no such one. propagation source or NULL_TREE if there is no such one.
@ -1060,90 +1028,6 @@ forward_propagate_addr_expr (tree name, tree rhs, bool parent_single_use_p)
} }
/* Forward propagate the comparison defined in *DEFGSI like
cond_1 = x CMP y to uses of the form
a_1 = (T')cond_1
a_1 = !cond_1
a_1 = cond_1 != 0
Returns true if stmt is now unused. Advance DEFGSI to the next
statement. */
static bool
forward_propagate_comparison (gimple_stmt_iterator *defgsi)
{
gimple stmt = gsi_stmt (*defgsi);
tree name = gimple_assign_lhs (stmt);
gimple use_stmt;
tree tmp = NULL_TREE;
gimple_stmt_iterator gsi;
enum tree_code code;
tree lhs;
/* Don't propagate ssa names that occur in abnormal phis. */
if ((TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME
&& SSA_NAME_OCCURS_IN_ABNORMAL_PHI (gimple_assign_rhs1 (stmt)))
|| (TREE_CODE (gimple_assign_rhs2 (stmt)) == SSA_NAME
&& SSA_NAME_OCCURS_IN_ABNORMAL_PHI (gimple_assign_rhs2 (stmt))))
goto bailout;
/* Do not un-cse comparisons. But propagate through copies. */
use_stmt = get_prop_dest_stmt (name, &name);
if (!use_stmt
|| !is_gimple_assign (use_stmt))
goto bailout;
code = gimple_assign_rhs_code (use_stmt);
lhs = gimple_assign_lhs (use_stmt);
if (!INTEGRAL_TYPE_P (TREE_TYPE (lhs)))
goto bailout;
/* We can propagate the condition into a statement that
computes the logical negation of the comparison result. */
if ((code == BIT_NOT_EXPR
&& TYPE_PRECISION (TREE_TYPE (lhs)) == 1)
|| (code == BIT_XOR_EXPR
&& integer_onep (gimple_assign_rhs2 (use_stmt))))
{
tree type = TREE_TYPE (gimple_assign_rhs1 (stmt));
bool nans = HONOR_NANS (TYPE_MODE (type));
enum tree_code inv_code;
inv_code = invert_tree_comparison (gimple_assign_rhs_code (stmt), nans);
if (inv_code == ERROR_MARK)
goto bailout;
tmp = build2 (inv_code, TREE_TYPE (lhs), gimple_assign_rhs1 (stmt),
gimple_assign_rhs2 (stmt));
}
else
goto bailout;
gsi = gsi_for_stmt (use_stmt);
gimple_assign_set_rhs_from_tree (&gsi, unshare_expr (tmp));
use_stmt = gsi_stmt (gsi);
update_stmt (use_stmt);
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, " Replaced '");
print_gimple_expr (dump_file, stmt, 0, dump_flags);
fprintf (dump_file, "' with '");
print_gimple_expr (dump_file, use_stmt, 0, dump_flags);
fprintf (dump_file, "'\n");
}
/* When we remove stmt now the iterator defgsi goes off it's current
sequence, hence advance it now. */
gsi_next (defgsi);
/* Remove defining statements. */
return remove_prop_source_from_use (name);
bailout:
gsi_next (defgsi);
return false;
}
/* Helper function for simplify_gimple_switch. Remove case labels that /* Helper function for simplify_gimple_switch. Remove case labels that
have values outside the range of the new type. */ have values outside the range of the new type. */
@ -2316,11 +2200,6 @@ pass_forwprop::execute (function *fun)
else else
gsi_next (&gsi); gsi_next (&gsi);
} }
else if (TREE_CODE_CLASS (code) == tcc_comparison)
{
if (forward_propagate_comparison (&gsi))
cfg_changed = true;
}
else else
gsi_next (&gsi); gsi_next (&gsi);
} }