aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog6
-rw-r--r--gcc/testsuite/ChangeLog12
-rw-r--r--gcc/testsuite/gcc.dg/torture/pr57214.c2
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-11.c18
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-12.c36
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-13.c46
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-14.c40
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-15.c67
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-16.c17
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-17.c44
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-16.c4
-rw-r--r--gcc/tree-ssa-dom.c319
12 files changed, 516 insertions, 95 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 258d424..9a60a80 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,11 @@
2017-08-28 Jeff Law <law@redhat.com>
+ * tree-ssa-dom.c (edge_info::record_simple_equiv): Call
+ derive_equivalences.
+ (derive_equivalences_from_bit_ior, record_temporary_equivalences):
+ Code moved into....
+ (edge_info::derive_equivalences): New private member function
+
* tree-ssa-dom.c (class edge_info): Changed from a struct
to a class. Add ctor/dtor, methods and data members.
(edge_info::edge_info): Renamed from allocate_edge_info.
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index cfe9090..0ffc4f9 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,15 @@
+2017-08-28 Jeff Law <law@redhat.com>
+
+ * gcc.dg/torture/pr57214.c: Fix type of loop counter.
+ * gcc.dg/tree-ssa/ssa-sink-16.c: Disable DOM.
+ * gcc.dg/tree-ssa/ssa-dom-thread-11.c: New test.
+ * gcc.dg/tree-ssa/ssa-dom-thread-12.c: New test.
+ * gcc.dg/tree-ssa/ssa-dom-thread-13.c: New test.
+ * gcc.dg/tree-ssa/ssa-dom-thread-14.c: New test.
+ * gcc.dg/tree-ssa/ssa-dom-thread-15.c: New test.
+ * gcc.dg/tree-ssa/ssa-dom-thread-16.c: New test.
+ * gcc.dg/tree-ssa/ssa-dom-thread-17.c: New test.
+
2017-08-28 Janus Weil <janus@gcc.gnu.org>
PR fortran/81770
diff --git a/gcc/testsuite/gcc.dg/torture/pr57214.c b/gcc/testsuite/gcc.dg/torture/pr57214.c
index d51067d..c697f84 100644
--- a/gcc/testsuite/gcc.dg/torture/pr57214.c
+++ b/gcc/testsuite/gcc.dg/torture/pr57214.c
@@ -15,7 +15,7 @@ bar (_Bool b)
b = 1;
baz ();
x = 0;
- int i;
+ unsigned int i;
while (buf[i] && i)
i++;
foo ();
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-11.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-11.c
new file mode 100644
index 0000000..f42d64b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-11.c
@@ -0,0 +1,18 @@
+/* { dg-do compile { target { ! logical_op_short_circuit } } } */
+/* { dg-options "-O2 -fdump-tree-dom2-details" } */
+
+static int *bb_ticks;
+extern void frob (void);
+void
+mark_target_live_regs (int b, int block, int bb_tick)
+{
+ if (b == block && b != -1 && bb_tick == bb_ticks[b])
+ return;
+ if (b != -1)
+ frob ();
+}
+
+/* When the first two conditionals in the first IF are true, but
+ the third conditional is false, then there's a jump threading
+ opportunity to bypass the second IF statement. */
+/* { dg-final { scan-tree-dump-times "Threaded" 1 "dom2"} } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-12.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-12.c
new file mode 100644
index 0000000..63bd12a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-12.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-dom2-details -w" } */
+typedef long unsigned int size_t;
+union tree_node;
+typedef union tree_node *tree;
+typedef union gimple_statement_d *gimple;
+typedef const union gimple_statement_d *const_gimple;
+union gimple_statement_d
+{
+ unsigned num_ops;
+ tree exp;
+};
+
+unsigned int x;
+static inline tree
+gimple_op (const_gimple gs, unsigned i)
+{
+ if (!(i < gs->num_ops))
+ abort ();
+ return gs->exp;
+}
+
+unsigned char
+scan_function (gimple stmt)
+{
+ unsigned i;
+ for (i = 0; i < stmt->num_ops - 3 ; i++)
+ gimple_call_arg (stmt, i);
+ gimple_op (stmt, 1);
+}
+
+/* The test which bypasses the loop is simplified prior to DOM to check
+ that stmt->num_ops - 3 != 0. When that test is false, we can derive
+ a value for stmt->num_ops. That in turn allows us to thread the jump
+ for the conditional at the start of the call to gimple_op. */
+/* { dg-final { scan-tree-dump-times "Threaded" 1 "dom2"} } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-13.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-13.c
new file mode 100644
index 0000000..209c40d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-13.c
@@ -0,0 +1,46 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-dom2-details -w" } */
+
+union tree_node;
+typedef union tree_node *tree;
+extern unsigned char tree_contains_struct[0xdead][64];
+struct tree_base
+{
+ int code:16;
+};
+struct tree_typed
+{
+ tree type;
+};
+struct tree_type_common
+{
+ tree main_variant;
+};
+extern tree build_target_option_node (void);
+union tree_node
+{
+ struct tree_base base;
+ struct tree_typed typed;
+ struct tree_type_common type_common;
+};
+tree
+convert (tree type, tree expr)
+{
+ tree e = expr;
+ int code = (type)->base.code;
+ const char *invalid_conv_diag;
+ tree ret;
+ if (tree_contains_struct[expr->base.code][(42)] != 1)
+ abort ();
+ if (type->type_common.main_variant == expr->typed.type->type_common.main_variant
+ && (expr->typed.type->base.code != 123
+ || e->base.code == 456))
+ return arf ();
+ if (expr->typed.type->base.code == 42)
+ error ("void value not ignored as it ought to be");
+}
+
+/* When the *->base.code tests in the second IF statement are false, we
+ know that expr->typed.base->base.code has the value 123. That allows
+ us to thread the test for the final IF statement on that path. */
+/* { dg-final { scan-tree-dump-times "Threaded" 1 "dom2"} } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-14.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-14.c
new file mode 100644
index 0000000..2d97f86
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-14.c
@@ -0,0 +1,40 @@
+/* { dg-do compile { target { ! logical_op_short_circuit } } } */
+/* { dg-options "-O2 -fdump-tree-dom2-details -w" } */
+
+enum optab_methods
+{
+ OPTAB_DIRECT,
+ OPTAB_LIB,
+ OPTAB_WIDEN,
+ OPTAB_LIB_WIDEN,
+ OPTAB_MUST_WIDEN
+};
+struct optab_d { };
+typedef struct optab_d *optab;
+void
+expand_shift_1 (int code, int unsignedp, int rotate,
+ optab lshift_optab, optab rshift_arith_optab)
+{
+ int left = (code == 42 || code == 0xde);
+ int attempt;
+ enum optab_methods methods;
+ if (attempt == 0)
+ methods = OPTAB_DIRECT;
+ else if (attempt == 1)
+ methods = OPTAB_WIDEN;
+ if ((!unsignedp || (!left && methods == OPTAB_WIDEN)))
+ {
+ enum optab_methods methods1 = methods;
+ if (unsignedp)
+ methods1 = OPTAB_MUST_WIDEN;
+ expand_binop (left ? lshift_optab : rshift_arith_optab,
+ unsignedp, methods1);
+ }
+}
+
+/* When UNSIGNEDP is true, LEFT is false and METHOD == OPTAB_WIDEN
+ we will enter the TRUE arm of the conditional and we can thread
+ the test to compute the first first argument of the expand_binop
+ call if we look backwards through the boolean logicals. */
+/* { dg-final { scan-tree-dump-times "Threaded" 1 "dom2"} } */
+
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-15.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-15.c
new file mode 100644
index 0000000..df6a9b3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-15.c
@@ -0,0 +1,67 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-dom2-details -w" } */
+struct rtx_def;
+typedef struct rtx_def *rtx;
+struct machine_frame_state
+{
+ rtx cfa_reg;
+ long sp_offset;
+};
+struct machine_function {
+ struct machine_frame_state fs;
+};
+enum global_rtl_index
+{
+ GR_PC,
+ GR_CC0,
+ GR_RETURN,
+ GR_SIMPLE_RETURN,
+ GR_STACK_POINTER,
+ GR_FRAME_POINTER,
+ GR_HARD_FRAME_POINTER,
+ GR_ARG_POINTER,
+ GR_VIRTUAL_INCOMING_ARGS,
+ GR_VIRTUAL_STACK_ARGS,
+ GR_VIRTUAL_STACK_DYNAMIC,
+ GR_VIRTUAL_OUTGOING_ARGS,
+ GR_VIRTUAL_CFA,
+ GR_VIRTUAL_PREFERRED_STACK_BOUNDARY,
+ GR_MAX
+};
+struct target_rtl {
+ rtx x_global_rtl[GR_MAX];
+};
+extern struct target_rtl default_target_rtl;
+struct function {
+ struct machine_function * machine;
+};
+extern struct function *cfun;
+struct ix86_frame
+{
+ long stack_pointer_offset;
+};
+void
+ix86_expand_prologue (void)
+{
+ struct machine_function *m = (cfun + 0)->machine;
+ struct ix86_frame frame;
+ long allocate;
+ allocate = frame.stack_pointer_offset - m->fs.sp_offset;
+ if (allocate == 0)
+ ;
+ else if (!ix86_target_stack_probe ())
+ {
+ pro_epilogue_adjust_stack ((((&default_target_rtl)->x_global_rtl)[GR_STACK_POINTER]), (((&default_target_rtl)->x_global_rtl)[GR_STACK_POINTER]),
+ gen_rtx_CONST_INT ((-allocate)), -1,
+ m->fs.cfa_reg == (((&default_target_rtl)->x_global_rtl)[GR_STACK_POINTER]));
+ }
+ ((void)(!(m->fs.sp_offset == frame.stack_pointer_offset) ? fancy_abort ("../../gcc-4.7.3/gcc/config/i386/i386.c", 10435, __FUNCTION__), 0 : 0));
+}
+
+/* In the case where ALLOCATE is zero, we know that sp_offset and
+ stack_poitner_offset within their respective structures are the
+ same. That allows us to thread the jump from the true arm of the
+ first IF conditional around the test controlling the call to
+ fancy_abort. */
+/* { dg-final { scan-tree-dump-times "Threaded" 1 "dom2"} } */
+
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-16.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-16.c
new file mode 100644
index 0000000..e2e0d20
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-16.c
@@ -0,0 +1,17 @@
+/* { dg-do compile { target { ! logical_op_short_circuit } } } */
+/* { dg-options "-O2 -fdump-tree-dom2-details -w" } */
+unsigned char
+validate_subreg (unsigned int offset, unsigned int isize, unsigned int osize, int zz, int qq)
+{
+if (osize >= (((zz & (1L << 2)) != 0) ? 8 : 4) && isize >= osize)
+ ;
+ else if (qq == 99)
+ return 0;
+ if (osize > isize)
+ return offset == 0;
+ return 1;
+}
+/* When we test isize >= osize in the first IF conditional and it is
+ false and qq != 99, then we can thread the osize > isize test of
+ the second conditional. */
+/* { dg-final { scan-tree-dump-times "Threaded" 1 "dom2"} } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-17.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-17.c
new file mode 100644
index 0000000..2c5c5a6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-17.c
@@ -0,0 +1,44 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-dom2 -w" } */
+
+struct rtx_def;
+typedef struct rtx_def *rtx;
+struct reload
+{
+ rtx in;
+ rtx reg_rtx;
+};
+extern struct reload rld[(2 * 30 * (2 + 1))];
+static rtx find_dummy_reload (rtx);
+extern int frob ();
+extern int arf ();
+int
+push_reload (rtx in, rtx out
+)
+{
+ int i;
+ if (out != 0 && in != out)
+ {
+ rld[i].reg_rtx = find_dummy_reload (out);
+ if (rld[i].reg_rtx == out)
+ rld[i].in = out;
+ }
+}
+rtx
+find_dummy_reload (rtx real_out)
+{
+ unsigned int nwords = frob ();
+ unsigned int regno = frob ();
+ unsigned int i;
+ for (i = 0; i < nwords; i++)
+ if (arf ())
+ break;
+ if (i == nwords)
+ return real_out;
+ return 0;
+}
+
+/* In the case where the call to find_dummy_reload returns 0,
+ the final test in push_reload will never be true and it will
+ be eliminated. */
+/* { dg-final { scan-tree-dump-not "out_\[^\n\r]+ == 0" "dom2"} } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-16.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-16.c
index 1b94c33..610c8d6 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-16.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-16.c
@@ -1,6 +1,6 @@
/* { dg-do compile } */
-/* Note PRE rotates the loop and blocks the sinking opportunity. */
-/* { dg-options "-O2 -fno-tree-pre -fdump-tree-sink -fdump-tree-optimized" } */
+/* Note PRE and DOM jump threading rotate the loop and blocks the sinking opportunity. */
+/* { dg-options "-O2 -fno-tree-pre -fno-tree-dominator-opts -fdump-tree-sink -fdump-tree-optimized" } */
int f(int n)
{
diff --git a/gcc/tree-ssa-dom.c b/gcc/tree-ssa-dom.c
index 403485b..d91766e 100644
--- a/gcc/tree-ssa-dom.c
+++ b/gcc/tree-ssa-dom.c
@@ -136,19 +136,240 @@ edge_info::edge_info (edge e)
}
/* Destructor just needs to release the vectors. */
+
edge_info::~edge_info (void)
{
this->cond_equivalences.release ();
this->simple_equivalences.release ();
}
-/* Record that LHS is known to be equal to RHS at runtime when the
- edge associated with THIS is traversed. */
+/* NAME is known to have the value VALUE, which must be a constant.
+
+ Walk through its use-def chain to see if there are other equivalences
+ we might be able to derive.
+
+ RECURSION_LIMIT controls how far back we recurse through the use-def
+ chains. */
+
+void
+edge_info::derive_equivalences (tree name, tree value, int recursion_limit)
+{
+ if (TREE_CODE (name) != SSA_NAME || TREE_CODE (value) != INTEGER_CST)
+ return;
+
+ /* This records the equivalence for the toplevel object. Do
+ this before checking the recursion limit. */
+ simple_equivalences.safe_push (equiv_pair (name, value));
+
+ /* Limit how far up the use-def chains we are willing to walk. */
+ if (recursion_limit == 0)
+ return;
+
+ /* We can walk up the use-def chains to potentially find more
+ equivalences. */
+ gimple *def_stmt = SSA_NAME_DEF_STMT (name);
+ if (is_gimple_assign (def_stmt))
+ {
+ /* We know the result of DEF_STMT was zero. See if that allows
+ us to deduce anything about the SSA_NAMEs used on the RHS. */
+ enum tree_code code = gimple_assign_rhs_code (def_stmt);
+ switch (code)
+ {
+ case BIT_IOR_EXPR:
+ if (integer_zerop (value))
+ {
+ tree rhs1 = gimple_assign_rhs1 (def_stmt);
+ tree rhs2 = gimple_assign_rhs2 (def_stmt);
+
+ value = build_zero_cst (TREE_TYPE (rhs1));
+ derive_equivalences (rhs1, value, recursion_limit - 1);
+ value = build_zero_cst (TREE_TYPE (rhs2));
+ derive_equivalences (rhs2, value, recursion_limit - 1);
+ }
+ break;
+
+ /* We know the result of DEF_STMT was one. See if that allows
+ us to deduce anything about the SSA_NAMEs used on the RHS. */
+ case BIT_AND_EXPR:
+ if (!integer_zerop (value))
+ {
+ tree rhs1 = gimple_assign_rhs1 (def_stmt);
+ tree rhs2 = gimple_assign_rhs2 (def_stmt);
+
+ /* If either operand has a boolean range, then we
+ know its value must be one, otherwise we just know it
+ is nonzero. The former is clearly useful, I haven't
+ seen cases where the latter is helpful yet. */
+ if (TREE_CODE (rhs1) == SSA_NAME)
+ {
+ if (ssa_name_has_boolean_range (rhs1))
+ {
+ value = build_one_cst (TREE_TYPE (rhs1));
+ derive_equivalences (rhs1, value, recursion_limit - 1);
+ }
+ }
+ if (TREE_CODE (rhs2) == SSA_NAME)
+ {
+ if (ssa_name_has_boolean_range (rhs2))
+ {
+ value = build_one_cst (TREE_TYPE (rhs2));
+ derive_equivalences (rhs2, value, recursion_limit - 1);
+ }
+ }
+ }
+ break;
+
+ /* If LHS is an SSA_NAME and RHS is a constant integer and LHS was
+ set via a widening type conversion, then we may be able to record
+ additional equivalences. */
+ case NOP_EXPR:
+ case CONVERT_EXPR:
+ {
+ tree rhs = gimple_assign_rhs1 (def_stmt);
+ tree rhs_type = TREE_TYPE (rhs);
+ if (INTEGRAL_TYPE_P (rhs_type)
+ && (TYPE_PRECISION (TREE_TYPE (name))
+ >= TYPE_PRECISION (rhs_type))
+ && int_fits_type_p (value, rhs_type))
+ derive_equivalences (rhs,
+ fold_convert (rhs_type, value),
+ recursion_limit - 1);
+ break;
+ }
+
+ /* We can invert the operation of these codes trivially if
+ one of the RHS operands is a constant to produce a known
+ value for the other RHS operand. */
+ case POINTER_PLUS_EXPR:
+ case PLUS_EXPR:
+ {
+ tree rhs1 = gimple_assign_rhs1 (def_stmt);
+ tree rhs2 = gimple_assign_rhs2 (def_stmt);
+
+ /* If either argument is a constant, then we can compute
+ a constant value for the nonconstant argument. */
+ if (TREE_CODE (rhs1) == INTEGER_CST
+ && TREE_CODE (rhs2) == SSA_NAME)
+ derive_equivalences (rhs2,
+ fold_binary (MINUS_EXPR, TREE_TYPE (rhs1),
+ value, rhs1),
+ recursion_limit - 1);
+ else if (TREE_CODE (rhs2) == INTEGER_CST
+ && TREE_CODE (rhs1) == SSA_NAME)
+ derive_equivalences (rhs1,
+ fold_binary (MINUS_EXPR, TREE_TYPE (rhs1),
+ value, rhs2),
+ recursion_limit - 1);
+ break;
+ }
+
+ /* If one of the operands is a constant, then we can compute
+ the value of the other operand. If both operands are
+ SSA_NAMEs, then they must be equal if the result is zero. */
+ case MINUS_EXPR:
+ {
+ tree rhs1 = gimple_assign_rhs1 (def_stmt);
+ tree rhs2 = gimple_assign_rhs2 (def_stmt);
+
+ /* If either argument is a constant, then we can compute
+ a constant value for the nonconstant argument. */
+ if (TREE_CODE (rhs1) == INTEGER_CST
+ && TREE_CODE (rhs2) == SSA_NAME)
+ derive_equivalences (rhs2,
+ fold_binary (MINUS_EXPR, TREE_TYPE (rhs1),
+ rhs1, value),
+ recursion_limit - 1);
+ else if (TREE_CODE (rhs2) == INTEGER_CST
+ && TREE_CODE (rhs1) == SSA_NAME)
+ derive_equivalences (rhs1,
+ fold_binary (PLUS_EXPR, TREE_TYPE (rhs1),
+ value, rhs2),
+ recursion_limit - 1);
+ else if (integer_zerop (value))
+ {
+ tree cond = build2 (EQ_EXPR, boolean_type_node,
+ gimple_assign_rhs1 (def_stmt),
+ gimple_assign_rhs2 (def_stmt));
+ tree inverted = invert_truthvalue (cond);
+ record_conditions (&this->cond_equivalences, cond, inverted);
+ }
+ break;
+ }
+
+
+ case EQ_EXPR:
+ case NE_EXPR:
+ {
+ if ((code == EQ_EXPR && integer_onep (value))
+ || (code == NE_EXPR && integer_zerop (value)))
+ {
+ tree rhs1 = gimple_assign_rhs1 (def_stmt);
+ tree rhs2 = gimple_assign_rhs2 (def_stmt);
+
+ /* If either argument is a constant, then record the
+ other argument as being the same as that constant.
+
+ If neither operand is a constant, then we have a
+ conditional name == name equivalence. */
+ if (TREE_CODE (rhs1) == INTEGER_CST)
+ derive_equivalences (rhs2, rhs1, recursion_limit - 1);
+ else if (TREE_CODE (rhs2) == INTEGER_CST)
+ derive_equivalences (rhs1, rhs2, recursion_limit - 1);
+ }
+ else
+ {
+ tree cond = build2 (code, boolean_type_node,
+ gimple_assign_rhs1 (def_stmt),
+ gimple_assign_rhs2 (def_stmt));
+ tree inverted = invert_truthvalue (cond);
+ if (integer_zerop (value))
+ std::swap (cond, inverted);
+ record_conditions (&this->cond_equivalences, cond, inverted);
+ }
+ break;
+ }
+
+ /* For BIT_NOT and NEGATE, we can just apply the operation to the
+ VALUE to get the new equivalence. It will always be a constant
+ so we can recurse. */
+ case BIT_NOT_EXPR:
+ case NEGATE_EXPR:
+ {
+ tree rhs = gimple_assign_rhs1 (def_stmt);
+ tree res = fold_build1 (code, TREE_TYPE (rhs), value);
+ derive_equivalences (rhs, res, recursion_limit - 1);
+ break;
+ }
+
+ default:
+ {
+ if (TREE_CODE_CLASS (code) == tcc_comparison)
+ {
+ tree cond = build2 (code, boolean_type_node,
+ gimple_assign_rhs1 (def_stmt),
+ gimple_assign_rhs2 (def_stmt));
+ tree inverted = invert_truthvalue (cond);
+ if (integer_zerop (value))
+ std::swap (cond, inverted);
+ record_conditions (&this->cond_equivalences, cond, inverted);
+ break;
+ }
+ break;
+ }
+ }
+ }
+}
void
edge_info::record_simple_equiv (tree lhs, tree rhs)
{
- simple_equivalences.safe_push (equiv_pair (lhs, rhs));
+ /* If the RHS is a constant, then we may be able to derive
+ further equivalences. Else just record the name = name
+ equivalence. */
+ if (TREE_CODE (rhs) == INTEGER_CST)
+ derive_equivalences (lhs, rhs, 4);
+ else
+ simple_equivalences.safe_push (equiv_pair (lhs, rhs));
}
/* Free the edge_info data attached to E, if it exists. */
@@ -702,42 +923,6 @@ back_propagate_equivalences (tree lhs, edge e,
BITMAP_FREE (domby);
}
-/* Record NAME has the value zero and if NAME was set from a BIT_IOR_EXPR
- recurse into both operands recording their values as zero too.
- RECURSION_DEPTH controls how far back we recurse through the operands
- of the BIT_IOR_EXPR. */
-
-static void
-derive_equivalences_from_bit_ior (tree name,
- const_and_copies *const_and_copies,
- int recursion_limit)
-{
- if (recursion_limit == 0)
- return;
-
- if (TREE_CODE (name) == SSA_NAME)
- {
- tree value = build_zero_cst (TREE_TYPE (name));
-
- /* This records the equivalence for the toplevel object. */
- record_equality (name, value, const_and_copies);
-
- /* And we can recurse into each operand to potentially find more
- equivalences. */
- gimple *def_stmt = SSA_NAME_DEF_STMT (name);
- if (is_gimple_assign (def_stmt)
- && gimple_assign_rhs_code (def_stmt) == BIT_IOR_EXPR)
- {
- derive_equivalences_from_bit_ior (gimple_assign_rhs1 (def_stmt),
- const_and_copies,
- recursion_limit - 1);
- derive_equivalences_from_bit_ior (gimple_assign_rhs2 (def_stmt),
- const_and_copies,
- recursion_limit - 1);
- }
- }
-}
-
/* Record into CONST_AND_COPIES and AVAIL_EXPRS_STACK any equivalences implied
by traversing edge E (which are cached in E->aux).
@@ -758,28 +943,7 @@ record_temporary_equivalences (edge e,
/* If we have 0 = COND or 1 = COND equivalences, record them
into our expression hash tables. */
for (i = 0; edge_info->cond_equivalences.iterate (i, &eq); ++i)
- {
- avail_exprs_stack->record_cond (eq);
-
- /* If the condition is testing that X == 0 is true or X != 0 is false
- and X is set from a BIT_IOR_EXPR, then we can record equivalences
- for the operands of the BIT_IOR_EXPR (and recurse on those). */
- tree op0 = eq->cond.ops.binary.opnd0;
- tree op1 = eq->cond.ops.binary.opnd1;
- if (TREE_CODE (op0) == SSA_NAME && integer_zerop (op1))
- {
- enum tree_code code = eq->cond.ops.binary.op;
- if ((code == EQ_EXPR && eq->value == boolean_true_node)
- || (code == NE_EXPR && eq->value == boolean_false_node))
- derive_equivalences_from_bit_ior (op0, const_and_copies, 4);
-
- /* TODO: We could handle BIT_AND_EXPR in a similar fashion
- recording that the operands have a nonzero value. */
-
- /* TODO: We can handle more cases here, particularly when OP0 is
- known to have a boolean range. */
- }
- }
+ avail_exprs_stack->record_cond (eq);
edge_info::equiv_pair *seq;
for (i = 0; edge_info->simple_equivalences.iterate (i, &seq); ++i)
@@ -806,42 +970,13 @@ record_temporary_equivalences (edge e,
int lhs_cost = estimate_num_insns (lhs_def, &eni_size_weights);
if (rhs_cost > lhs_cost)
- record_equality (rhs, lhs, const_and_copies);
+ record_equality (rhs, lhs, const_and_copies);
else if (rhs_cost < lhs_cost)
- record_equality (lhs, rhs, const_and_copies);
+ record_equality (lhs, rhs, const_and_copies);
}
else
record_equality (lhs, rhs, const_and_copies);
- /* If LHS is an SSA_NAME and RHS is a constant integer and LHS was
- set via a widening type conversion, then we may be able to record
- additional equivalences. */
- if (TREE_CODE (rhs) == INTEGER_CST)
- {
- gimple *defstmt = SSA_NAME_DEF_STMT (lhs);
-
- if (defstmt
- && is_gimple_assign (defstmt)
- && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (defstmt)))
- {
- tree old_rhs = gimple_assign_rhs1 (defstmt);
-
- /* If the conversion widens the original value and
- the constant is in the range of the type of OLD_RHS,
- then convert the constant and record the equivalence.
-
- Note that int_fits_type_p does not check the precision
- if the upper and lower bounds are OK. */
- if (INTEGRAL_TYPE_P (TREE_TYPE (old_rhs))
- && (TYPE_PRECISION (TREE_TYPE (lhs))
- > TYPE_PRECISION (TREE_TYPE (old_rhs)))
- && int_fits_type_p (rhs, TREE_TYPE (old_rhs)))
- {
- tree newval = fold_convert (TREE_TYPE (old_rhs), rhs);
- record_equality (old_rhs, newval, const_and_copies);
- }
- }
- }
/* Any equivalence found for LHS may result in additional
equivalences for other uses of LHS that we have already