+/* Propagate from the ssa name definition statements of COND_EXPR
+ in the rhs of statement STMT into the conditional if that simplifies it.
+ Returns zero if no statement was changed, one if there were
+ changes and two if cfg_cleanup needs to run.
+
+ This must be kept in sync with forward_propagate_into_gimple_cond. */
+
+static int
+forward_propagate_into_cond (gimple_stmt_iterator *gsi_p)
+{
+ gimple stmt = gsi_stmt (*gsi_p);
+ location_t loc = gimple_location (stmt);
+ int did_something = 0;
+
+ do {
+ tree tmp = NULL_TREE;
+ tree cond = gimple_assign_rhs1 (stmt);
+ tree name, rhs0 = NULL_TREE, rhs1 = NULL_TREE;
+ gimple def_stmt;
+ bool single_use0_p = false, single_use1_p = false;
+
+ /* We can do tree combining on SSA_NAME and comparison expressions. */
+ if (COMPARISON_CLASS_P (cond)
+ && TREE_CODE (TREE_OPERAND (cond, 0)) == SSA_NAME)
+ {
+ /* For comparisons use the first operand, that is likely to
+ simplify comparisons against constants. */
+ name = TREE_OPERAND (cond, 0);
+ def_stmt = get_prop_source_stmt (name, false, &single_use0_p);
+ if (def_stmt && can_propagate_from (def_stmt))
+ {
+ tree op1 = TREE_OPERAND (cond, 1);
+ rhs0 = rhs_to_tree (TREE_TYPE (op1), def_stmt);
+ tmp = combine_cond_expr_cond (loc, TREE_CODE (cond),
+ boolean_type_node,
+ rhs0, op1, !single_use0_p);
+ }
+ /* If that wasn't successful, try the second operand. */
+ if (tmp == NULL_TREE
+ && TREE_CODE (TREE_OPERAND (cond, 1)) == SSA_NAME)
+ {
+ tree op0 = TREE_OPERAND (cond, 0);
+ name = TREE_OPERAND (cond, 1);
+ def_stmt = get_prop_source_stmt (name, false, &single_use1_p);
+ if (!def_stmt || !can_propagate_from (def_stmt))
+ return did_something;
+
+ rhs1 = rhs_to_tree (TREE_TYPE (op0), def_stmt);
+ tmp = combine_cond_expr_cond (loc, TREE_CODE (cond),
+ boolean_type_node,
+ op0, rhs1, !single_use1_p);
+ }
+ /* If that wasn't successful either, try both operands. */
+ if (tmp == NULL_TREE
+ && rhs0 != NULL_TREE
+ && rhs1 != NULL_TREE)
+ tmp = combine_cond_expr_cond (loc, TREE_CODE (cond),
+ boolean_type_node,
+ rhs0,
+ fold_convert_loc (loc,
+ TREE_TYPE (rhs0),
+ rhs1),
+ !(single_use0_p && single_use1_p));
+ }
+ else if (TREE_CODE (cond) == SSA_NAME)
+ {
+ name = cond;
+ def_stmt = get_prop_source_stmt (name, true, NULL);
+ if (def_stmt || !can_propagate_from (def_stmt))
+ return did_something;
+
+ rhs0 = gimple_assign_rhs1 (def_stmt);
+ tmp = combine_cond_expr_cond (loc, NE_EXPR, boolean_type_node, rhs0,
+ build_int_cst (TREE_TYPE (rhs0), 0),
+ false);
+ }
+
+ if (tmp)
+ {
+ if (dump_file && tmp)
+ {
+ fprintf (dump_file, " Replaced '");
+ print_generic_expr (dump_file, cond, 0);
+ fprintf (dump_file, "' with '");
+ print_generic_expr (dump_file, tmp, 0);
+ fprintf (dump_file, "'\n");
+ }
+
+ gimple_assign_set_rhs_from_tree (gsi_p, unshare_expr (tmp));
+ stmt = gsi_stmt (*gsi_p);
+ update_stmt (stmt);
+
+ /* Remove defining statements. */
+ remove_prop_source_from_use (name, NULL);
+
+ if (is_gimple_min_invariant (tmp))
+ did_something = 2;
+ else if (did_something == 0)
+ did_something = 1;
+
+ /* Continue combining. */
+ continue;
+ }
+
+ break;
+ } while (1);
+
+ return did_something;