===================================================================
@@ -1650,6 +1650,695 @@ maybe_cleanup_end_of_block (edge e, rtx
}
}
+/* Check if statement can be considered as a "simple" one. Simples are:
+ - minimal invariant
+ - any non-SSA_NAME veriant
+ - any SSA_NAME variant without a definition statement
+ - any SSA_NAME with default definition.
+ - an assignment of kind ~X, if X is minimal invariant, or has no
+ definition statement, We exclude here floating point types for X
+ and Y, as ~ (X cmp Y) can have special meaning on floats..
+ - an assignment of kind X ^ ~0, if X is minimal invariant, or has no
+ definition statement, */
+
+static bool
+is_bool_op_p (tree op, bool *is_not)
+{
+ gimple s;
+ enum tree_code code;
+
+ *is_not = false;
+
+ /* Reject result types not of boolean kine. */
+ if (TREE_CODE (TREE_TYPE (op)) != BOOLEAN_TYPE)
+ return false;
+
+ if (is_gimple_min_invariant (op)
+ || TREE_CODE (op) != SSA_NAME)
+ return true;
+
+ if ((!SA.values || !bitmap_bit_p (SA.values, SSA_NAME_VERSION (op)))
+ && SSA_NAME_DEF_STMT (op)
+ && !SSA_NAME_IS_DEFAULT_DEF (op))
+ return false;
+ if (SSA_NAME_IS_DEFAULT_DEF (op)
+ || (s = SSA_NAME_DEF_STMT (op)) == NULL)
+ return true;
+ /* Reject statement which isn't of kind assign. */
+ if (!is_gimple_assign (s))
+ return false;
+
+ code = gimple_assign_rhs_code (s);
+
+ /* See if we have a "simple" logical not. */
+ if (code == BIT_NOT_EXPR)
+ *is_not = true;
+ else if (code == BIT_XOR_EXPR
+ && integer_all_onesp (gimple_assign_rhs2 (s)))
+ *is_not = true;
+ else
+ return false;
+
+ op = gimple_assign_rhs1 (s);
+
+ if (TREE_CODE (op) != SSA_NAME)
+ return false;
+
+ /* Can the inner statement be considered as
+ simple. */
+ if (is_gimple_min_invariant (op)
+ || SSA_NAME_IS_DEFAULT_DEF (op)
+ || SSA_NAME_DEF_STMT (op) == NULL)
+ return true;
+
+ *is_not = false;
+ return false;
+}
+
+/* This helper routine normalizes comparisons on boolean-typed operands
+ for OP1 ==/!= CST.
+ Folded patterns are:
+ X ==/!= 1 -> X !=/== 0
+ ~(X cmp Y) !=/== 0 -> (X cmp Y) ==/!= 0, if X and Y aren't floats.
+ ~(X & Y) !=/== 0 -> (X & Y) ==/!= 0
+ ~(Y | Y) !=/== 0 -> (X | Y) ==/!= 0
+ (X cmp Y) != 0 -> (X cmp Y)
+ (X cmp Y) == 0 -> (X cmp-invert Y), if X and Y aren't floats.
+ Note: We reject here operations on floats as pattern ~(float-compare)
+ can have side-effects. */
+
+static void
+normalize_truth_condition (enum tree_code *cmp, tree *op1, tree *op2)
+{
+ gimple stmt, s;
+ tree nop0, nop1, op;
+ tree type = TREE_TYPE (*op1);
+ enum tree_code code2;
+
+ if (TREE_CODE (type) != BOOLEAN_TYPE
+ || (*cmp != EQ_EXPR && *cmp != NE_EXPR)
+ || TREE_CODE (*op2) != INTEGER_CST)
+ return;
+
+ if (!SA.values
+ || TREE_CODE (*op1) != SSA_NAME
+ || (!bitmap_bit_p (SA.values, SSA_NAME_VERSION (*op1))
+ && SSA_NAME_DEF_STMT (*op1)))
+ return;
+
+ if (integer_onep (*op2))
+ {
+ *op2 = build_int_cst (type, 0);
+ *cmp = (*cmp == EQ_EXPR ? NE_EXPR : EQ_EXPR);
+ }
+
+ for (;;)
+ {
+ if (!SA.values
+ || TREE_CODE (*op1) != SSA_NAME
+ || !bitmap_bit_p (SA.values, SSA_NAME_VERSION (*op1)))
+ return;
+
+ stmt = SSA_NAME_DEF_STMT (*op1);
+ if (gimple_code (stmt) != GIMPLE_ASSIGN)
+ return;
+
+ code2 = gimple_assign_rhs_code (stmt);
+ if (code2 != BIT_NOT_EXPR)
+ break;
+ op = gimple_assign_rhs1 (stmt);
+
+ if (!SA.values
+ || TREE_CODE (op) != SSA_NAME
+ || !bitmap_bit_p (SA.values, SSA_NAME_VERSION (op)))
+ return;
+
+ s = SSA_NAME_DEF_STMT (op);
+ if (!s || gimple_code (s) != GIMPLE_ASSIGN)
+ return;
+
+ code2 = gimple_assign_rhs_code (s);
+
+ if (TREE_CODE_CLASS (code2) == tcc_comparison)
+ {
+ tree t = TREE_TYPE (gimple_assign_rhs1 (s));
+
+ /* Don't fold ~ (X cmp Y) ==/!= 0 to (X cmp Y) ==/!= 0,
+ if operands of comparison are floating-points. */
+ if (FLOAT_TYPE_P (t))
+ return;
+ }
+ else if (code2 != BIT_AND_EXPR && code2 != BIT_IOR_EXPR)
+ return;
+ *op1 = op;
+ *cmp = (*cmp == EQ_EXPR ? NE_EXPR : EQ_EXPR);
+ }
+
+ if (TREE_CODE_CLASS (code2) != tcc_comparison)
+ return;
+
+ nop0 = gimple_assign_rhs1 (stmt);
+ nop1 = gimple_assign_rhs2 (stmt);
+
+ /* Case (X cmp Y) != 0 -> X cmp Y. */
+ if (*cmp == NE_EXPR)
+ {
+ *cmp = code2;
+ *op1 = nop0;
+ *op2 = nop1;
+ return;
+ }
+
+ /* Case (X cmp Y) == 0 */
+
+ type = TREE_TYPE (nop0);
+ if (FLOAT_TYPE_P (type))
+ return;
+ code2 = invert_tree_comparison (*cmp,
+ HONOR_NANS (TYPE_MODE (type)));
+ if (code2 == ERROR_MARK)
+ return;
+ *cmp = code2;
+ *op1 = nop0;
+ *op2 = nop1;
+}
+
+/* Structure to keep some attributes of operands
+ for bitwise-and/or chain within a condition. */
+
+typedef struct {
+ tree leaf;
+ enum tree_code code;
+ tree op2;
+ tree type;
+ bool sa_valued;
+ bool is_bool;
+ bool is_trap;
+ bool has_sideeffect;
+ bool is_bool_not;
+ bool is_or;
+ bool is_and;
+ bool joined;
+} cond_assoc_t;
+
+DEF_VEC_O(cond_assoc_t);
+DEF_VEC_ALLOC_O(cond_assoc_t, heap);
+
+/* Build up operand list in OP for bitwise operand chain of kind CODE and
+ store each element in CONDS, if non-NULL..
+ CMP can be either EQ_EXPR or NE_EXPR, and op2 is integral zero.
+ Function returns the count of found elements in OP. */
+static int
+collect_cond_chain (tree op, enum tree_code code,
+ VEC (cond_assoc_t, heap) **pconds,
+ enum tree_code cmp, tree op2)
+{
+ gimple s = NULL;
+ int ret = 0;
+ bool sa_valued;
+
+ sa_valued = (SA.values
+ && TREE_CODE (op) == SSA_NAME
+ && (bitmap_bit_p (SA.values,
+ SSA_NAME_VERSION (op))
+ || SSA_NAME_DEF_STMT (op) == NULL));
+ if (TREE_CODE (op) != SSA_NAME
+ || !sa_valued
+ || (s = SSA_NAME_DEF_STMT (op)) == NULL
+ || !is_gimple_assign (s)
+ || gimple_assign_rhs_code (s) != code)
+ {
+ enum tree_code ncode = cmp;
+ tree nop2 = op2;
+ cond_assoc_t tmp;
+
+ memset (&tmp, 0, sizeof (cond_assoc_t));
+ normalize_truth_condition (&ncode, &op, &nop2);
+
+ tmp.leaf = op;
+ tmp.code = ncode;
+ tmp.op2 = nop2;
+ tmp.type = boolean_type_node;
+ tmp.sa_valued = sa_valued;
+
+ s = NULL;
+ if (TREE_CODE (op) != SSA_NAME
+ || !sa_valued
+ || (s = SSA_NAME_DEF_STMT (op)) == NULL
+ || !is_gimple_assign (s))
+ s = NULL;
+
+ if (s)
+ tmp.is_trap = gimple_could_trap_p (s);
+ if (s)
+ tmp.has_sideeffect = gimple_has_side_effects (s);
+
+ if ((ncode == EQ_EXPR || ncode == NE_EXPR)
+ && TREE_CODE (TREE_TYPE (op)) == BOOLEAN_TYPE
+ && integer_zerop (nop2))
+ {
+ tmp.is_bool_not = false;
+ tmp.is_bool = is_bool_op_p (op, &tmp.is_bool_not);
+
+ if (!tmp.is_bool || tmp.is_trap || tmp.has_sideeffect)
+ {
+ tmp.is_bool = false;
+ tmp.is_bool_not = false;
+ }
+ code = ERROR_MARK;
+ if (s && is_gimple_assign (s)
+ && TREE_CODE (TREE_TYPE (op)) == BOOLEAN_TYPE)
+ code = gimple_assign_rhs_code (s);
+ tmp.is_or = (code == BIT_IOR_EXPR);
+ tmp.is_and = (code == BIT_AND_EXPR);
+ }
+
+ VEC_safe_push (cond_assoc_t, heap, *pconds, &tmp);
+ return 1;
+ }
+ ret = collect_cond_chain (gimple_assign_rhs1 (s), code,
+ pconds, cmp, op2);
+ ret += collect_cond_chain (gimple_assign_rhs2 (s), code,
+ pconds, cmp, op2);
+
+ return ret;
+}
+
+/* This routine collects the bitwise operand chain of CODE in OP.
+ The found amount of elements is stored in *PCNT.
+ The function returns the pointer allocated buffer containing
+ *PCNT elements. */
+
+static VEC (cond_assoc_t, heap) *
+get_condition_list_for (tree op, enum tree_code code, int *pcnt,
+ enum tree_code cmp, tree cst)
+{
+ int cnt;
+ VEC (cond_assoc_t, heap) *conds = NULL;
+ cnt = collect_cond_chain (op, code, &conds, cmp, cst);
+
+ *pcnt = cnt;
+
+ return conds;
+}
+
+/* Helper function to build a binary tree.
+ If OP0 is boolean-typed, CODE is equal to NE_EXPR,
+ and OP2 is zero constant, then return OP0. Otherwise
+ the result of build2 is returned. */
+
+static tree
+build_cond_expr (enum tree_code code, tree type, tree op0, tree op1)
+{
+ if (code == NE_EXPR && integer_zerop (op1)
+ && TREE_CODE (TREE_TYPE (op0)) == BOOLEAN_TYPE)
+ return op0;
+ return build2 (code, type, op0, op1);
+}
+
+/* Deside if we can spare branch costs on combining
+ L and R operands for bitwise-and/or dependent on BRANCH_COST.
+ Function returns TRUE, if combining of L and R might be profitable,
+ otherwise FALSE is returned. */
+
+static bool
+is_bitwise_binary_simple_combine (cond_assoc_t *l, cond_assoc_t *r)
+{
+ bool op0_has_not = false, op1_has_not = false;
+ int bcosts = BRANCH_COST (optimize_insn_for_speed_p (), false);
+ int costs = 1;
+
+ /* If jumps aren't cheap avoid to turn some more codes into
+ jumpy sequences. */
+ if (bcosts > 4)
+ return true;
+
+ /* We would spare one branch, but higher the count of executed
+ instructions. */
+ if (bcosts <= 0)
+ return false;
+
+ if (l->is_bool == false || r->is_bool == false)
+ return false;
+
+ op0_has_not = l->is_bool_not;
+ op1_has_not = r->is_bool_not;
+
+ /* If L and R have inner bit-not, then there
+ are no additional costs for them. */
+ if (op0_has_not && op1_has_not)
+ op0_has_not = op1_has_not = false;
+
+ /* If comparison codes of L and R aren't equal, then
+ it might be more costy to combine them, if not
+ on arm doesn't have an inner logical-not. */
+ if (l->code != r->code)
+ {
+ if (op0_has_not)
+ op0_has_not = false;
+ else if (op1_has_not)
+ op1_has_not = false;
+ else
+ op0_has_not = true;
+ }
+ /* If leaf of L or R isn't boolean-typed, then we have at least
+ two operations to obtain result.
+ Each logical-not costs one more operation. */
+
+ if (TREE_CODE (TREE_TYPE (l->leaf)) != BOOLEAN_TYPE)
+ costs += 2;
+ else if (op0_has_not)
+ costs++;
+
+ if (TREE_CODE (TREE_TYPE (r->leaf)) != BOOLEAN_TYPE)
+ costs += 2;
+ else if (op1_has_not)
+ costs++;
+
+ if (bcosts < costs)
+ return false;
+
+ return true;
+}
+
+/* Obtain some characteristics on comparison of intergral typed
+ arguments and determine if we have here a simple combinable
+ operand.
+ In PREFIX_NOT the value TRUE is stored, if operand CA contains
+ a value-invert operation.
+ In CMP_ZERO the value TRUE is stored, if operand CA is a comparison
+ to integral zero.
+ This function returns TRUE, if a possible candidate was matched,
+ otherwise it returns FALSE. */
+
+static bool
+preeval_cond_integral (const cond_assoc_t *ca, bool *prefix_not, bool *cmp_zero)
+{
+ gimple s = NULL;
+ tree o;
+
+ if (ca->joined == true
+ || ca->is_bool
+ || ca->is_trap || ca->has_sideeffect
+ || ca->sa_valued == false
+ || ca->is_and || ca->is_or)
+ return false;
+
+ /* Reject anything different than X !=/== 0 and X !=/== ~0. */
+ if ((ca->code != EQ_EXPR && ca->code != NE_EXPR)
+ || !INTEGRAL_TYPE_P (TREE_TYPE (ca->leaf))
+ || TREE_CODE (TREE_TYPE (ca->leaf)) == BOOLEAN_TYPE
+ || (!integer_zerop (ca->op2) && !integer_all_onesp (ca->op2)))
+ return false;
+
+ if (TREE_CODE (ca->leaf) != SSA_NAME)
+ return false;
+ *prefix_not = false;
+ *cmp_zero = integer_zerop (ca->op2);
+
+ s = SSA_NAME_DEF_STMT (ca->leaf);
+ if (!s || SSA_NAME_IS_DEFAULT_DEF (ca->leaf))
+ return true;
+
+ /* See if we have a valid ~X pattern in left-hand comparison
+ operand. */
+ if (!is_gimple_assign (s)
+ || gimple_assign_rhs_code (s) != BIT_NOT_EXPR)
+ return false;
+
+ o = gimple_assign_rhs1 (s);
+
+ if (TREE_CODE (o) != SSA_NAME
+ || !SA.values
+ || (!bitmap_bit_p (SA.values, SSA_NAME_VERSION (o))
+ && SSA_NAME_DEF_STMT (o) != NULL))
+ return false;
+
+ *prefix_not = true;
+ s = SSA_NAME_DEF_STMT (o);
+ if (!s || SSA_NAME_IS_DEFAULT_DEF (o))
+ return true;
+ *prefix_not = false;
+
+ return false;
+}
+
+/* Helper routine to do branch-cost optimization for operand-list
+ in CA with count CA_COUNT. The bitwise-binary operation BITCODE needs
+ to be toggled between and/or, if INVERTED is TRUE.
+ In PCODE the final binary result-code is stored. In POP0 and POP1
+ its final operands. */
+
+static void
+combine_conds (VEC (cond_assoc_t, heap) *ca, int ca_count, bool inverted,
+ enum tree_code bitcode, enum tree_code *pcode, tree *pop0, tree *pop1)
+{
+ VEC (cond_assoc_t, heap) *sub_ca;
+ int sub_ca_count, i, l;
+ tree collect = NULL_TREE, tem;
+ enum tree_code chain_bitwise = bitcode;
+ enum tree_code chain_logical;
+ cond_assoc_t *ca_i, *ca_l;
+
+ if (inverted)
+ chain_bitwise = (chain_bitwise == BIT_AND_EXPR ? BIT_IOR_EXPR
+ : BIT_AND_EXPR);
+ chain_logical = (chain_bitwise == BIT_AND_EXPR ? TRUTH_ANDIF_EXPR
+ : TRUTH_ORIF_EXPR);
+
+ /* First try to combine the comparisons on integral-typed arguments, which
+ aren't boolean-typed. */
+ for (i = 0; i < ca_count; i++)
+ {
+ tree o1, o2;
+ bool op1_not = false, op2_not = false;
+ bool op1_cmp_zero = false, op2_cmp_zero = false;
+ int bcosts = BRANCH_COST (optimize_insn_for_speed_p (), false);
+
+ if (bcosts < 2)
+ break;
+ ca_i = VEC_index (cond_assoc_t, ca, i);
+ if (!preeval_cond_integral (ca_i, &op1_not, &op1_cmp_zero))
+ continue;
+
+ if ((chain_bitwise == BIT_IOR_EXPR && ca_i->code != NE_EXPR)
+ || (chain_bitwise == BIT_AND_EXPR && ca_i->code != EQ_EXPR))
+ continue;
+
+ for (l = i + 1; l < ca_count; l++)
+ {
+ tree p1;
+
+ ca_l = VEC_index (cond_assoc_t, ca, l);
+ if (!preeval_cond_integral (ca_l, &op2_not, &op2_cmp_zero))
+ continue;
+ if (ca_i->code != ca_l->code)
+ continue;
+
+ if (TREE_TYPE (ca_i->leaf) != TREE_TYPE (ca_l->leaf))
+ continue;
+
+ o1 = ca_i->leaf;
+ o2 = ca_l->leaf;
+ p1 = ca_i->op2;
+
+ if (op1_cmp_zero == op2_cmp_zero)
+ {
+ if (op2_not && op1_not)
+ {
+ o1 = gimple_assign_rhs1 (SSA_NAME_DEF_STMT (o1));
+ p1 = fold_build1 (BIT_NOT_EXPR, TREE_TYPE (p1), p1);
+ o2 = gimple_assign_rhs1 (SSA_NAME_DEF_STMT (o2));
+ op1_cmp_zero = !op1_cmp_zero;
+ }
+ else if ((op1_not || op2_not) && bcosts <= 2)
+ continue;
+ }
+ else if (!op1_not && !op2_not)
+ continue;
+ else if (op1_not)
+ {
+ if (op2_not && bcosts <= 2)
+ continue;
+ o1 = gimple_assign_rhs1 (SSA_NAME_DEF_STMT (o1));
+ p1 = fold_build1 (BIT_NOT_EXPR, TREE_TYPE (p1), p1);
+ op1_cmp_zero = !op1_cmp_zero;
+ }
+ else
+ o2 = gimple_assign_rhs1 (SSA_NAME_DEF_STMT (o2));
+
+ if (op1_cmp_zero)
+ ca_i->leaf = build2 (BIT_IOR_EXPR, TREE_TYPE (o1), o1, o2);
+ else
+ ca_i->leaf = build2 (BIT_AND_EXPR, TREE_TYPE (o1), o1, o2);
+ ca_i->op2 = p1;
+ ca_l->joined = true;
+ break;
+ }
+ }
+
+ /* Now try to combine comparisons on boolean-typed arguments and do
+ operations for inner bitwise and/or chains. */
+ for (i = 0; i < ca_count; i++)
+ {
+ ca_i = VEC_index (cond_assoc_t, ca, i);
+ if (ca_i->joined == true)
+ continue;
+
+ if (ca_i->is_and || ca_i->is_or)
+ {
+ enum tree_code sub_code;
+ tree op0;
+ tree cst = ca_i->op2;
+ enum tree_code ao_code = ca_i->code;
+
+ sub_ca = get_condition_list_for (ca_i->leaf,
+ (ca_i->is_and ? BIT_AND_EXPR : BIT_IOR_EXPR),
+ &sub_ca_count,
+ ao_code, cst);
+ combine_conds (sub_ca, sub_ca_count, (ao_code == EQ_EXPR),
+ (ca_i->is_and ? BIT_AND_EXPR : BIT_IOR_EXPR),
+ &sub_code, &op0, &cst);
+ VEC_free (cond_assoc_t, heap, sub_ca);
+ sub_ca = NULL;
+ tem = build_cond_expr (sub_code, ca_i->type, op0, cst);
+ ca_i->joined = true;
+ }
+ else
+ {
+ ca_i->joined = true;
+ tem = NULL_TREE;
+ if (ca_i->is_bool)
+ {
+ for (l = i + 1; l < ca_count; l++)
+ {
+ ca_l = VEC_index (cond_assoc_t, ca, l);
+ if (ca_l->joined == true || ca_l->is_bool == false)
+ continue;
+ if (is_bitwise_binary_simple_combine (ca_i, ca_l))
+ break;
+ }
+ if (l < ca_count)
+ {
+ tree tem2;
+ enum tree_code bitw = chain_bitwise;
+
+ ca_l = VEC_index (cond_assoc_t, ca, l);
+ /* ~X == 0 -> X != 0, ~X != 0 -> X == 0 */
+ if (ca_i->is_bool_not && ca_l->is_bool_not)
+ {
+ gimple s = SSA_NAME_DEF_STMT (ca_i->leaf);
+ ca_i->leaf = gimple_assign_rhs1 (s);
+ ca_i->code = (ca_i->code == EQ_EXPR ? NE_EXPR : EQ_EXPR);
+ s = SSA_NAME_DEF_STMT (ca_l->leaf);
+ ca_l->leaf = gimple_assign_rhs1 (s);
+ ca_l->code = (ca_l->code == EQ_EXPR ? NE_EXPR : EQ_EXPR);
+ }
+ if (ca_i->code != ca_l->code)
+ {
+ gimple s;
+
+ if (ca_i->is_bool_not)
+ {
+ s = SSA_NAME_DEF_STMT (ca_i->leaf);
+ ca_i->leaf = gimple_assign_rhs1 (s);
+ ca_i->code = (ca_i->code == EQ_EXPR ? NE_EXPR : EQ_EXPR);
+ }
+ else
+ {
+ s = SSA_NAME_DEF_STMT (ca_l->leaf);
+ ca_l->leaf = gimple_assign_rhs1 (s);
+ ca_l->code = (ca_l->code == EQ_EXPR ? NE_EXPR : EQ_EXPR);
+ }
+ }
+ /* (X == 0 op Y == 0) != 0 -> (X op-inv Y) == 0. */
+ if (ca_i->code == EQ_EXPR && ca_l->code == EQ_EXPR)
+ {
+ bitw = (bitw == BIT_AND_EXPR ? BIT_IOR_EXPR
+ : BIT_AND_EXPR);
+ tem = build_cond_expr (NE_EXPR, ca_i->type,
+ ca_i->leaf, ca_i->op2);
+ tem2 = build_cond_expr (NE_EXPR, ca_l->type,
+ ca_l->leaf, ca_l->op2);
+ tem = build_cond_expr (bitw,
+ TREE_TYPE (tem), tem, tem2);
+ tem = build_cond_expr (EQ_EXPR, ca_i->type, tem,
+ ca_i->op2);
+ }
+ else
+ {
+ tem = build_cond_expr (ca_i->code, ca_i->type,
+ ca_i->leaf, ca_i->op2);
+ tem2 = build_cond_expr (ca_l->code, ca_l->type,
+ ca_l->leaf, ca_l->op2);
+ tem = build_cond_expr (bitw,
+ TREE_TYPE (tem), tem, tem2);
+ }
+ ca_l->joined = true;
+ }
+ }
+
+ if (!tem)
+ tem = build_cond_expr (ca_i->code, ca_i->type, ca_i->leaf, ca_i->op2);
+ }
+
+ if (!collect)
+ collect = tem;
+ else
+ collect = build2 (chain_logical, TREE_TYPE (collect), collect, tem);
+ }
+
+ *pcode = TREE_CODE (collect);
+ *pop0 = TREE_OPERAND (collect, 0);
+ *pop1 = TREE_OPERAND (collect, 1);
+}
+
+/* Helper routine to do branch-cost optimization on binary expression
+ *POP0 *PCODE *POP1. */
+
+static void
+branchcost_optimization_on_conditions (enum tree_code *pcode, tree *pop0,
+ tree *pop1)
+{
+ tree op0 = *pop0;
+ tree op1 = *pop1;
+ tree type = TREE_TYPE (op0);
+ enum tree_code code = *pcode;
+ gimple stmt;
+ bool invert = false;
+ VEC (cond_assoc_t, heap) *ca = NULL;
+ int ca_count;
+
+ if (TREE_CODE (type) != BOOLEAN_TYPE
+ || !integer_zerop (op1)
+ || (code != EQ_EXPR && code != NE_EXPR))
+ return;
+
+ if (!SA.values
+ || TREE_CODE (op0) != SSA_NAME
+ || !bitmap_bit_p (SA.values, SSA_NAME_VERSION (op0)))
+ return;
+
+ invert = (code == EQ_EXPR);
+ stmt = SSA_NAME_DEF_STMT (op0);
+ if (gimple_code (stmt) != GIMPLE_ASSIGN)
+ return;
+ switch (gimple_assign_rhs_code (stmt))
+ {
+ case BIT_AND_EXPR:
+ case BIT_IOR_EXPR:
+ break;
+ default:
+ return;
+ }
+
+ ca = get_condition_list_for (op0, gimple_assign_rhs_code (stmt),
+ &ca_count, code, op1);
+ combine_conds (ca, ca_count, invert, gimple_assign_rhs_code (stmt),
+ pcode, pop0, pop1);
+ VEC_free (cond_assoc_t, heap, ca);
+}
+
/* A subroutine of expand_gimple_basic_block. Expand one GIMPLE_COND.
Returns a new basic block if we've terminated the current basic
block and created a new one. */
@@ -1668,6 +2357,8 @@ expand_gimple_cond (basic_block bb, gimp
code = gimple_cond_code (stmt);
op0 = gimple_cond_lhs (stmt);
op1 = gimple_cond_rhs (stmt);
+
+ normalize_truth_condition (&code, &op0, &op1);
/* We're sometimes presented with such code:
D.123_1 = x < y;
if (D.123_1 != 0)
@@ -1676,44 +2367,16 @@ expand_gimple_cond (basic_block bb, gimp
be cleaned up by combine. But some pattern matchers like if-conversion
work better when there's only one compare, so make up for this
here as special exception if TER would have made the same change. */
- if (gimple_cond_single_var_p (stmt)
- && SA.values
- && TREE_CODE (op0) == SSA_NAME
- && bitmap_bit_p (SA.values, SSA_NAME_VERSION (op0)))
- {
- gimple second = SSA_NAME_DEF_STMT (op0);
- if (gimple_code (second) == GIMPLE_ASSIGN)
- {
- enum tree_code code2 = gimple_assign_rhs_code (second);
- if (TREE_CODE_CLASS (code2) == tcc_comparison)
- {
- code = code2;
- op0 = gimple_assign_rhs1 (second);
- op1 = gimple_assign_rhs2 (second);
- }
- /* If jumps are cheap turn some more codes into
- jumpy sequences. */
- else if (BRANCH_COST (optimize_insn_for_speed_p (), false) < 4)
- {
- if ((code2 == BIT_AND_EXPR
- && TYPE_PRECISION (TREE_TYPE (op0)) == 1
- && TREE_CODE (gimple_assign_rhs2 (second)) != INTEGER_CST)
- || code2 == TRUTH_AND_EXPR)
- {
- code = TRUTH_ANDIF_EXPR;
- op0 = gimple_assign_rhs1 (second);
- op1 = gimple_assign_rhs2 (second);
- }
- else if (code2 == BIT_IOR_EXPR || code2 == TRUTH_OR_EXPR)
- {
- code = TRUTH_ORIF_EXPR;
- op0 = gimple_assign_rhs1 (second);
- op1 = gimple_assign_rhs2 (second);
- }
- }
- }
- }
+ branchcost_optimization_on_conditions (&code, &op0, &op1);
+ /* Take care that final statement is a comparison, if we end
+ up with an AND or OR associative statement. */
+ if (code == BIT_AND_EXPR || code == BIT_IOR_EXPR)
+ {
+ op0 = build2 (code, TREE_TYPE (op0), op0, op1);
+ code = NE_EXPR;
+ op1 = build_int_cst (TREE_TYPE (op0), 0);
+ }
last2 = last = get_last_insn ();
extract_true_false_edges_from_block (bb, &true_edge, &false_edge);
===================================================================
@@ -579,13 +579,12 @@ do_jump (tree exp, rtx if_false_label, r
goto normal;
/* Boolean comparisons can be compiled as TRUTH_AND_EXPR. */
-
case TRUTH_AND_EXPR:
/* High branch cost, expand as the bitwise AND of the conditions.
Do the same if the RHS has side effects, because we're effectively
turning a TRUTH_AND_EXPR into a TRUTH_ANDIF_EXPR. */
if (BRANCH_COST (optimize_insn_for_speed_p (),
- false) >= 4
+ false) >= 1
|| TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 1)))
goto normal;
code = TRUTH_ANDIF_EXPR;
@@ -596,7 +595,7 @@ do_jump (tree exp, rtx if_false_label, r
/* High branch cost, expand as the bitwise OR of the conditions.
Do the same if the RHS has side effects, because we're effectively
turning a TRUTH_OR_EXPR into a TRUTH_ORIF_EXPR. */
- if (BRANCH_COST (optimize_insn_for_speed_p (), false) >= 4
+ if (BRANCH_COST (optimize_insn_for_speed_p (), false) >= 1
|| TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 1)))
goto normal;
code = TRUTH_ORIF_EXPR;
===================================================================
@@ -3711,13 +3711,26 @@ simple_operand_p_2 (tree exp)
code = TREE_CODE (exp);
- if (TREE_CODE_CLASS (code) == tcc_comparison)
- return (simple_operand_p (TREE_OPERAND (exp, 0))
- && simple_operand_p (TREE_OPERAND (exp, 1)));
+ if (code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR)
+ return false;
+
+ /* We need to recurse here tree for two reasons. First is that
+ simple_operand_p would reject too much binary/unary/expression-kind
+ expression. Secondly, tree_could_trap_p doesn't inspect all kind
+ of binary/expression/unary-expression and so misses some side-effects. */
+
+ if (TREE_CODE_CLASS (code) == tcc_binary
+ || TREE_CODE_CLASS (code) == tcc_comparison
+ || code == TRUTH_AND_EXPR || code == TRUTH_OR_EXPR
+ || code == TRUTH_XOR_EXPR)
+ return (simple_operand_p_2 (TREE_OPERAND (exp, 0))
+ && simple_operand_p_2 (TREE_OPERAND (exp, 1)));
- if (code == TRUTH_NOT_EXPR)
+ if (TREE_CODE_CLASS (code) == tcc_unary
+ || code == TRUTH_NOT_EXPR)
return simple_operand_p_2 (TREE_OPERAND (exp, 0));
+ /* This function is in some cases too strict. */
return simple_operand_p (exp);
}
@@ -4875,45 +4888,6 @@ fold_range_test (location_t loc, enum tr
return or_op ? invert_truthvalue_loc (loc, tem) : tem;
}
- /* On machines where the branch cost is expensive, if this is a
- short-circuited branch and the underlying object on both sides
- is the same, make a non-short-circuit operation. */
- else if (LOGICAL_OP_NON_SHORT_CIRCUIT
- && lhs != 0 && rhs != 0
- && (code == TRUTH_ANDIF_EXPR
- || code == TRUTH_ORIF_EXPR)
- && operand_equal_p (lhs, rhs, 0))
- {
- /* If simple enough, just rewrite. Otherwise, make a SAVE_EXPR
- unless we are at top level or LHS contains a PLACEHOLDER_EXPR, in
- which cases we can't do this. */
- if (simple_operand_p (lhs))
- return build2_loc (loc, code == TRUTH_ANDIF_EXPR
- ? TRUTH_AND_EXPR : TRUTH_OR_EXPR,
- type, op0, op1);
-
- else if (!lang_hooks.decls.global_bindings_p ()
- && !CONTAINS_PLACEHOLDER_P (lhs))
- {
- tree common = save_expr (lhs);
-
- if (0 != (lhs = build_range_check (loc, type, common,
- or_op ? ! in0_p : in0_p,
- low0, high0))
- && (0 != (rhs = build_range_check (loc, type, common,
- or_op ? ! in1_p : in1_p,
- low1, high1))))
- {
- if (strict_overflow_p)
- fold_overflow_warning (warnmsg,
- WARN_STRICT_OVERFLOW_COMPARISON);
- return build2_loc (loc, code == TRUTH_ANDIF_EXPR
- ? TRUTH_AND_EXPR : TRUTH_OR_EXPR,
- type, lhs, rhs);
- }
- }
- }
-
return 0;
}
@@ -5143,40 +5117,6 @@ fold_truth_andor_1 (location_t loc, enum
code = ((code == TRUTH_AND_EXPR || code == TRUTH_ANDIF_EXPR)
? TRUTH_AND_EXPR : TRUTH_OR_EXPR);
- /* If the RHS can be evaluated unconditionally and its operands are
- simple, it wins to evaluate the RHS unconditionally on machines
- with expensive branches. In this case, this isn't a comparison
- that can be merged. */
-
- if (BRANCH_COST (optimize_function_for_speed_p (cfun),
- false) >= 2
- && ! FLOAT_TYPE_P (TREE_TYPE (rl_arg))
- && simple_operand_p (rl_arg)
- && simple_operand_p (rr_arg))
- {
- /* Convert (a != 0) || (b != 0) into (a | b) != 0. */
- if (code == TRUTH_OR_EXPR
- && lcode == NE_EXPR && integer_zerop (lr_arg)
- && rcode == NE_EXPR && integer_zerop (rr_arg)
- && TREE_TYPE (ll_arg) == TREE_TYPE (rl_arg)
- && INTEGRAL_TYPE_P (TREE_TYPE (ll_arg)))
- return build2_loc (loc, NE_EXPR, truth_type,
- build2 (BIT_IOR_EXPR, TREE_TYPE (ll_arg),
- ll_arg, rl_arg),
- build_int_cst (TREE_TYPE (ll_arg), 0));
-
- /* Convert (a == 0) && (b == 0) into (a | b) == 0. */
- if (code == TRUTH_AND_EXPR
- && lcode == EQ_EXPR && integer_zerop (lr_arg)
- && rcode == EQ_EXPR && integer_zerop (rr_arg)
- && TREE_TYPE (ll_arg) == TREE_TYPE (rl_arg)
- && INTEGRAL_TYPE_P (TREE_TYPE (ll_arg)))
- return build2_loc (loc, EQ_EXPR, truth_type,
- build2 (BIT_IOR_EXPR, TREE_TYPE (ll_arg),
- ll_arg, rl_arg),
- build_int_cst (TREE_TYPE (ll_arg), 0));
- }
-
/* See if the comparisons can be merged. Then get all the parameters for
each side. */
@@ -8406,13 +8346,12 @@ fold_truth_andor (location_t loc, enum t
if ((tem = fold_truth_andor_1 (loc, code, type, arg0, arg1)) != 0)
return tem;
- if ((BRANCH_COST (optimize_function_for_speed_p (cfun),
- false) >= 2)
- && LOGICAL_OP_NON_SHORT_CIRCUIT
- && (code == TRUTH_AND_EXPR
- || code == TRUTH_ANDIF_EXPR
- || code == TRUTH_OR_EXPR
- || code == TRUTH_ORIF_EXPR))
+ /* Try to optimize TRUTH_AND/OR[IF]_EXPRs to associative TRUTH_AND/OR_EXPRs
+ chains. */
+ if (code == TRUTH_AND_EXPR
+ || code == TRUTH_ANDIF_EXPR
+ || code == TRUTH_OR_EXPR
+ || code == TRUTH_ORIF_EXPR)
{
enum tree_code ncode, icode;
@@ -8440,7 +8379,7 @@ fold_truth_andor (location_t loc, enum t
return fold_build2_loc (loc, icode, type, TREE_OPERAND (arg0, 0),
tem);
}
- /* Same as abouve but for (A AND[-IF] (B AND-IF C)) -> ((A AND B) AND-IF C),
+ /* Same as above but for (A AND[-IF] (B AND-IF C)) -> ((A AND B) AND-IF C),
or (A OR[-IF] (B OR-IF C) -> ((A OR B) OR-IF C). */
else if (TREE_CODE (arg1) == icode
&& simple_operand_p_2 (arg0)
===================================================================
@@ -13,7 +13,7 @@ foo (unsigned int x)
return -1;
}
-/* { dg-final { scan-tree-dump-times "x_\[0-9\]+\\(D\\) != 4" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "x_\[0-9\]+\\(D\\) != 4" 0 "optimized" } } */
/* { dg-final { scan-tree-dump-times "x_\[0-9\]+\\(D\\) != 6" 0 "optimized" } } */
/* { dg-final { scan-tree-dump-times "x_\[0-9\]+\\(D\\) == 2" 0 "optimized" } } */
/* { dg-final { scan-tree-dump-times "x_\[0-9\]+\\(D\\) == 6" 0 "optimized" } } */
===================================================================
@@ -3,7 +3,14 @@
/* This is from PR14052. */
-int f2(int x) { return x == 1 || x == 3 || x == 1; }
+int f2(int x)
+{
+ if (x == 1 || x == 3)
+ return 1;
+ if (x == 1)
+ return 1;
+ return 0;
+}
/* { dg-final { scan-tree-dump "Folding predicate.*== 1 to 0" "vrp1" } } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */
===================================================================
@@ -11,6 +11,7 @@ foo (int a, int b)
return 0;
}
-/* { dg-final { scan-tree-dump-times "if " 2 "gimple" } } */
-/* { dg-final { scan-tree-dump-not " & " "gimple" } } */
+/* { dg-final { scan-tree-dump-times "if " 1 "gimple" } } */
+/* { dg-final { scan-tree-dump-times " & " 1 "gimple" } } */
+/* { dg-final { scan-assembler-times "jne|je" 2 } } */
/* { dg-final { cleanup-tree-dump "gimple" } } */
===================================================================
@@ -13,4 +13,5 @@ foo (int a, int b)
/* { dg-final { scan-tree-dump-times "if " 1 "gimple" } } */
/* { dg-final { scan-tree-dump-times " & " 1 "gimple" } } */
+/* { dg-final { scan-assembler-times "jne|je" 1 } } */
/* { dg-final { cleanup-tree-dump "gimple" } } */
===================================================================
@@ -13,4 +13,5 @@ foo (_Bool a, _Bool b)
/* { dg-final { scan-tree-dump-times "if " 1 "gimple" } } */
/* { dg-final { scan-tree-dump-times " & " 1 "gimple" } } */
+/* { dg-final { scan-assembler-times "jne|je" 1 } } */
/* { dg-final { cleanup-tree-dump "gimple" } } */
===================================================================
@@ -11,6 +11,7 @@ foo (_Bool a, _Bool b)
return 0;
}
-/* { dg-final { scan-tree-dump-times "if " 2 "gimple" } } */
-/* { dg-final { scan-tree-dump-not " & " "gimple" } } */
+/* { dg-final { scan-tree-dump-times "if " 1 "gimple" } } */
+/* { dg-final { scan-tree-dump-times " & " 1 "gimple" } } */
+/* { dg-final { scan-assembler-times "jne|je" 2 } } */
/* { dg-final { cleanup-tree-dump "gimple" } } */