On Fri, Jul 8, 2011 at 11:28 AM, Kai Tietz <ktiet...@googlemail.com> wrote > 2011/7/8 Richard Guenther <richard.guent...@gmail.com>: >> On Thu, Jul 7, 2011 at 6:06 PM, Kai Tietz <ktiet...@googlemail.com> wrote: >>> Hello, >>> >>> This patch - first of series - adds to fold and some helper routines support >>> for one-bit precision bitwise folding and detection. >>> This patch is necessary for - next patch of series - boolification of >>> comparisons. >>> >>> Bootstrapped and regression tested for all standard-languages (plus >>> Ada and Obj-C++) on host x86_64-pc-linux-gnu. >>> >>> Ok for apply? >> >> Factoring out fold_truth_andor to a function should be done separately. >> A patch that does just that is pre-approved. > > Ok I will sent for this a separate patch. But in fact it makes just > sense together with the 1-bit precision bitwise support, too.
No, it makes sense anyway to get rid of that goto. Note _only_ factoring out the function, not changing anything in it. >> Otherwise the patch globs too many changes and lacks reasoning. >> Why do we want to handle all this in fold when the boolification >> happens only after gimplification? > > We still rely on truth/bitwise folding on fold-const. Also we need to > handle this for passes, which are using fold_binary to optimize and > handle boolified operations - like tree-ssa-reassoc, of tree-vect*. > This support in fold-const is necessary when we are preserving casts > from/to boolean, as otherwise we don't fold bitwise-binary with > compares proper anymore. Additionally we have to take care that we > don't enter TRUTH_(AND|OR|XOR) expressions on boolified trees, as > otherwise tree-cfg will barf. Also we need to take care that types of > comparisons and TRUTH_NOT expressions are boolean one, as otherwise > again tree-cfg will detect incompatible types for those expressions. Sounds like many different things for many individual patches. Btw, I'd rather have the tree passes that rely on fold call a gimple specific wrapper where we can add such things (and also use gimple/SSA specific optimizations, like less strict typing), like gimple_fold_binary (....), see also my gimple folding proposal from earlier this year. http://gcc.gnu.org/ml/gcc-patches/2011-03/msg01099.html Richard. >> Thanks, >> Richard. >> >>> Regards, >>> Kai >>> >>> ChangeLog >>> >>> 2011-07-07 Kai Tietz <kti...@redhat.com> >>> >>> * fold-const.c (fold_truth_not_expr): Handle >>> one bit precision bitwise operations. >>> (fold_range_test): Likewise. >>> (fold_truthop): Likewise. >>> (fold_binary_loc): Likewise. >>> (fold_truth_andor): Function replaces truth_andor >>> label. >>> (fold_ternary_loc): Use truth_value_type_p instead >>> of truth_value_p. >>> * gimple.c (canonicalize_cond_expr_cond): Likewise. >>> * gimplify.c (gimple_boolify): Likewise. >>> * tree-ssa-structalias.c (find_func_aliases): Likewise. >>> * tree-ssa-forwprop.c (truth_valued_ssa_name): Likewise. >>> * tree.h (truth_value_type_p): New function. >>> (truth_value_p): Implemented as macro via truth_value_type_p. >>> >>> >>> Index: gcc-head/gcc/fold-const.c >>> =================================================================== >>> --- gcc-head.orig/gcc/fold-const.c >>> +++ gcc-head/gcc/fold-const.c >>> @@ -3074,20 +3074,35 @@ fold_truth_not_expr (location_t loc, tre >>> case INTEGER_CST: >>> return constant_boolean_node (integer_zerop (arg), type); >>> >>> + case BIT_AND_EXPR: >>> + if (integer_onep (TREE_OPERAND (arg, 1))) >>> + return build2_loc (loc, EQ_EXPR, type, arg, build_int_cst (type, >>> 0)); >>> + if (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg, 0))) != 1) >>> + return NULL_TREE; >>> + /* fall through */ >>> case TRUTH_AND_EXPR: >>> loc1 = expr_location_or (TREE_OPERAND (arg, 0), loc); >>> loc2 = expr_location_or (TREE_OPERAND (arg, 1), loc); >>> - return build2_loc (loc, TRUTH_OR_EXPR, type, >>> + return build2_loc (loc, (code == BIT_AND_EXPR ? BIT_IOR_EXPR >>> + : TRUTH_OR_EXPR), type, >>> invert_truthvalue_loc (loc1, TREE_OPERAND (arg, 0)), >>> invert_truthvalue_loc (loc2, TREE_OPERAND (arg, >>> 1))); >>> >>> + case BIT_IOR_EXPR: >>> + if (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg, 0))) != 1) >>> + return NULL_TREE; >>> + /* fall through. */ >>> case TRUTH_OR_EXPR: >>> loc1 = expr_location_or (TREE_OPERAND (arg, 0), loc); >>> loc2 = expr_location_or (TREE_OPERAND (arg, 1), loc); >>> - return build2_loc (loc, TRUTH_AND_EXPR, type, >>> + return build2_loc (loc, (code == BIT_IOR_EXPR ? BIT_AND_EXPR >>> + : TRUTH_AND_EXPR), type, >>> invert_truthvalue_loc (loc1, TREE_OPERAND (arg, 0)), >>> invert_truthvalue_loc (loc2, TREE_OPERAND (arg, >>> 1))); >>> - >>> + case BIT_XOR_EXPR: >>> + if (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg, 0))) != 1) >>> + return NULL_TREE; >>> + /* fall through. */ >>> case TRUTH_XOR_EXPR: >>> /* Here we can invert either operand. We invert the first operand >>> unless the second operand is a TRUTH_NOT_EXPR in which case our >>> @@ -3095,10 +3110,14 @@ fold_truth_not_expr (location_t loc, tre >>> negation of the second operand. */ >>> >>> if (TREE_CODE (TREE_OPERAND (arg, 1)) == TRUTH_NOT_EXPR) >>> - return build2_loc (loc, TRUTH_XOR_EXPR, type, TREE_OPERAND (arg, 0), >>> + return build2_loc (loc, code, type, TREE_OPERAND (arg, 0), >>> + TREE_OPERAND (TREE_OPERAND (arg, 1), 0)); >>> + else if (TREE_CODE (TREE_OPERAND (arg, 1)) == BIT_NOT_EXPR >>> + && TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg, 1))) == 1) >>> + return build2_loc (loc, code, type, TREE_OPERAND (arg, 0), >>> TREE_OPERAND (TREE_OPERAND (arg, 1), 0)); >>> else >>> - return build2_loc (loc, TRUTH_XOR_EXPR, type, >>> + return build2_loc (loc, code, type, >>> invert_truthvalue_loc (loc, TREE_OPERAND (arg, >>> 0)), >>> TREE_OPERAND (arg, 1)); >>> >>> @@ -3116,6 +3135,11 @@ fold_truth_not_expr (location_t loc, tre >>> invert_truthvalue_loc (loc1, TREE_OPERAND (arg, 0)), >>> invert_truthvalue_loc (loc2, TREE_OPERAND (arg, >>> 1))); >>> >>> + >>> + case BIT_NOT_EXPR: >>> + if (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg, 0))) != 1) >>> + return NULL_TREE; >>> + /* fall through */ >>> case TRUTH_NOT_EXPR: >>> return TREE_OPERAND (arg, 0); >>> >>> @@ -3158,11 +3182,6 @@ fold_truth_not_expr (location_t loc, tre >>> return build1_loc (loc, TREE_CODE (arg), type, >>> invert_truthvalue_loc (loc1, TREE_OPERAND (arg, >>> 0))); >>> >>> - case BIT_AND_EXPR: >>> - if (!integer_onep (TREE_OPERAND (arg, 1))) >>> - return NULL_TREE; >>> - return build2_loc (loc, EQ_EXPR, type, arg, build_int_cst (type, 0)); >>> - >>> case SAVE_EXPR: >>> return build1_loc (loc, TRUTH_NOT_EXPR, type, arg); >>> >>> @@ -4800,7 +4819,7 @@ fold_range_test (location_t loc, enum tr >>> tree op0, tree op1) >>> { >>> int or_op = (code == TRUTH_ORIF_EXPR >>> - || code == TRUTH_OR_EXPR); >>> + || code == TRUTH_OR_EXPR || code == BIT_IOR_EXPR); >>> int in0_p, in1_p, in_p; >>> tree low0, low1, low, high0, high1, high; >>> bool strict_overflow_p = false; >>> @@ -5099,8 +5118,9 @@ fold_truthop (location_t loc, enum tree_ >>> } >>> } >>> >>> - code = ((code == TRUTH_AND_EXPR || code == TRUTH_ANDIF_EXPR) >>> - ? TRUTH_AND_EXPR : TRUTH_OR_EXPR); >>> + if (code != BIT_AND_EXPR && code != BIT_IOR_EXPR) >>> + 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 >>> @@ -5115,7 +5135,7 @@ fold_truthop (location_t loc, enum tree_ >>> && simple_operand_p (rr_arg)) >>> { >>> /* Convert (a != 0) || (b != 0) into (a | b) != 0. */ >>> - if (code == TRUTH_OR_EXPR >>> + if ((code == TRUTH_OR_EXPR || code == BIT_IOR_EXPR) >>> && lcode == NE_EXPR && integer_zerop (lr_arg) >>> && rcode == NE_EXPR && integer_zerop (rr_arg) >>> && TREE_TYPE (ll_arg) == TREE_TYPE (rl_arg) >>> @@ -5126,7 +5146,7 @@ fold_truthop (location_t loc, enum tree_ >>> build_int_cst (TREE_TYPE (ll_arg), 0)); >>> >>> /* Convert (a == 0) && (b == 0) into (a | b) == 0. */ >>> - if (code == TRUTH_AND_EXPR >>> + if ((code == TRUTH_AND_EXPR || code == BIT_AND_EXPR) >>> && lcode == EQ_EXPR && integer_zerop (lr_arg) >>> && rcode == EQ_EXPR && integer_zerop (rr_arg) >>> && TREE_TYPE (ll_arg) == TREE_TYPE (rl_arg) >>> @@ -5190,7 +5210,8 @@ fold_truthop (location_t loc, enum tree_ >>> fail. However, we can convert a one-bit comparison against zero into >>> the opposite comparison against that bit being set in the field. */ >>> >>> - wanted_code = (code == TRUTH_AND_EXPR ? EQ_EXPR : NE_EXPR); >>> + wanted_code = ((code == TRUTH_AND_EXPR || code == BIT_AND_EXPR) >>> + ? EQ_EXPR : NE_EXPR); >>> if (lcode != wanted_code) >>> { >>> if (l_const && integer_zerop (l_const) && integer_pow2p (ll_mask)) >>> @@ -9324,6 +9345,105 @@ get_pointer_modulus_and_residue (tree ex >>> return 1; >>> } >>> >>> +/* Fold a binary bitwise/truth expression of code CODE and type TYPE >>> with operands >>> + OP0 and OP1. LOC is the location of the resulting expression. >>> + ARG0 and ARG1 are the NOP_STRIPed results of OP0 and OP1. >>> + Return the folded expression if folding is successful. Otherwise, >>> + return NULL_TREE. */ >>> + >>> +static tree >>> +fold_truth_andor (location_t loc, enum tree_code code, tree type, >>> + tree arg0, tree arg1, tree op0, tree op1) >>> +{ >>> + tree tem; >>> + >>> + /* We only do these simplifications if we are optimizing. */ >>> + if (!optimize) >>> + return NULL_TREE; >>> + /* If code is BIT_AND_EXPR or BIT_IOR_EXPR, type precision has to be >>> one. */ >>> + if ((code == BIT_AND_EXPR || code == BIT_IOR_EXPR) >>> + && (!INTEGRAL_TYPE_P (type) || TYPE_PRECISION (type) != 1)) >>> + return NULL_TREE; >>> + >>> + /* Check for things like (A || B) && (A || C). We can convert this >>> + to A || (B && C). Note that either operator can be any of the four >>> + truth and/or operations and the transformation will still be >>> + valid. Also note that we only care about order for the >>> + ANDIF and ORIF operators. If B contains side effects, this >>> + might change the truth-value of A. */ >>> + if (TREE_CODE (arg0) == TREE_CODE (arg1) >>> + && (TREE_CODE (arg0) == TRUTH_ANDIF_EXPR >>> + || TREE_CODE (arg0) == TRUTH_ORIF_EXPR >>> + || TREE_CODE (arg0) == BIT_AND_EXPR >>> + || TREE_CODE (arg0) == BIT_IOR_EXPR >>> + || TREE_CODE (arg0) == TRUTH_AND_EXPR >>> + || TREE_CODE (arg0) == TRUTH_OR_EXPR) >>> + && ! TREE_SIDE_EFFECTS (TREE_OPERAND (arg0, 1))) >>> + { >>> + tree a00 = TREE_OPERAND (arg0, 0); >>> + tree a01 = TREE_OPERAND (arg0, 1); >>> + tree a10 = TREE_OPERAND (arg1, 0); >>> + tree a11 = TREE_OPERAND (arg1, 1); >>> + int commutative = ((TREE_CODE (arg0) == TRUTH_OR_EXPR >>> + || TREE_CODE (arg0) == TRUTH_AND_EXPR >>> + || TREE_CODE (arg0) == BIT_AND_EXPR) >>> + && (code == TRUTH_AND_EXPR >>> + || code == TRUTH_OR_EXPR >>> + || code == BIT_IOR_EXPR)); >>> + >>> + if (operand_equal_p (a00, a10, 0)) >>> + return fold_build2_loc (loc, TREE_CODE (arg0), type, a00, >>> + fold_build2_loc (loc, code, type, a01, a11)); >>> + else if (commutative && operand_equal_p (a00, a11, 0)) >>> + return fold_build2_loc (loc, TREE_CODE (arg0), type, a00, >>> + fold_build2_loc (loc, code, type, a01, a10)); >>> + else if (commutative && operand_equal_p (a01, a10, 0)) >>> + return fold_build2_loc (loc, TREE_CODE (arg0), type, a01, >>> + fold_build2_loc (loc, code, type, a00, a11)); >>> + >>> + /* This case if tricky because we must either have commutative >>> + operators or else A10 must not have side-effects. */ >>> + >>> + else if ((commutative || ! TREE_SIDE_EFFECTS (a10)) >>> + && operand_equal_p (a01, a11, 0)) >>> + return fold_build2_loc (loc, TREE_CODE (arg0), type, >>> + fold_build2_loc (loc, code, type, a00, a10), >>> + a01); >>> + } >>> + >>> + /* See if we can build a range comparison. */ >>> + if (0 != (tem = fold_range_test (loc, code, type, op0, op1))) >>> + return tem; >>> + >>> + if ((code == TRUTH_ANDIF_EXPR && TREE_CODE (arg0) == TRUTH_ORIF_EXPR) >>> + || (code == TRUTH_ORIF_EXPR && TREE_CODE (arg0) == TRUTH_ANDIF_EXPR)) >>> + { >>> + tem = merge_truthop_with_opposite_arm (loc, arg0, arg1, true); >>> + if (tem) >>> + return fold_build2_loc (loc, code, type, tem, arg1); >>> + } >>> + >>> + if ((code == TRUTH_ANDIF_EXPR && TREE_CODE (arg1) == TRUTH_ORIF_EXPR) >>> + || (code == TRUTH_ORIF_EXPR && TREE_CODE (arg1) == TRUTH_ANDIF_EXPR)) >>> + { >>> + tem = merge_truthop_with_opposite_arm (loc, arg1, arg0, false); >>> + if (tem) >>> + return fold_build2_loc (loc, code, type, arg0, tem); >>> + } >>> + >>> + /* Check for the possibility of merging component references. If our >>> + lhs is another similar operation, try to merge its rhs with our >>> + rhs. Then try to merge our lhs and rhs. */ >>> + if (TREE_CODE (arg0) == code >>> + && 0 != (tem = fold_truthop (loc, code, type, >>> + TREE_OPERAND (arg0, 1), arg1))) >>> + return fold_build2_loc (loc, code, type, TREE_OPERAND (arg0, 0), tem); >>> + >>> + if ((tem = fold_truthop (loc, code, type, arg0, arg1)) != 0) >>> + return tem; >>> + >>> + return NULL_TREE; >>> +} >>> >>> /* Fold a binary expression of code CODE and type TYPE with operands >>> OP0 and OP1. LOC is the location of the resulting expression. >>> @@ -9424,21 +9544,42 @@ fold_binary_loc (location_t loc, >>> >>> if ((code == BIT_AND_EXPR || code == BIT_IOR_EXPR >>> || code == EQ_EXPR || code == NE_EXPR) >>> - && ((truth_value_p (TREE_CODE (arg0)) >>> - && (truth_value_p (TREE_CODE (arg1)) >>> + && (!INTEGRAL_TYPE_P (type) || TYPE_PRECISION (type) != 1) >>> + && ((truth_value_type_p (TREE_CODE (arg0), TREE_TYPE (arg0)) >>> + && (truth_value_type_p (TREE_CODE (arg1), TREE_TYPE (arg1)) >>> || (TREE_CODE (arg1) == BIT_AND_EXPR >>> && integer_onep (TREE_OPERAND (arg1, 1))))) >>> - || (truth_value_p (TREE_CODE (arg1)) >>> - && (truth_value_p (TREE_CODE (arg0)) >>> + || (truth_value_type_p (TREE_CODE (arg1), TREE_TYPE (arg1)) >>> + && (truth_value_type_p (TREE_CODE (arg0), TREE_TYPE (arg0)) >>> || (TREE_CODE (arg0) == BIT_AND_EXPR >>> && integer_onep (TREE_OPERAND (arg0, 1))))))) >>> { >>> tem = fold_build2_loc (loc, code == BIT_AND_EXPR ? TRUTH_AND_EXPR >>> - : code == BIT_IOR_EXPR ? TRUTH_OR_EXPR >>> - : TRUTH_XOR_EXPR, >>> - boolean_type_node, >>> - fold_convert_loc (loc, boolean_type_node, arg0), >>> - fold_convert_loc (loc, boolean_type_node, arg1)); >>> + : code == BIT_IOR_EXPR ? TRUTH_OR_EXPR >>> + : TRUTH_XOR_EXPR, >>> + boolean_type_node, >>> + fold_convert_loc (loc, boolean_type_node, arg0), >>> + fold_convert_loc (loc, boolean_type_node, arg1)); >>> + >>> + if (code == EQ_EXPR) >>> + tem = invert_truthvalue_loc (loc, tem); >>> + >>> + return fold_convert_loc (loc, type, tem); >>> + } >>> + if ((code == EQ_EXPR || code == NE_EXPR) >>> + && ((truth_value_type_p (TREE_CODE (arg0), TREE_TYPE (arg0)) >>> + && (truth_value_type_p (TREE_CODE (arg1), TREE_TYPE (arg1)) >>> + || (TREE_CODE (arg1) == BIT_AND_EXPR >>> + && integer_onep (TREE_OPERAND (arg1, 1))))) >>> + || (truth_value_type_p (TREE_CODE (arg1), TREE_TYPE (arg1)) >>> + && (truth_value_type_p (TREE_CODE (arg0), TREE_TYPE (arg0)) >>> + || (TREE_CODE (arg0) == BIT_AND_EXPR >>> + && integer_onep (TREE_OPERAND (arg0, 1))))))) >>> + { >>> + tem = fold_build2_loc (loc, BIT_XOR_EXPR, >>> + boolean_type_node, >>> + fold_convert_loc (loc, boolean_type_node, arg0), >>> + fold_convert_loc (loc, boolean_type_node, arg1)); >>> >>> if (code == EQ_EXPR) >>> tem = invert_truthvalue_loc (loc, tem); >>> @@ -10597,6 +10738,57 @@ fold_binary_loc (location_t loc, >>> if (operand_equal_p (arg0, arg1, 0)) >>> return non_lvalue_loc (loc, fold_convert_loc (loc, type, arg0)); >>> >>> + if (TYPE_PRECISION (type) == 1 && INTEGRAL_TYPE_P (type)) >>> + { >>> + /* If either arg is constant zero, drop it. */ >>> + if (TREE_CODE (arg0) == INTEGER_CST && integer_zerop (arg0)) >>> + return non_lvalue_loc (loc, fold_convert_loc (loc, type, arg1)); >>> + if (TREE_CODE (arg1) == INTEGER_CST && integer_zerop (arg1)) >>> + return non_lvalue_loc (loc, fold_convert_loc (loc, type, arg0)); >>> + /* If second arg is constant true, result is true, but we must >>> + evaluate first arg. */ >>> + if (TREE_CODE (arg1) == INTEGER_CST && ! integer_zerop (arg1)) >>> + return omit_one_operand_loc (loc, type, arg1, arg0); >>> + if (TREE_CODE (arg0) == INTEGER_CST && ! integer_zerop (arg0)) >>> + return omit_one_operand_loc (loc, type, arg0, arg1); >>> + >>> + /* !X | X is always true. */ >>> + if ((TREE_CODE (arg0) == TRUTH_NOT_EXPR >>> + || TREE_CODE (arg0) == BIT_NOT_EXPR) >>> + && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)) >>> + return omit_one_operand_loc (loc, type, integer_one_node, arg1); >>> + /* X | !X is always true. */ >>> + if ((TREE_CODE (arg1) == TRUTH_NOT_EXPR >>> + || TREE_CODE (arg1) == BIT_NOT_EXPR) >>> + && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0)) >>> + return omit_one_operand_loc (loc, type, integer_one_node, arg0); >>> + >>> + /* (X & !Y) | (!X & Y) is X ^ Y */ >>> + if (TREE_CODE (arg0) == BIT_AND_EXPR >>> + && TREE_CODE (arg1) == BIT_AND_EXPR) >>> + { >>> + tree a0, a1, l0, l1, n0, n1; >>> + >>> + a0 = fold_convert_loc (loc, type, TREE_OPERAND (arg1, 0)); >>> + a1 = fold_convert_loc (loc, type, TREE_OPERAND (arg1, 1)); >>> + >>> + l0 = fold_convert_loc (loc, type, TREE_OPERAND (arg0, 0)); >>> + l1 = fold_convert_loc (loc, type, TREE_OPERAND (arg0, 1)); >>> + >>> + n0 = fold_build1_loc (loc, TRUTH_NOT_EXPR, type, l0); >>> + n1 = fold_build1_loc (loc, TRUTH_NOT_EXPR, type, l1); >>> + >>> + if ((operand_equal_p (n0, a0, 0) >>> + && operand_equal_p (n1, a1, 0)) >>> + || (operand_equal_p (n0, a1, 0) >>> + && operand_equal_p (n1, a0, 0))) >>> + return fold_build2_loc (loc, BIT_XOR_EXPR, type, l0, n1); >>> + } >>> + tem = fold_truth_andor (loc, code, type, arg0, arg1, op0, op1); >>> + if (tem) >>> + return tem; >>> + } >>> + >>> /* ~X | X is -1. */ >>> if (TREE_CODE (arg0) == BIT_NOT_EXPR >>> && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)) >>> @@ -10758,6 +10950,24 @@ fold_binary_loc (location_t loc, >>> if (operand_equal_p (arg0, arg1, 0)) >>> return omit_one_operand_loc (loc, type, integer_zero_node, arg0); >>> >>> + if (TYPE_PRECISION (type) == 1 && INTEGRAL_TYPE_P (type)) >>> + { >>> + /* If the second arg is constant true, this is a logical >>> inversion. */ >>> + if (integer_onep (arg1)) >>> + { >>> + tem = invert_truthvalue_loc (loc, arg0); >>> + return non_lvalue_loc (loc, fold_convert_loc (loc, type, >>> tem)); >>> + } >>> + /* !X ^ X is always true. */ >>> + if (TREE_CODE (arg0) == TRUTH_NOT_EXPR >>> + && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)) >>> + return omit_one_operand_loc (loc, type, integer_one_node, arg1); >>> + /* X ^ !X is always true. */ >>> + if (TREE_CODE (arg1) == TRUTH_NOT_EXPR >>> + && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0)) >>> + return omit_one_operand_loc (loc, type, integer_one_node, arg0); >>> + } >>> + >>> /* ~X ^ X is -1. */ >>> if (TREE_CODE (arg0) == BIT_NOT_EXPR >>> && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)) >>> @@ -10918,6 +11128,61 @@ fold_binary_loc (location_t loc, >>> return omit_one_operand_loc (loc, type, arg1, arg0); >>> if (operand_equal_p (arg0, arg1, 0)) >>> return non_lvalue_loc (loc, fold_convert_loc (loc, type, arg0)); >>> + /* Note that the operands of this must be ints >>> + and their values must be 0 or 1. >>> + ("true" is a fixed value perhaps depending on the language.) */ >>> + /* If first arg is constant zero, return it. */ >>> + if (integer_zerop (arg0)) >>> + return fold_convert_loc (loc, type, arg0); >>> + >>> + if (TYPE_PRECISION (type) == 1 && INTEGRAL_TYPE_P (type)) >>> + { >>> + /* If either arg is constant true, drop it. */ >>> + if (TREE_CODE (arg0) == INTEGER_CST && ! integer_zerop (arg0)) >>> + return non_lvalue_loc (loc, fold_convert_loc (loc, type, arg1)); >>> + if (TREE_CODE (arg1) == INTEGER_CST && ! integer_zerop (arg1) >>> + /* Preserve sequence points. */ >>> + && (code != TRUTH_ANDIF_EXPR || ! TREE_SIDE_EFFECTS (arg0))) >>> + return non_lvalue_loc (loc, fold_convert_loc (loc, type, arg0)); >>> + /* If second arg is constant zero, result is zero, but first arg >>> + must be evaluated. */ >>> + if (integer_zerop (arg1)) >>> + return omit_one_operand_loc (loc, type, arg1, arg0); >>> + /* Likewise for first arg, but note that only the TRUTH_AND_EXPR >>> + case will be handled here. */ >>> + if (integer_zerop (arg0)) >>> + return omit_one_operand_loc (loc, type, arg0, arg1); >>> + >>> + /* !X && X is always false. */ >>> + if (TREE_CODE (arg0) == TRUTH_NOT_EXPR >>> + && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)) >>> + return omit_one_operand_loc (loc, type, integer_zero_node, >>> arg1); >>> + /* X & !X is always false. */ >>> + if (TREE_CODE (arg1) == TRUTH_NOT_EXPR >>> + && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0)) >>> + return omit_one_operand_loc (loc, type, integer_zero_node, >>> arg0); >>> + >>> + /* A < X & A + 1 > Y ==> A < X & A >= Y. Normally A + 1 > Y >>> + means A >= Y & A != MAX, but in this case we know that >>> + A < X <= MAX. */ >>> + >>> + if (!TREE_SIDE_EFFECTS (arg0) >>> + && !TREE_SIDE_EFFECTS (arg1)) >>> + { >>> + tem = fold_to_nonsharp_ineq_using_bound (loc, arg0, arg1); >>> + if (tem && !operand_equal_p (tem, arg0, 0)) >>> + return fold_build2_loc (loc, code, type, tem, arg1); >>> + >>> + tem = fold_to_nonsharp_ineq_using_bound (loc, arg1, arg0); >>> + if (tem && !operand_equal_p (tem, arg1, 0)) >>> + return fold_build2_loc (loc, code, type, arg0, tem); >>> + } >>> + >>> + tem = fold_truth_andor (loc, code, type, arg0, arg1, op0, op1); >>> + if (tem) >>> + return tem; >>> + >>> + } >>> >>> /* ~X & X, (X == 0) & X, and !X & X are always zero. */ >>> if ((TREE_CODE (arg0) == BIT_NOT_EXPR >>> @@ -12006,86 +12271,11 @@ fold_binary_loc (location_t loc, >>> return fold_build2_loc (loc, code, type, arg0, tem); >>> } >>> >>> - truth_andor: >>> - /* We only do these simplifications if we are optimizing. */ >>> - if (!optimize) >>> - return NULL_TREE; >>> - >>> - /* Check for things like (A || B) && (A || C). We can convert this >>> - to A || (B && C). Note that either operator can be any of the four >>> - truth and/or operations and the transformation will still be >>> - valid. Also note that we only care about order for the >>> - ANDIF and ORIF operators. If B contains side effects, this >>> - might change the truth-value of A. */ >>> - if (TREE_CODE (arg0) == TREE_CODE (arg1) >>> - && (TREE_CODE (arg0) == TRUTH_ANDIF_EXPR >>> - || TREE_CODE (arg0) == TRUTH_ORIF_EXPR >>> - || TREE_CODE (arg0) == TRUTH_AND_EXPR >>> - || TREE_CODE (arg0) == TRUTH_OR_EXPR) >>> - && ! TREE_SIDE_EFFECTS (TREE_OPERAND (arg0, 1))) >>> - { >>> - tree a00 = TREE_OPERAND (arg0, 0); >>> - tree a01 = TREE_OPERAND (arg0, 1); >>> - tree a10 = TREE_OPERAND (arg1, 0); >>> - tree a11 = TREE_OPERAND (arg1, 1); >>> - int commutative = ((TREE_CODE (arg0) == TRUTH_OR_EXPR >>> - || TREE_CODE (arg0) == TRUTH_AND_EXPR) >>> - && (code == TRUTH_AND_EXPR >>> - || code == TRUTH_OR_EXPR)); >>> - >>> - if (operand_equal_p (a00, a10, 0)) >>> - return fold_build2_loc (loc, TREE_CODE (arg0), type, a00, >>> - fold_build2_loc (loc, code, type, a01, >>> a11)); >>> - else if (commutative && operand_equal_p (a00, a11, 0)) >>> - return fold_build2_loc (loc, TREE_CODE (arg0), type, a00, >>> - fold_build2_loc (loc, code, type, a01, >>> a10)); >>> - else if (commutative && operand_equal_p (a01, a10, 0)) >>> - return fold_build2_loc (loc, TREE_CODE (arg0), type, a01, >>> - fold_build2_loc (loc, code, type, a00, >>> a11)); >>> - >>> - /* This case if tricky because we must either have commutative >>> - operators or else A10 must not have side-effects. */ >>> - >>> - else if ((commutative || ! TREE_SIDE_EFFECTS (a10)) >>> - && operand_equal_p (a01, a11, 0)) >>> - return fold_build2_loc (loc, TREE_CODE (arg0), type, >>> - fold_build2_loc (loc, code, type, a00, a10), >>> - a01); >>> - } >>> - >>> - /* See if we can build a range comparison. */ >>> - if (0 != (tem = fold_range_test (loc, code, type, op0, op1))) >>> - return tem; >>> - >>> - if ((code == TRUTH_ANDIF_EXPR && TREE_CODE (arg0) == TRUTH_ORIF_EXPR) >>> - || (code == TRUTH_ORIF_EXPR && TREE_CODE (arg0) == >>> TRUTH_ANDIF_EXPR)) >>> - { >>> - tem = merge_truthop_with_opposite_arm (loc, arg0, arg1, true); >>> - if (tem) >>> - return fold_build2_loc (loc, code, type, tem, arg1); >>> - } >>> - >>> - if ((code == TRUTH_ANDIF_EXPR && TREE_CODE (arg1) == TRUTH_ORIF_EXPR) >>> - || (code == TRUTH_ORIF_EXPR && TREE_CODE (arg1) == >>> TRUTH_ANDIF_EXPR)) >>> - { >>> - tem = merge_truthop_with_opposite_arm (loc, arg1, arg0, false); >>> - if (tem) >>> - return fold_build2_loc (loc, code, type, arg0, tem); >>> - } >>> - >>> - /* Check for the possibility of merging component references. If our >>> - lhs is another similar operation, try to merge its rhs with our >>> - rhs. Then try to merge our lhs and rhs. */ >>> - if (TREE_CODE (arg0) == code >>> - && 0 != (tem = fold_truthop (loc, code, type, >>> - TREE_OPERAND (arg0, 1), arg1))) >>> - return fold_build2_loc (loc, code, type, TREE_OPERAND (arg0, 0), >>> tem); >>> - >>> - if ((tem = fold_truthop (loc, code, type, arg0, arg1)) != 0) >>> - return tem; >>> + tem = fold_truth_andor (loc, code, type, arg0, arg1, op0, op1); >>> + if (tem) >>> + return tem; >>> >>> return NULL_TREE; >>> - >>> case TRUTH_ORIF_EXPR: >>> /* Note that the operands of this must be ints >>> and their values must be 0 or true. >>> @@ -12140,7 +12330,11 @@ fold_binary_loc (location_t loc, >>> && operand_equal_p (n1, a0, 0))) >>> return fold_build2_loc (loc, TRUTH_XOR_EXPR, type, l0, n1); >>> } >>> - goto truth_andor; >>> + tem = fold_truth_andor (loc, code, type, arg0, arg1, op0, op1); >>> + if (tem) >>> + return tem; >>> + >>> + return NULL_TREE; >>> >>> case TRUTH_XOR_EXPR: >>> /* If the second arg is constant zero, drop it. */ >>> @@ -13401,7 +13595,7 @@ fold_ternary_loc (location_t loc, enum t >>> >>> /* 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)) >>> + if (truth_value_type_p (TREE_CODE (arg0), TREE_TYPE (arg0)) >>> && tree_swap_operands_p (op1, op2, false)) >>> { >>> location_t loc0 = expr_location_or (arg0, loc); >>> @@ -13427,7 +13621,7 @@ fold_ternary_loc (location_t loc, enum t >>> over COND_EXPR in cases such as floating point comparisons. */ >>> if (integer_zerop (op1) >>> && integer_onep (op2) >>> - && truth_value_p (TREE_CODE (arg0))) >>> + && truth_value_type_p (TREE_CODE (arg0), TREE_TYPE (arg0))) >>> return pedantic_non_lvalue_loc (loc, >>> fold_convert_loc (loc, type, >>> invert_truthvalue_loc (loc, >>> Index: gcc-head/gcc/gimple.c >>> =================================================================== >>> --- gcc-head.orig/gcc/gimple.c >>> +++ gcc-head/gcc/gimple.c >>> @@ -3160,7 +3160,8 @@ canonicalize_cond_expr_cond (tree t) >>> { >>> /* Strip conversions around boolean operations. */ >>> if (CONVERT_EXPR_P (t) >>> - && truth_value_p (TREE_CODE (TREE_OPERAND (t, 0)))) >>> + && truth_value_type_p (TREE_CODE (TREE_OPERAND (t, 0)), >>> + TREE_TYPE (TREE_OPERAND (t, 0)))) >>> t = TREE_OPERAND (t, 0); >>> >>> /* For !x use x == 0. */ >>> Index: gcc-head/gcc/gimplify.c >>> =================================================================== >>> --- gcc-head.orig/gcc/gimplify.c >>> +++ gcc-head/gcc/gimplify.c >>> @@ -2837,7 +2837,7 @@ gimple_boolify (tree expr) >>> if (TREE_CODE (arg) == NOP_EXPR >>> && TREE_TYPE (arg) == TREE_TYPE (call)) >>> arg = TREE_OPERAND (arg, 0); >>> - if (truth_value_p (TREE_CODE (arg))) >>> + if (truth_value_type_p (TREE_CODE (arg), TREE_TYPE (arg))) >>> { >>> arg = gimple_boolify (arg); >>> CALL_EXPR_ARG (call, 0) >>> Index: gcc-head/gcc/tree-ssa-structalias.c >>> =================================================================== >>> --- gcc-head.orig/gcc/tree-ssa-structalias.c >>> +++ gcc-head/gcc/tree-ssa-structalias.c >>> @@ -4416,7 +4416,8 @@ find_func_aliases (gimple origt) >>> && !POINTER_TYPE_P (TREE_TYPE (rhsop)))) >>> || gimple_assign_single_p (t)) >>> get_constraint_for_rhs (rhsop, &rhsc); >>> - else if (truth_value_p (code)) >>> + else if (truth_value_type_p (code, >>> + TREE_TYPE (lhsop))) >>> /* Truth value results are not pointer (parts). Or at least >>> very very unreasonable obfuscation of a part. */ >>> ; >>> Index: gcc-head/gcc/tree.h >>> =================================================================== >>> --- gcc-head.orig/gcc/tree.h >>> +++ gcc-head/gcc/tree.h >>> @@ -5309,13 +5309,22 @@ extern tree combine_comparisons (locatio >>> extern void debug_fold_checksum (const_tree); >>> >>> /* Return nonzero if CODE is a tree code that represents a truth value. */ >>> +#define truth_value_p(CODE) truth_value_type_p ((CODE), NULL_TREE) >>> + >>> +/* Return nonzero if CODE is a tree code that represents a truth value. >>> + If TYPE is an integral type, unsigned, and has precision of one, then >>> + additionally return for bitwise-binary and bitwise-invert nonzero. */ >>> static inline bool >>> -truth_value_p (enum tree_code code) >>> +truth_value_type_p (enum tree_code code, tree type) >>> { >>> return (TREE_CODE_CLASS (code) == tcc_comparison >>> || code == TRUTH_AND_EXPR || code == TRUTH_ANDIF_EXPR >>> || code == TRUTH_OR_EXPR || code == TRUTH_ORIF_EXPR >>> - || code == TRUTH_XOR_EXPR || code == TRUTH_NOT_EXPR); >>> + || code == TRUTH_XOR_EXPR || code == TRUTH_NOT_EXPR >>> + || ((code == BIT_AND_EXPR || code == BIT_IOR_EXPR >>> + || code == BIT_XOR_EXPR || code == BIT_NOT_EXPR) >>> + && type && INTEGRAL_TYPE_P (type) >>> + && TYPE_PRECISION (type) == 1 && TYPE_UNSIGNED (type))); >>> } >>> >>> >>> Index: gcc-head/gcc/tree-ssa-forwprop.c >>> =================================================================== >>> --- gcc-head.orig/gcc/tree-ssa-forwprop.c >>> +++ gcc-head/gcc/tree-ssa-forwprop.c >>> @@ -1668,7 +1668,7 @@ truth_valued_ssa_name (tree name) >>> return true; >>> def = SSA_NAME_DEF_STMT (name); >>> if (is_gimple_assign (def)) >>> - return truth_value_p (gimple_assign_rhs_code (def)); >>> + return truth_value_type_p (gimple_assign_rhs_code (def), type); >>> return false; >>> } >>> >> >