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:
parent
87b6c18c01
commit
f84e7fd6cb
@ -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>
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
54
gcc/match.pd
54
gcc/match.pd
@ -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))))))
|
||||||
|
@ -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.
|
||||||
|
@ -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" } } */
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user