+ mark_symbols_for_renaming (stmt);
+}
+
+/* DEF_RHS defines LHS which is contains the address of the 0th element
+ in an array. USE_STMT uses LHS to compute the address of an
+ arbitrary element within the array. The (variable) byte offset
+ of the element is contained in OFFSET.
+
+ We walk back through the use-def chains of OFFSET to verify that
+ it is indeed computing the offset of an element within the array
+ and extract the index corresponding to the given byte offset.
+
+ We then try to fold the entire address expression into a form
+ &array[index].
+
+ If we are successful, we replace the right hand side of USE_STMT
+ with the new address computation. */
+
+static bool
+forward_propagate_addr_into_variable_array_index (tree offset, tree lhs,
+ tree def_rhs, tree use_stmt)
+{
+ tree index;
+
+ /* The offset must be defined by a simple GIMPLE_MODIFY_STMT statement. */
+ if (TREE_CODE (offset) != GIMPLE_MODIFY_STMT)
+ return false;
+
+ /* The RHS of the statement which defines OFFSET must be a gimple
+ cast of another SSA_NAME. */
+ offset = GIMPLE_STMT_OPERAND (offset, 1);
+ if (!is_gimple_cast (offset))
+ return false;
+
+ offset = TREE_OPERAND (offset, 0);
+ if (TREE_CODE (offset) != SSA_NAME)
+ return false;
+
+ /* Get the defining statement of the offset before type
+ conversion. */
+ offset = SSA_NAME_DEF_STMT (offset);
+
+ /* The statement which defines OFFSET before type conversion
+ must be a simple GIMPLE_MODIFY_STMT. */
+ if (TREE_CODE (offset) != GIMPLE_MODIFY_STMT)
+ return false;
+
+ /* The RHS of the statement which defines OFFSET must be a
+ multiplication of an object by the size of the array elements.
+ This implicitly verifies that the size of the array elements
+ is constant. */
+ offset = GIMPLE_STMT_OPERAND (offset, 1);
+ if (TREE_CODE (offset) != MULT_EXPR
+ || TREE_CODE (TREE_OPERAND (offset, 1)) != INTEGER_CST
+ || !simple_cst_equal (TREE_OPERAND (offset, 1),
+ TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (lhs)))))
+ return false;
+
+ /* The first operand to the MULT_EXPR is the desired index. */
+ index = TREE_OPERAND (offset, 0);
+
+ /* Replace the pointer addition with array indexing. */
+ GIMPLE_STMT_OPERAND (use_stmt, 1) = unshare_expr (def_rhs);
+ TREE_OPERAND (TREE_OPERAND (GIMPLE_STMT_OPERAND (use_stmt, 1), 0), 1)
+ = index;
+
+ /* That should have created gimple, so there is no need to
+ record information to undo the propagation. */
+ fold_stmt_inplace (use_stmt);
+ tidy_after_forward_propagate_addr (use_stmt);
+ return true;
+}
+
+/* NAME is a SSA_NAME representing DEF_RHS which is of the form
+ ADDR_EXPR <whatever>.
+
+ Try to forward propagate the ADDR_EXPR into the use USE_STMT.
+ Often this will allow for removal of an ADDR_EXPR and INDIRECT_REF
+ node or for recovery of array indexing from pointer arithmetic.
+
+ Return true if the propagation was successful (the propagation can
+ be not totally successful, yet things may have been changed). */
+
+static bool
+forward_propagate_addr_expr_1 (tree name, tree def_rhs, tree use_stmt)
+{
+ tree lhs, rhs, array_ref;
+
+ /* Strip away any outer COMPONENT_REF/ARRAY_REF nodes from the LHS.
+ ADDR_EXPR will not appear on the LHS. */
+ lhs = GIMPLE_STMT_OPERAND (use_stmt, 0);
+ while (handled_component_p (lhs))
+ lhs = TREE_OPERAND (lhs, 0);
+
+ rhs = GIMPLE_STMT_OPERAND (use_stmt, 1);
+
+ /* Now see if the LHS node is an INDIRECT_REF using NAME. If so,
+ propagate the ADDR_EXPR into the use of NAME and fold the result. */
+ if (TREE_CODE (lhs) == INDIRECT_REF && TREE_OPERAND (lhs, 0) == name)
+ {
+ /* This should always succeed in creating gimple, so there is
+ no need to save enough state to undo this propagation. */
+ TREE_OPERAND (lhs, 0) = unshare_expr (def_rhs);
+ fold_stmt_inplace (use_stmt);
+ tidy_after_forward_propagate_addr (use_stmt);
+
+ /* Continue propagating into the RHS. */
+ }
+
+ /* Trivial case. The use statement could be a trivial copy or a
+ useless conversion. Recurse to the uses of the lhs as copyprop does
+ not copy through differen variant pointers and FRE does not catch
+ all useless conversions. */
+ else if ((TREE_CODE (lhs) == SSA_NAME
+ && rhs == name)
+ || ((TREE_CODE (rhs) == NOP_EXPR
+ || TREE_CODE (rhs) == CONVERT_EXPR)
+ && tree_ssa_useless_type_conversion_1 (TREE_TYPE (rhs),
+ TREE_TYPE (def_rhs))))
+ return forward_propagate_addr_expr (lhs, def_rhs);
+
+ /* Strip away any outer COMPONENT_REF, ARRAY_REF or ADDR_EXPR
+ nodes from the RHS. */
+ while (handled_component_p (rhs)
+ || TREE_CODE (rhs) == ADDR_EXPR)
+ rhs = TREE_OPERAND (rhs, 0);
+
+ /* Now see if the RHS node is an INDIRECT_REF using NAME. If so,
+ propagate the ADDR_EXPR into the use of NAME and fold the result. */
+ if (TREE_CODE (rhs) == INDIRECT_REF && TREE_OPERAND (rhs, 0) == name)
+ {
+ /* This should always succeed in creating gimple, so there is
+ no need to save enough state to undo this propagation. */
+ TREE_OPERAND (rhs, 0) = unshare_expr (def_rhs);
+ fold_stmt_inplace (use_stmt);
+ tidy_after_forward_propagate_addr (use_stmt);
+ return true;
+ }
+
+ /* The remaining cases are all for turning pointer arithmetic into
+ array indexing. They only apply when we have the address of
+ element zero in an array. If that is not the case then there
+ is nothing to do. */
+ array_ref = TREE_OPERAND (def_rhs, 0);
+ if (TREE_CODE (array_ref) != ARRAY_REF
+ || TREE_CODE (TREE_TYPE (TREE_OPERAND (array_ref, 0))) != ARRAY_TYPE
+ || !integer_zerop (TREE_OPERAND (array_ref, 1)))
+ return false;
+
+ /* If the use of the ADDR_EXPR must be a PLUS_EXPR, or else there
+ is nothing to do. */
+ if (TREE_CODE (rhs) != PLUS_EXPR)
+ return false;
+
+ /* Try to optimize &x[0] + C where C is a multiple of the size
+ of the elements in X into &x[C/element size]. */
+ if (TREE_OPERAND (rhs, 0) == name
+ && TREE_CODE (TREE_OPERAND (rhs, 1)) == INTEGER_CST)
+ {
+ tree orig = unshare_expr (rhs);
+ TREE_OPERAND (rhs, 0) = unshare_expr (def_rhs);
+
+ /* If folding succeeds, then we have just exposed new variables
+ in USE_STMT which will need to be renamed. If folding fails,
+ then we need to put everything back the way it was. */
+ if (fold_stmt_inplace (use_stmt))
+ {
+ tidy_after_forward_propagate_addr (use_stmt);
+ return true;
+ }
+ else
+ {
+ GIMPLE_STMT_OPERAND (use_stmt, 1) = orig;
+ update_stmt (use_stmt);
+ return false;
+ }
+ }
+
+ /* Try to optimize &x[0] + OFFSET where OFFSET is defined by
+ converting a multiplication of an index by the size of the
+ array elements, then the result is converted into the proper
+ type for the arithmetic. */
+ if (TREE_OPERAND (rhs, 0) == name
+ && TREE_CODE (TREE_OPERAND (rhs, 1)) == SSA_NAME
+ /* Avoid problems with IVopts creating PLUS_EXPRs with a
+ different type than their operands. */
+ && lang_hooks.types_compatible_p (TREE_TYPE (name), TREE_TYPE (rhs)))
+ {
+ bool res;
+ tree offset_stmt = SSA_NAME_DEF_STMT (TREE_OPERAND (rhs, 1));
+
+ res = forward_propagate_addr_into_variable_array_index (offset_stmt, lhs,
+ def_rhs, use_stmt);
+ return res;
+ }
+
+ /* Same as the previous case, except the operands of the PLUS_EXPR
+ were reversed. */
+ if (TREE_OPERAND (rhs, 1) == name
+ && TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME
+ /* Avoid problems with IVopts creating PLUS_EXPRs with a
+ different type than their operands. */
+ && lang_hooks.types_compatible_p (TREE_TYPE (name), TREE_TYPE (rhs)))
+ {
+ bool res;
+ tree offset_stmt = SSA_NAME_DEF_STMT (TREE_OPERAND (rhs, 0));
+ res = forward_propagate_addr_into_variable_array_index (offset_stmt, lhs,
+ def_rhs, use_stmt);
+ return res;
+ }
+ return false;
+}
+
+/* STMT is a statement of the form SSA_NAME = ADDR_EXPR <whatever>.
+
+ Try to forward propagate the ADDR_EXPR into all uses of the SSA_NAME.
+ Often this will allow for removal of an ADDR_EXPR and INDIRECT_REF
+ node or for recovery of array indexing from pointer arithmetic.
+ Returns true, if all uses have been propagated into. */
+
+static bool
+forward_propagate_addr_expr (tree name, tree rhs)
+{
+ int stmt_loop_depth = bb_for_stmt (SSA_NAME_DEF_STMT (name))->loop_depth;
+ imm_use_iterator iter;
+ tree use_stmt;
+ bool all = true;
+
+ FOR_EACH_IMM_USE_STMT (use_stmt, iter, name)
+ {
+ bool result;
+
+ /* If the use is not in a simple assignment statement, then
+ there is nothing we can do. */
+ if (TREE_CODE (use_stmt) != GIMPLE_MODIFY_STMT)
+ {
+ all = false;
+ continue;
+ }
+
+ /* If the use is in a deeper loop nest, then we do not want
+ to propagate the ADDR_EXPR into the loop as that is likely
+ adding expression evaluations into the loop. */
+ if (bb_for_stmt (use_stmt)->loop_depth > stmt_loop_depth)
+ {
+ all = false;
+ continue;
+ }
+
+ push_stmt_changes (&use_stmt);
+
+ result = forward_propagate_addr_expr_1 (name, rhs, use_stmt);
+ all &= result;
+
+ pop_stmt_changes (&use_stmt);
+
+ /* Remove intermediate now unused copy and conversion chains. */
+ if (result
+ && TREE_CODE (GIMPLE_STMT_OPERAND (use_stmt, 0)) == SSA_NAME
+ && (TREE_CODE (GIMPLE_STMT_OPERAND (use_stmt, 1)) == SSA_NAME
+ || TREE_CODE (GIMPLE_STMT_OPERAND (use_stmt, 1)) == NOP_EXPR
+ || TREE_CODE (GIMPLE_STMT_OPERAND (use_stmt, 1)) == CONVERT_EXPR))
+ {
+ block_stmt_iterator bsi = bsi_for_stmt (use_stmt);
+ release_defs (use_stmt);
+ bsi_remove (&bsi, true);
+ }
+ }
+
+ return all;
+}
+
+/* If we have lhs = ~x (STMT), look and see if earlier we had x = ~y.
+ If so, we can change STMT into lhs = y which can later be copy
+ propagated. Similarly for negation.
+
+ This could trivially be formulated as a forward propagation
+ to immediate uses. However, we already had an implementation
+ from DOM which used backward propagation via the use-def links.
+
+ It turns out that backward propagation is actually faster as
+ there's less work to do for each NOT/NEG expression we find.
+ Backwards propagation needs to look at the statement in a single
+ backlink. Forward propagation needs to look at potentially more
+ than one forward link. */
+
+static void
+simplify_not_neg_expr (tree stmt)
+{
+ tree rhs = GIMPLE_STMT_OPERAND (stmt, 1);
+ tree rhs_def_stmt = SSA_NAME_DEF_STMT (TREE_OPERAND (rhs, 0));
+
+ /* See if the RHS_DEF_STMT has the same form as our statement. */
+ if (TREE_CODE (rhs_def_stmt) == GIMPLE_MODIFY_STMT
+ && TREE_CODE (GIMPLE_STMT_OPERAND (rhs_def_stmt, 1)) == TREE_CODE (rhs))