[backport from gcc-4.9/trunk r196855 ] List-Archive: Date: Wed, 20 Mar 2013 22:43:18 -0600 From: Jeff Law Subject: Record missing equivalence This was something I spotted while looking at why certain redundant conditionals were not eliminated. In particular this affects the compiler's ability to eliminate a variety of gimple checking tests. Consider an equality comparison if (a == 10) true arm else else arm We obviously want to record an equivalence so that we can replace uses of "a" in the true arm with "10". Now consider if "a" was set by a widening type conversion. a = (int) z; /* Assume Z is a narrower type */ if (a == 10) true arm else else arm We'd really like to also record an equivalence for "z" in the true arm so that uses of "z" can be replaced with "10". We restrict this to widening conversions where the constant is equal in both the original and widened type. That's precisely what this patch does. When we're going to record an equivalence from an equality comparison between an SSA_NAME and a constant, we look to see if the SSA_NAME was set from widening conversion and verify the constant is the same in both the original and widened type. When true, we record the additional equivalence. As I mentioned, this ultimately allows us to discover more redundant conditionals for gimple checking and eliminate them. The included testcase is drastically simplified and merely tests for whether or not we record & propagate the additional equivalence. It does not show the eliminated tests. Bootstrapped and regression tested on x86_64-unknown-linux-gnu. Installed on the trunk. gcc/ 2013-03-20 Jeff Law * tree-ssa-dom.c (record_equivalences_from_incoming_edge): Record addititional equivalences for equality comparisons between an SSA_NAME and a constant where the SSA_NAME was set from a widening conversion. gcc/testsuite/ 2013-03-20 Jeff Law * g++.dg/tree-ssa/ssa-dom.C: New test. --- gcc-4.8.0/gcc/testsuite/g++.dg/tree-ssa/ssa-dom.C.~1~ 1970-01-01 01:00:00.000000000 +0100 +++ gcc-4.8.0/gcc/testsuite/g++.dg/tree-ssa/ssa-dom.C 2013-03-23 20:53:42.460699880 +0100 @@ -0,0 +1,104 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-dom1" } */ + +typedef long unsigned int size_t; +extern void abort (void) __attribute__ ((__noreturn__)); +union tree_node; +typedef union tree_node *tree; +union gimple_statement_d; +typedef union gimple_statement_d *gimple; +typedef const union gimple_statement_d *const_gimple; + +enum gimple_code +{ + GIMPLE_RETURN = 10, +}; + + + + + +struct gimple_statement_base +{ + + + enum gimple_code code:8; +}; + + +enum gimple_statement_structure_enum +{ + xyz +}; + + + + + + +union gimple_statement_d +{ + struct gimple_statement_base gsbase; +}; + + + + + +extern size_t const gimple_ops_offset_[]; + + +extern enum gimple_statement_structure_enum const gss_for_code_[]; + + +static inline enum gimple_code +gimple_code (const_gimple g) +{ + return g->gsbase.code; +} + + + + +static inline enum gimple_statement_structure_enum +gss_for_code (enum gimple_code code) +{ + return gss_for_code_[code]; +} + + + + +static inline enum gimple_statement_structure_enum +gimple_statement_structure (gimple gs) +{ + return gss_for_code (gimple_code (gs)); +} + + +static inline tree * +gimple_ops (gimple gs) +{ + size_t off; + off = gimple_ops_offset_[gimple_statement_structure (gs)]; + return (tree *) ((char *) gs + off); +} + + +static inline void +gimple_set_op (gimple gs, unsigned i, tree op) +{ + gimple_ops (gs)[i] = op; +} + +void +gimple_return_set_retval (gimple gs, tree retval) +{ + const_gimple __gs = (gs); + if (gimple_code (__gs) != (GIMPLE_RETURN)) + abort (); + gimple_set_op (gs, 0, retval); +} +/* { dg-final { scan-tree-dump-times "gss_for_code_.10." 1 "dom1"} } */ +/* { dg-final { cleanup-tree-dump "dom1" } } */ + --- gcc-4.8.0/gcc/tree-ssa-dom.c.~1~ 2013-01-29 11:40:24.000000000 +0100 +++ gcc-4.8.0/gcc/tree-ssa-dom.c 2013-03-23 20:53:42.460699880 +0100 @@ -1135,6 +1135,33 @@ record_equivalences_from_incoming_edge ( if (lhs) record_equality (lhs, rhs); + /* If LHS is an SSA_NAME and RHS is a constant and LHS was set + via a widening type conversion, then we may be able to record + additional equivalences. */ + if (lhs + && TREE_CODE (lhs) == SSA_NAME + && is_gimple_constant (rhs)) + { + 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); + tree newval = fold_convert (TREE_TYPE (old_rhs), rhs); + + /* If this was a widening conversion and if RHS is converted + to the type of OLD_RHS and has the same value, then we + can record an equivalence between OLD_RHS and the + converted representation of RHS. */ + if ((TYPE_PRECISION (TREE_TYPE (lhs)) + > TYPE_PRECISION (TREE_TYPE (old_rhs))) + && operand_equal_p (rhs, newval, 0)) + record_equality (old_rhs, newval); + } + } + for (i = 0; edge_info->cond_equivalences.iterate (i, &eq); ++i) record_cond (eq); }