From 14d6281388bad11de8c328be7ea825b184fc7efe Mon Sep 17 00:00:00 2001 From: Jeff Law Date: Mon, 28 Aug 2017 23:03:36 -0600 Subject: [PATCH] tree-ssa-dom.c (edge_info::record_simple_equiv): Call derive_equivalences. * 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 * 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. From-SVN: r251397 --- gcc/ChangeLog | 6 + gcc/testsuite/ChangeLog | 12 + gcc/testsuite/gcc.dg/torture/pr57214.c | 2 +- .../gcc.dg/tree-ssa/ssa-dom-thread-11.c | 18 + .../gcc.dg/tree-ssa/ssa-dom-thread-12.c | 36 ++ .../gcc.dg/tree-ssa/ssa-dom-thread-13.c | 46 +++ .../gcc.dg/tree-ssa/ssa-dom-thread-14.c | 40 +++ .../gcc.dg/tree-ssa/ssa-dom-thread-15.c | 67 ++++ .../gcc.dg/tree-ssa/ssa-dom-thread-16.c | 17 + .../gcc.dg/tree-ssa/ssa-dom-thread-17.c | 44 +++ gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-16.c | 4 +- gcc/tree-ssa-dom.c | 319 +++++++++++++----- 12 files changed, 516 insertions(+), 95 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-11.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-12.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-13.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-14.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-15.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-16.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-17.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 258d4242f30..9a60a80b746 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,11 @@ 2017-08-28 Jeff Law + * 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 cfe90904f6d..0ffc4f9a70f 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,15 @@ +2017-08-28 Jeff Law + + * 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 PR fortran/81770 diff --git a/gcc/testsuite/gcc.dg/torture/pr57214.c b/gcc/testsuite/gcc.dg/torture/pr57214.c index d51067d95d8..c697f84514e 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 00000000000..f42d64bed71 --- /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 00000000000..63bd12a06a4 --- /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 00000000000..209c40d4c95 --- /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 00000000000..2d97f86fa28 --- /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 00000000000..df6a9b32eb1 --- /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 00000000000..e2e0d20fb9f --- /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 00000000000..2c5c5a6cf94 --- /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 1b94c336806..610c8d60ebe 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 403485b3c55..d91766e902e 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 -- 2.30.2