/* Forward declarations for some mutually recursive functions. */
static tree
-and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
+and_comparisons_1 (tree type, enum tree_code code1, tree op1a, tree op1b,
enum tree_code code2, tree op2a, tree op2b);
static tree
-and_var_with_comparison (tree var, bool invert,
+and_var_with_comparison (tree type, tree var, bool invert,
enum tree_code code2, tree op2a, tree op2b);
static tree
-and_var_with_comparison_1 (gimple *stmt,
+and_var_with_comparison_1 (tree type, gimple *stmt,
enum tree_code code2, tree op2a, tree op2b);
static tree
-or_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
+or_comparisons_1 (tree, enum tree_code code1, tree op1a, tree op1b,
enum tree_code code2, tree op2a, tree op2b);
static tree
-or_var_with_comparison (tree var, bool invert,
+or_var_with_comparison (tree, tree var, bool invert,
enum tree_code code2, tree op2a, tree op2b);
static tree
-or_var_with_comparison_1 (gimple *stmt,
+or_var_with_comparison_1 (tree, gimple *stmt,
enum tree_code code2, tree op2a, tree op2b);
/* Helper function for and_comparisons_1: try to simplify the AND of the
Return NULL_EXPR if we can't simplify this to a single expression. */
static tree
-and_var_with_comparison (tree var, bool invert,
+and_var_with_comparison (tree type, tree var, bool invert,
enum tree_code code2, tree op2a, tree op2b)
{
tree t;
!var AND (op2a code2 op2b) => !(var OR !(op2a code2 op2b))
Then we only have to consider the simpler non-inverted cases. */
if (invert)
- t = or_var_with_comparison_1 (stmt,
+ t = or_var_with_comparison_1 (type, stmt,
invert_tree_comparison (code2, false),
op2a, op2b);
else
- t = and_var_with_comparison_1 (stmt, code2, op2a, op2b);
+ t = and_var_with_comparison_1 (type, stmt, code2, op2a, op2b);
return canonicalize_bool (t, invert);
}
Return NULL_EXPR if we can't simplify this to a single expression. */
static tree
-and_var_with_comparison_1 (gimple *stmt,
+and_var_with_comparison_1 (tree type, gimple *stmt,
enum tree_code code2, tree op2a, tree op2b)
{
tree var = gimple_assign_lhs (stmt);
/* If the definition is a comparison, recurse on it. */
if (TREE_CODE_CLASS (innercode) == tcc_comparison)
{
- tree t = and_comparisons_1 (innercode,
+ tree t = and_comparisons_1 (type, innercode,
gimple_assign_rhs1 (stmt),
gimple_assign_rhs2 (stmt),
code2,
else if (inner1 == false_test_var)
return (is_and
? boolean_false_node
- : and_var_with_comparison (inner2, false, code2, op2a, op2b));
+ : and_var_with_comparison (type, inner2, false, code2, op2a,
+ op2b));
else if (inner2 == false_test_var)
return (is_and
? boolean_false_node
- : and_var_with_comparison (inner1, false, code2, op2a, op2b));
+ : and_var_with_comparison (type, inner1, false, code2, op2a,
+ op2b));
/* Next, redistribute/reassociate the AND across the inner tests.
Compute the first partial result, (inner1 AND (op2a code op2b)) */
if (TREE_CODE (inner1) == SSA_NAME
&& is_gimple_assign (s = SSA_NAME_DEF_STMT (inner1))
&& TREE_CODE_CLASS (gimple_assign_rhs_code (s)) == tcc_comparison
- && (t = maybe_fold_and_comparisons (gimple_assign_rhs_code (s),
+ && (t = maybe_fold_and_comparisons (type, gimple_assign_rhs_code (s),
gimple_assign_rhs1 (s),
gimple_assign_rhs2 (s),
code2, op2a, op2b)))
if (TREE_CODE (inner2) == SSA_NAME
&& is_gimple_assign (s = SSA_NAME_DEF_STMT (inner2))
&& TREE_CODE_CLASS (gimple_assign_rhs_code (s)) == tcc_comparison
- && (t = maybe_fold_and_comparisons (gimple_assign_rhs_code (s),
+ && (t = maybe_fold_and_comparisons (type, gimple_assign_rhs_code (s),
gimple_assign_rhs1 (s),
gimple_assign_rhs2 (s),
code2, op2a, op2b)))
in the first comparison but not the second. */
static tree
-and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
+and_comparisons_1 (tree type, enum tree_code code1, tree op1a, tree op1b,
enum tree_code code2, tree op2a, tree op2b)
{
tree truth_type = truth_type_for (TREE_TYPE (op1a));
{
case GIMPLE_ASSIGN:
/* Try to simplify by copy-propagating the definition. */
- return and_var_with_comparison (op1a, invert, code2, op2a, op2b);
+ return and_var_with_comparison (type, op1a, invert, code2, op2a,
+ op2b);
case GIMPLE_PHI:
/* If every argument to the PHI produces the same result when
gimple_bb (def_stmt),
gimple_bb (stmt)))
return NULL_TREE;
- temp = and_var_with_comparison (arg, invert, code2,
+ temp = and_var_with_comparison (type, arg, invert, code2,
op2a, op2b);
if (!temp)
return NULL_TREE;
return NULL_TREE;
}
+/* Helper function for maybe_fold_and_comparisons and maybe_fold_or_comparisons
+ : try to simplify the AND/OR of the ssa variable VAR with the comparison
+ specified by (OP2A CODE2 OP2B) from match.pd. Return NULL_EXPR if we can't
+ simplify this to a single expression. As we are going to lower the cost
+ of building SSA names / gimple stmts significantly, we need to allocate
+ them ont the stack. This will cause the code to be a bit ugly. */
+
+static tree
+maybe_fold_comparisons_from_match_pd (tree type, enum tree_code code,
+ enum tree_code code1,
+ tree op1a, tree op1b,
+ enum tree_code code2, tree op2a,
+ tree op2b)
+{
+ /* Allocate gimple stmt1 on the stack. */
+ gassign *stmt1
+ = (gassign *) XALLOCAVEC (char, gimple_size (GIMPLE_ASSIGN, 3));
+ gimple_init (stmt1, GIMPLE_ASSIGN, 3);
+ gimple_assign_set_rhs_code (stmt1, code1);
+ gimple_assign_set_rhs1 (stmt1, op1a);
+ gimple_assign_set_rhs2 (stmt1, op1b);
+
+ /* Allocate gimple stmt2 on the stack. */
+ gassign *stmt2
+ = (gassign *) XALLOCAVEC (char, gimple_size (GIMPLE_ASSIGN, 3));
+ gimple_init (stmt2, GIMPLE_ASSIGN, 3);
+ gimple_assign_set_rhs_code (stmt2, code2);
+ gimple_assign_set_rhs1 (stmt2, op2a);
+ gimple_assign_set_rhs2 (stmt2, op2b);
+
+ /* Allocate SSA names(lhs1) on the stack. */
+ tree lhs1 = (tree)XALLOCA (tree_ssa_name);
+ memset (lhs1, 0, sizeof (tree_ssa_name));
+ TREE_SET_CODE (lhs1, SSA_NAME);
+ TREE_TYPE (lhs1) = type;
+ init_ssa_name_imm_use (lhs1);
+
+ /* Allocate SSA names(lhs2) on the stack. */
+ tree lhs2 = (tree)XALLOCA (tree_ssa_name);
+ memset (lhs2, 0, sizeof (tree_ssa_name));
+ TREE_SET_CODE (lhs2, SSA_NAME);
+ TREE_TYPE (lhs2) = type;
+ init_ssa_name_imm_use (lhs2);
+
+ gimple_assign_set_lhs (stmt1, lhs1);
+ gimple_assign_set_lhs (stmt2, lhs2);
+
+ gimple_match_op op (gimple_match_cond::UNCOND, code,
+ type, gimple_assign_lhs (stmt1),
+ gimple_assign_lhs (stmt2));
+ if (op.resimplify (NULL, follow_all_ssa_edges))
+ {
+ if (gimple_simplified_result_is_gimple_val (&op))
+ {
+ tree res = op.ops[0];
+ if (res == lhs1)
+ return build2 (code1, type, op1a, op1b);
+ else if (res == lhs2)
+ return build2 (code2, type, op2a, op2b);
+ else
+ return res;
+ }
+ }
+
+ return NULL_TREE;
+}
+
/* Try to simplify the AND of two comparisons, specified by
(OP1A CODE1 OP1B) and (OP2B CODE2 OP2B), respectively.
If this can be simplified to a single expression (without requiring
If the result expression is non-null, it has boolean type. */
tree
-maybe_fold_and_comparisons (enum tree_code code1, tree op1a, tree op1b,
+maybe_fold_and_comparisons (tree type,
+ enum tree_code code1, tree op1a, tree op1b,
enum tree_code code2, tree op2a, tree op2b)
{
- tree t = and_comparisons_1 (code1, op1a, op1b, code2, op2a, op2b);
- if (t)
+ if (tree t = and_comparisons_1 (type, code1, op1a, op1b, code2, op2a, op2b))
return t;
- else
- return and_comparisons_1 (code2, op2a, op2b, code1, op1a, op1b);
+
+ if (tree t = and_comparisons_1 (type, code2, op2a, op2b, code1, op1a, op1b))
+ return t;
+
+ if (tree t = maybe_fold_comparisons_from_match_pd (type, BIT_AND_EXPR, code1,
+ op1a, op1b, code2, op2a,
+ op2b))
+ return t;
+
+ return NULL_TREE;
}
/* Helper function for or_comparisons_1: try to simplify the OR of the
Return NULL_EXPR if we can't simplify this to a single expression. */
static tree
-or_var_with_comparison (tree var, bool invert,
+or_var_with_comparison (tree type, tree var, bool invert,
enum tree_code code2, tree op2a, tree op2b)
{
tree t;
!var OR (op2a code2 op2b) => !(var AND !(op2a code2 op2b))
Then we only have to consider the simpler non-inverted cases. */
if (invert)
- t = and_var_with_comparison_1 (stmt,
+ t = and_var_with_comparison_1 (type, stmt,
invert_tree_comparison (code2, false),
op2a, op2b);
else
- t = or_var_with_comparison_1 (stmt, code2, op2a, op2b);
+ t = or_var_with_comparison_1 (type, stmt, code2, op2a, op2b);
return canonicalize_bool (t, invert);
}
Return NULL_EXPR if we can't simplify this to a single expression. */
static tree
-or_var_with_comparison_1 (gimple *stmt,
+or_var_with_comparison_1 (tree type, gimple *stmt,
enum tree_code code2, tree op2a, tree op2b)
{
tree var = gimple_assign_lhs (stmt);
/* If the definition is a comparison, recurse on it. */
if (TREE_CODE_CLASS (innercode) == tcc_comparison)
{
- tree t = or_comparisons_1 (innercode,
+ tree t = or_comparisons_1 (type, innercode,
gimple_assign_rhs1 (stmt),
gimple_assign_rhs2 (stmt),
code2,
else if (inner1 == false_test_var)
return (is_or
? boolean_true_node
- : or_var_with_comparison (inner2, false, code2, op2a, op2b));
+ : or_var_with_comparison (type, inner2, false, code2, op2a,
+ op2b));
else if (inner2 == false_test_var)
return (is_or
? boolean_true_node
- : or_var_with_comparison (inner1, false, code2, op2a, op2b));
+ : or_var_with_comparison (type, inner1, false, code2, op2a,
+ op2b));
/* Next, redistribute/reassociate the OR across the inner tests.
Compute the first partial result, (inner1 OR (op2a code op2b)) */
if (TREE_CODE (inner1) == SSA_NAME
&& is_gimple_assign (s = SSA_NAME_DEF_STMT (inner1))
&& TREE_CODE_CLASS (gimple_assign_rhs_code (s)) == tcc_comparison
- && (t = maybe_fold_or_comparisons (gimple_assign_rhs_code (s),
+ && (t = maybe_fold_or_comparisons (type, gimple_assign_rhs_code (s),
gimple_assign_rhs1 (s),
gimple_assign_rhs2 (s),
code2, op2a, op2b)))
if (TREE_CODE (inner2) == SSA_NAME
&& is_gimple_assign (s = SSA_NAME_DEF_STMT (inner2))
&& TREE_CODE_CLASS (gimple_assign_rhs_code (s)) == tcc_comparison
- && (t = maybe_fold_or_comparisons (gimple_assign_rhs_code (s),
+ && (t = maybe_fold_or_comparisons (type, gimple_assign_rhs_code (s),
gimple_assign_rhs1 (s),
gimple_assign_rhs2 (s),
code2, op2a, op2b)))
in the first comparison but not the second. */
static tree
-or_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
+or_comparisons_1 (tree type, enum tree_code code1, tree op1a, tree op1b,
enum tree_code code2, tree op2a, tree op2b)
{
tree truth_type = truth_type_for (TREE_TYPE (op1a));
{
case GIMPLE_ASSIGN:
/* Try to simplify by copy-propagating the definition. */
- return or_var_with_comparison (op1a, invert, code2, op2a, op2b);
+ return or_var_with_comparison (type, op1a, invert, code2, op2a,
+ op2b);
case GIMPLE_PHI:
/* If every argument to the PHI produces the same result when
gimple_bb (def_stmt),
gimple_bb (stmt)))
return NULL_TREE;
- temp = or_var_with_comparison (arg, invert, code2,
+ temp = or_var_with_comparison (type, arg, invert, code2,
op2a, op2b);
if (!temp)
return NULL_TREE;
If the result expression is non-null, it has boolean type. */
tree
-maybe_fold_or_comparisons (enum tree_code code1, tree op1a, tree op1b,
+maybe_fold_or_comparisons (tree type,
+ enum tree_code code1, tree op1a, tree op1b,
enum tree_code code2, tree op2a, tree op2b)
{
- tree t = or_comparisons_1 (code1, op1a, op1b, code2, op2a, op2b);
- if (t)
+ if (tree t = or_comparisons_1 (type, code1, op1a, op1b, code2, op2a, op2b))
return t;
- else
- return or_comparisons_1 (code2, op2a, op2b, code1, op1a, op1b);
-}
+ if (tree t = or_comparisons_1 (type, code2, op2a, op2b, code1, op1a, op1b))
+ return t;
+
+ if (tree t = maybe_fold_comparisons_from_match_pd (type, BIT_IOR_EXPR, code1,
+ op1a, op1b, code2, op2a,
+ op2b))
+ return t;
+
+ return NULL_TREE;
+}
/* Fold STMT to a constant using VALUEIZE to valueize SSA names.