From 4a60186570defebed7d811b37c46092267407a96 Mon Sep 17 00:00:00 2001 From: Maximilian Downey Twiss <creatorsmithmdt@gmail.com> Date: Fri, 18 Nov 2022 09:05:50 +1100 Subject: [PATCH 13/56] Re-add flag_evaluation_order, reorder_operands_p, and add reorder bool argument to tree_swap_operands_p.
gcc/ChangeLog: * common.opt (flag_evaluation_order): Re-add. * expr.cc (expand_operands): Re-add code guarded by flag_evaluation_order. * fold-const.cc (reorder_operands_p): Re-add. (negate_expr_p): Handle reorder_operands_p. (fold_negate_expr_1): Likewise. (tree_swap_operands_p): Re-add reorder argument. (fold_binary_loc): Likewise. (fold_ternary_loc): Likewise * fold-const.h (tree_swap_operands_p): Likewise. * genmatch.cc (dt_operand::gen_gimple_expr): Likewise. * gimple-fold.cc (fold_stmt_1): Likewise. * gimple-match-head.cc (gimple_resimplify2): Likewise. (gimple_resimplify3): Likewise. (gimple_resimplify4): Likewise. (gimple_resimplify5): Likewise. (gimple_simplify): Likewise. * match.pd: Likewise. * tree-ssa-dom.cc (record_equality): Likewise. * tree-ssa-reassoc.cc (optimize_range_tests_var_bound): Likewise. * tree-ssa-sccvn.cc (vn_nary_op_compute_hash): Likewise. * tree-ssa-threadedge.cc: Likewise. --- gcc/common.opt | 4 +++ gcc/expr.cc | 4 +++ gcc/fold-const.cc | 51 ++++++++++++++++++++++++++++++-------- gcc/fold-const.h | 2 +- gcc/genmatch.cc | 2 +- gcc/gimple-fold.cc | 8 +++--- gcc/gimple-match-head.cc | 20 +++++++++------ gcc/match.pd | 2 +- gcc/tree-ssa-dom.cc | 2 +- gcc/tree-ssa-reassoc.cc | 2 +- gcc/tree-ssa-sccvn.cc | 4 +-- gcc/tree-ssa-threadedge.cc | 2 +- 12 files changed, 74 insertions(+), 29 deletions(-) diff --git a/gcc/common.opt b/gcc/common.opt index 26e9d1cc4e7..318eafc2e8c 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -62,6 +62,10 @@ int flag_complex_method = 1 Variable int flag_default_complex_method = 1 +; Nonzero if subexpressions must be evaluated from left-to-right. +Variable +int flag_evaluation_order = 0 + ; Language specific warning pass for unused results. Variable bool flag_warn_unused_result = false diff --git a/gcc/expr.cc b/gcc/expr.cc index d9407432ea5..2e770ab090d 100644 --- a/gcc/expr.cc +++ b/gcc/expr.cc @@ -8576,6 +8576,10 @@ expand_operands (tree exp0, tree exp1, rtx target, rtx *op0, rtx *op1, } else { + /* If we need to preserve evaluation order, copy exp0 into its own + temporary variable so that it can't be clobbered by exp1. */ + if (flag_evaluation_order && TREE_SIDE_EFFECTS (exp1)) + exp0 = save_expr (exp0); *op0 = expand_expr (exp0, target, VOIDmode, modifier); *op1 = expand_expr (exp1, NULL_RTX, VOIDmode, modifier); } diff --git a/gcc/fold-const.cc b/gcc/fold-const.cc index b89cac91cae..374878b31a4 100644 --- a/gcc/fold-const.cc +++ b/gcc/fold-const.cc @@ -139,6 +139,7 @@ static tree fold_cond_expr_with_comparison (location_t, tree, enum tree_code, static tree unextend (tree, int, int, tree); static tree extract_muldiv (tree, tree, enum tree_code, tree, bool *); static tree extract_muldiv_1 (tree, tree, enum tree_code, tree, bool *); +static bool reorder_operands_p (const_tree, const_tree); static tree fold_binary_op_with_conditional_arg (location_t, enum tree_code, tree, tree, tree, @@ -472,7 +473,9 @@ negate_expr_p (tree t) && ! TYPE_OVERFLOW_WRAPS (type))) return false; /* -(A + B) -> (-B) - A. */ - if (negate_expr_p (TREE_OPERAND (t, 1))) + if (negate_expr_p (TREE_OPERAND (t, 1)) + && reorder_operands_p (TREE_OPERAND (t, 0), + TREE_OPERAND (t, 1))) return true; /* -(A + B) -> (-A) - B. */ return negate_expr_p (TREE_OPERAND (t, 0)); @@ -482,7 +485,9 @@ negate_expr_p (tree t) return !HONOR_SIGN_DEPENDENT_ROUNDING (type) && !HONOR_SIGNED_ZEROS (type) && (! ANY_INTEGRAL_TYPE_P (type) - || TYPE_OVERFLOW_WRAPS (type)); + || TYPE_OVERFLOW_WRAPS (type)) + && reorder_operands_p (TREE_OPERAND (t, 0), + TREE_OPERAND (t, 1)); case MULT_EXPR: if (TYPE_UNSIGNED (type)) @@ -643,7 +648,9 @@ fold_negate_expr_1 (location_t loc, tree t) && !HONOR_SIGNED_ZEROS (type)) { /* -(A + B) -> (-B) - A. */ - if (negate_expr_p (TREE_OPERAND (t, 1))) + if (negate_expr_p (TREE_OPERAND (t, 1)) + && reorder_operands_p (TREE_OPERAND (t, 0), + TREE_OPERAND (t, 1))) { tem = negate_expr (TREE_OPERAND (t, 1)); return fold_build2_loc (loc, MINUS_EXPR, type, @@ -663,7 +670,8 @@ fold_negate_expr_1 (location_t loc, tree t) case MINUS_EXPR: /* - (A - B) -> B - A */ if (!HONOR_SIGN_DEPENDENT_ROUNDING (type) - && !HONOR_SIGNED_ZEROS (type)) + && !HONOR_SIGNED_ZEROS (element_mode (type)) + && reorder_operands_p (TREE_OPERAND (t, 0), TREE_OPERAND (t, 1))) return fold_build2_loc (loc, MINUS_EXPR, type, TREE_OPERAND (t, 1), TREE_OPERAND (t, 0)); break; @@ -7492,12 +7500,27 @@ fold_single_bit_test (location_t loc, enum tree_code code, return NULL_TREE; } +/* Check whether we are allowed to reorder operands arg0 and arg1, + such that the evaluation of arg1 occurs before arg0. */ + +static bool +reorder_operands_p (const_tree arg0, const_tree arg1) +{ + if (! flag_evaluation_order) + return true; + if (TREE_CONSTANT (arg0) || TREE_CONSTANT (arg1)) + return true; + return ! TREE_SIDE_EFFECTS (arg0) + && ! TREE_SIDE_EFFECTS (arg1); +} + /* Test whether it is preferable to swap two operands, ARG0 and ARG1, for example because ARG0 is an integer constant and ARG1 - isn't. */ + isn't. If REORDER is true, only recommend swapping if we can + evaluate the operands in reverse order. */ bool -tree_swap_operands_p (const_tree arg0, const_tree arg1) +tree_swap_operands_p (const_tree arg0, const_tree arg1, bool reorder) { if (CONSTANT_CLASS_P (arg1)) return 0; @@ -7512,6 +7535,10 @@ tree_swap_operands_p (const_tree arg0, const_tree arg1) if (TREE_CONSTANT (arg0)) return 1; + if (reorder && flag_evaluation_order + && (TREE_SIDE_EFFECTS (arg0) || TREE_SIDE_EFFECTS (arg1))) + return 0; + /* It is preferable to swap two SSA_NAME to ensure a canonical form for commutative and comparison operators. Ensuring a canonical form allows the optimizers to find additional redundancies without @@ -10904,13 +10931,13 @@ fold_binary_loc (location_t loc, enum tree_code code, tree type, /* If this is a commutative operation, and ARG0 is a constant, move it to ARG1 to reduce the number of tests below. */ if (commutative_tree_code (code) - && tree_swap_operands_p (arg0, arg1)) + && tree_swap_operands_p (arg0, arg1, true)) return fold_build2_loc (loc, code, type, op1, op0); /* Likewise if this is a comparison, and ARG0 is a constant, move it to ARG1 to reduce the number of tests below. */ if (kind == tcc_comparison - && tree_swap_operands_p (arg0, arg1)) + && tree_swap_operands_p (arg0, arg1, true)) return fold_build2_loc (loc, swap_tree_comparison (code), type, op1, op0); tem = generic_simplify (loc, code, type, op0, op1); @@ -10969,7 +10996,8 @@ fold_binary_loc (location_t loc, enum tree_code code, tree type, return build2_loc (loc, COMPOUND_EXPR, type, TREE_OPERAND (arg0, 0), tem); } - if (TREE_CODE (arg1) == COMPOUND_EXPR) + if (TREE_CODE (arg1) == COMPOUND_EXPR + && reorder_operands_p (arg0, TREE_OPERAND (arg1, 0))) { tem = fold_build2_loc (loc, code, type, op0, fold_convert_loc (loc, TREE_TYPE (op1), @@ -11519,6 +11547,7 @@ fold_binary_loc (location_t loc, enum tree_code code, tree type, /* (-A) - B -> (-B) - A where B is easily negated and we can swap. */ if (TREE_CODE (arg0) == NEGATE_EXPR && negate_expr_p (op1) + && reorder_operands_p (arg0, arg1) /* If arg0 is e.g. unsigned int and type is int, then this could introduce UB, because if A is INT_MIN at runtime, the original expression can be well defined while the latter is not. @@ -12798,7 +12827,7 @@ fold_ternary_loc (location_t loc, enum tree_code code, tree type, /* If this is a commutative operation, and OP0 is a constant, move it to OP1 to reduce the number of tests below. */ if (commutative_ternary_tree_code (code) - && tree_swap_operands_p (op0, op1)) + && tree_swap_operands_p (op0, op1, true)) return fold_build3_loc (loc, code, type, op1, op0, op2); tem = generic_simplify (loc, code, type, op0, op1, op2); @@ -12931,7 +12960,7 @@ fold_ternary_loc (location_t loc, enum tree_code code, tree type, /* If the second operand is simpler than the third, swap them since that produces better jump optimization results. */ if (truth_value_p (TREE_CODE (arg0)) - && tree_swap_operands_p (op1, op2)) + && tree_swap_operands_p (op1, op2, false)) { location_t loc0 = expr_location_or (arg0, loc); /* See if this can be inverted. If it can't, possibly because diff --git a/gcc/fold-const.h b/gcc/fold-const.h index fa284c712bf..486dad8d252 100644 --- a/gcc/fold-const.h +++ b/gcc/fold-const.h @@ -149,7 +149,7 @@ extern tree build_invariant_address (tree, tree, poly_int64); extern tree constant_boolean_node (bool, tree); extern tree div_if_zero_remainder (const_tree, const_tree); -extern bool tree_swap_operands_p (const_tree, const_tree); +extern bool tree_swap_operands_p (const_tree, const_tree, bool); extern enum tree_code swap_tree_comparison (enum tree_code); extern bool ptr_difference_const (tree, tree, poly_int64_pod *); diff --git a/gcc/genmatch.cc b/gcc/genmatch.cc index 4a8802469cd..6b2be7da519 100644 --- a/gcc/genmatch.cc +++ b/gcc/genmatch.cc @@ -2873,7 +2873,7 @@ dt_operand::gen_gimple_expr (FILE *f, int indent, int depth) gen_opname (child_opname0, opno); gen_opname (child_opname1, opno + 1); fprintf_indent (f, indent, - "if (tree_swap_operands_p (%s, %s))\n", + "if (tree_swap_operands_p (%s, %s, false))\n", child_opname0, child_opname1); fprintf_indent (f, indent, " std::swap (%s, %s);\n", diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc index c2d9c806aee..efc0354566e 100644 --- a/gcc/gimple-fold.cc +++ b/gcc/gimple-fold.cc @@ -6142,7 +6142,7 @@ fold_stmt_1 (gimple_stmt_iterator *gsi, bool inplace, tree (*valueize) (tree)) { tree rhs1 = gimple_assign_rhs1 (stmt); tree rhs2 = gimple_assign_rhs2 (stmt); - if (tree_swap_operands_p (rhs1, rhs2)) + if (tree_swap_operands_p (rhs1, rhs2, false)) { gimple_assign_set_rhs1 (stmt, rhs2); gimple_assign_set_rhs2 (stmt, rhs1); @@ -6178,7 +6178,9 @@ fold_stmt_1 (gimple_stmt_iterator *gsi, bool inplace, tree (*valueize) (tree)) { tree arg1 = gimple_call_arg (call, opno); tree arg2 = gimple_call_arg (call, opno + 1); - if (tree_swap_operands_p (arg1, arg2)) + /* FIXME: Find the correct third value to set for + tree_swap_operands_p here. */ + if (tree_swap_operands_p (arg1, arg2, false)) { gimple_call_set_arg (call, opno, arg2); gimple_call_set_arg (call, opno + 1, arg1); @@ -6226,7 +6228,7 @@ fold_stmt_1 (gimple_stmt_iterator *gsi, bool inplace, tree (*valueize) (tree)) /* Canonicalize operand order. */ tree lhs = gimple_cond_lhs (stmt); tree rhs = gimple_cond_rhs (stmt); - if (tree_swap_operands_p (lhs, rhs)) + if (tree_swap_operands_p (lhs, rhs, false)) { gcond *gc = as_a <gcond *> (stmt); gimple_cond_set_lhs (gc, rhs); diff --git a/gcc/gimple-match-head.cc b/gcc/gimple-match-head.cc index 9986e3479f9..d48a4ca5c86 100644 --- a/gcc/gimple-match-head.cc +++ b/gcc/gimple-match-head.cc @@ -300,7 +300,7 @@ gimple_resimplify2 (gimple_seq *seq, gimple_match_op *res_op, = (res_op->code.is_tree_code () && TREE_CODE_CLASS (tree_code (res_op->code)) == tcc_comparison); if ((is_comparison || commutative_binary_op_p (res_op->code, res_op->type)) - && tree_swap_operands_p (res_op->ops[0], res_op->ops[1])) + && tree_swap_operands_p (res_op->ops[0], res_op->ops[1], false)) { std::swap (res_op->ops[0], res_op->ops[1]); if (is_comparison) @@ -374,11 +374,13 @@ gimple_resimplify3 (gimple_seq *seq, gimple_match_op *res_op, } } - /* Canonicalize operand order. */ + /* Canonicalize operand order. */ bool canonicalized = false; int argno = first_commutative_argument (res_op->code, res_op->type); if (argno >= 0 - && tree_swap_operands_p (res_op->ops[argno], res_op->ops[argno + 1])) + /* FIXME: Find the correct third value to set for + tree_swap_operands_p here. */ + && tree_swap_operands_p (res_op->ops[argno], res_op->ops[argno + 1], false)) { std::swap (res_op->ops[argno], res_op->ops[argno + 1]); canonicalized = true; @@ -428,7 +430,9 @@ gimple_resimplify4 (gimple_seq *seq, gimple_match_op *res_op, bool canonicalized = false; int argno = first_commutative_argument (res_op->code, res_op->type); if (argno >= 0 - && tree_swap_operands_p (res_op->ops[argno], res_op->ops[argno + 1])) + /* FIXME: Find the correct third value to set for + tree_swap_operands_p here. */ + && tree_swap_operands_p (res_op->ops[argno], res_op->ops[argno + 1], false)) { std::swap (res_op->ops[argno], res_op->ops[argno + 1]); canonicalized = true; @@ -479,7 +483,9 @@ gimple_resimplify5 (gimple_seq *seq, gimple_match_op *res_op, bool canonicalized = false; int argno = first_commutative_argument (res_op->code, res_op->type); if (argno >= 0 - && tree_swap_operands_p (res_op->ops[argno], res_op->ops[argno + 1])) + /* FIXME: Find the correct third value to set for + tree_swap_operands_p here. */ + && tree_swap_operands_p (res_op->ops[argno], res_op->ops[argno + 1], false)) { std::swap (res_op->ops[argno], res_op->ops[argno + 1]); canonicalized = true; @@ -732,7 +738,7 @@ gimple_simplify (enum tree_code code, tree type, generation. */ if ((commutative_tree_code (code) || TREE_CODE_CLASS (code) == tcc_comparison) - && tree_swap_operands_p (op0, op1)) + && tree_swap_operands_p (op0, op1, false)) { std::swap (op0, op1); if (TREE_CODE_CLASS (code) == tcc_comparison) @@ -764,7 +770,7 @@ gimple_simplify (enum tree_code code, tree type, /* Canonicalize operand order both for matching and fallback stmt generation. */ if (commutative_ternary_tree_code (code) - && tree_swap_operands_p (op0, op1)) + && tree_swap_operands_p (op0, op1, false)) std::swap (op0, op1); gimple_match_op res_op; diff --git a/gcc/match.pd b/gcc/match.pd index a4d1386fd9f..367cd6d8ca6 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -7870,7 +7870,7 @@ and, /* Since the order of @0 and @2 doesn't matter, let tree_swap_operands_p pick a canonical order. This increases the chances of using the same pointer_plus in multiple checks. */ - (with { bool swap_p = tree_swap_operands_p (@0, @2); + (with { bool swap_p = tree_swap_operands_p (@0, @2, false); tree rhs_tree = wide_int_to_tree (sizetype, rhs); } (if (cmp == LT_EXPR) (gt (convert:sizetype diff --git a/gcc/tree-ssa-dom.cc b/gcc/tree-ssa-dom.cc index c7f095d79fc..edcaa71e12e 100644 --- a/gcc/tree-ssa-dom.cc +++ b/gcc/tree-ssa-dom.cc @@ -1449,7 +1449,7 @@ record_equality (tree x, tree y, class const_and_copies *const_and_copies) { tree prev_x = NULL, prev_y = NULL; - if (tree_swap_operands_p (x, y)) + if (tree_swap_operands_p (x, y, false)) std::swap (x, y); /* Most of the time tree_swap_operands_p does what we want. But there diff --git a/gcc/tree-ssa-reassoc.cc b/gcc/tree-ssa-reassoc.cc index b39c3c882c4..d50bece1d38 100644 --- a/gcc/tree-ssa-reassoc.cc +++ b/gcc/tree-ssa-reassoc.cc @@ -3987,7 +3987,7 @@ optimize_range_tests_var_bound (enum tree_code opcode, int first, int length, rhs2 = gimple_assign_lhs (g); gsi_insert_before (&gsi, g, GSI_SAME_STMT); } - if (tree_swap_operands_p (rhs1, rhs2)) + if (tree_swap_operands_p (rhs1, rhs2, false)) { std::swap (rhs1, rhs2); ccode = swap_tree_comparison (ccode); diff --git a/gcc/tree-ssa-sccvn.cc b/gcc/tree-ssa-sccvn.cc index 37484403c56..47872db7bcd 100644 --- a/gcc/tree-ssa-sccvn.cc +++ b/gcc/tree-ssa-sccvn.cc @@ -4146,10 +4146,10 @@ vn_nary_op_compute_hash (const vn_nary_op_t vno1) && commutative_tree_code (vno1->opcode)) || (vno1->length == 3 && commutative_ternary_tree_code (vno1->opcode))) - && tree_swap_operands_p (vno1->op[0], vno1->op[1])) + && tree_swap_operands_p (vno1->op[0], vno1->op[1], false)) std::swap (vno1->op[0], vno1->op[1]); else if (TREE_CODE_CLASS (vno1->opcode) == tcc_comparison - && tree_swap_operands_p (vno1->op[0], vno1->op[1])) + && tree_swap_operands_p (vno1->op[0], vno1->op[1], false)) { std::swap (vno1->op[0], vno1->op[1]); vno1->opcode = swap_tree_comparison (vno1->opcode); diff --git a/gcc/tree-ssa-threadedge.cc b/gcc/tree-ssa-threadedge.cc index 905a98c8c68..0caef94a62b 100644 --- a/gcc/tree-ssa-threadedge.cc +++ b/gcc/tree-ssa-threadedge.cc @@ -490,7 +490,7 @@ jump_threader::simplify_control_stmt_condition_1 example, op0 might be a constant while op1 is an SSA_NAME. Failure to canonicalize will cause us to miss threading opportunities. */ - if (tree_swap_operands_p (op0, op1)) + if (tree_swap_operands_p (op0, op1, false)) { cond_code = swap_tree_comparison (cond_code); std::swap (op0, op1); -- 2.38.1