+/* Forward propagate the comparison COND defined in STMT like
+ cond_1 = x CMP y to uses of the form
+ a_1 = (T')cond_1
+ a_1 = !cond_1
+ a_1 = cond_1 != 0
+ Returns true if stmt is now unused. */
+
+static bool
+forward_propagate_comparison (tree cond, tree stmt)
+{
+ tree name = GIMPLE_STMT_OPERAND (stmt, 0);
+ tree use_stmt, tmp = NULL_TREE;
+
+ /* Don't propagate ssa names that occur in abnormal phis. */
+ if ((TREE_CODE (TREE_OPERAND (cond, 0)) == SSA_NAME
+ && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (TREE_OPERAND (cond, 0)))
+ || (TREE_CODE (TREE_OPERAND (cond, 1)) == SSA_NAME
+ && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (TREE_OPERAND (cond, 1))))
+ return false;
+
+ /* Do not un-cse comparisons. But propagate through copies. */
+ use_stmt = get_prop_dest_stmt (name, &name);
+ if (use_stmt == NULL_TREE)
+ return false;
+
+ /* Conversion of the condition result to another integral type. */
+ if (TREE_CODE (use_stmt) == GIMPLE_MODIFY_STMT
+ && (TREE_CODE (GIMPLE_STMT_OPERAND (use_stmt, 1)) == CONVERT_EXPR
+ || TREE_CODE (GIMPLE_STMT_OPERAND (use_stmt, 1)) == NOP_EXPR
+ || COMPARISON_CLASS_P (GIMPLE_STMT_OPERAND (use_stmt, 1))
+ || TREE_CODE (GIMPLE_STMT_OPERAND (use_stmt, 1)) == TRUTH_NOT_EXPR)
+ && INTEGRAL_TYPE_P (TREE_TYPE (GIMPLE_STMT_OPERAND (use_stmt, 0))))
+ {
+ tree lhs = GIMPLE_STMT_OPERAND (use_stmt, 0);
+ tree rhs = GIMPLE_STMT_OPERAND (use_stmt, 1);
+
+ /* We can propagate the condition into a conversion. */
+ if (TREE_CODE (rhs) == CONVERT_EXPR
+ || TREE_CODE (rhs) == NOP_EXPR)
+ {
+ /* Avoid using fold here as that may create a COND_EXPR with
+ non-boolean condition as canonical form. */
+ tmp = build2 (TREE_CODE (cond), TREE_TYPE (lhs),
+ TREE_OPERAND (cond, 0), TREE_OPERAND (cond, 1));
+ }
+ /* We can propagate the condition into X op CST where op
+ is EQ_EXRP or NE_EXPR and CST is either one or zero. */
+ else if (COMPARISON_CLASS_P (rhs)
+ && TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME
+ && TREE_CODE (TREE_OPERAND (rhs, 1)) == INTEGER_CST)
+ {
+ enum tree_code code = TREE_CODE (rhs);
+ tree cst = TREE_OPERAND (rhs, 1);
+
+ tmp = combine_cond_expr_cond (code, TREE_TYPE (lhs),
+ fold_convert (TREE_TYPE (cst), cond),
+ cst, false);
+ if (tmp == NULL_TREE)
+ return false;
+ }
+ /* We can propagate the condition into a statement that
+ computes the logical negation of the comparison result. */
+ else if (TREE_CODE (rhs) == TRUTH_NOT_EXPR)
+ {
+ tree type = TREE_TYPE (TREE_OPERAND (cond, 0));
+ bool nans = HONOR_NANS (TYPE_MODE (type));
+ enum tree_code code;
+ code = invert_tree_comparison (TREE_CODE (cond), nans);
+ if (code == ERROR_MARK)
+ return false;
+
+ tmp = build2 (code, TREE_TYPE (lhs), TREE_OPERAND (cond, 0),
+ TREE_OPERAND (cond, 1));
+ }
+ else
+ return false;
+
+ GIMPLE_STMT_OPERAND (use_stmt, 1) = unshare_expr (tmp);
+ update_stmt (use_stmt);
+
+ /* Remove defining statements. */
+ remove_prop_source_from_use (name, stmt);
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, " Replaced '");
+ print_generic_expr (dump_file, rhs, dump_flags);
+ fprintf (dump_file, "' with '");
+ print_generic_expr (dump_file, tmp, dump_flags);
+ fprintf (dump_file, "'\n");
+ }
+
+ return true;
+ }
+
+ return false;
+}
+