[backport proposed and approved but not yet applied patch for PR58088 ] List-Archive: From: "Kyrylo Tkachov" Subject: [PATCH][tree-optimization] Fix PR58088 Date: Wed, 7 Aug 2013 14:21:32 +0100 Hi all, In PR58088 the constant folder goes into an infinite recursion and runs out of stack space because of two conflicting optimisations: (X * C1) & C2 plays dirty when nested inside an IOR expression like so: ((X * C1) & C2) | C4. One can undo the other leading to an infinite recursion. Thanks to Marek for finding the IOR case. This patch fixes that by checking in the IOR case that the change to C2 will not conflict with the AND case transformation. Example testcases in the PR on bugzilla. This issue is present in 4.8.1 as well as trunk. However, I think 4.8 uses a different API for double_int, so this patch will need to be reworked for 4.8. In the meantime, Ok for trunk? Bootstrapped on x86_64-linux-gnu and tested arm-none-eabi on qemu. List-Archive: From: "Kyrylo Tkachov" Subject: RE: [PATCH][tree-optimization] Fix PR58088 Date: Wed, 7 Aug 2013 15:41:27 +0100 > This issue is present in 4.8.1 as well as trunk. However, I think 4.8 > uses a different API for double_int, so this patch will need to be reworked for > 4.8. Actually, I was confused. This patch applies to 4.8.1 as well and fixes the issue. Passes bootstrap on x86_64-linux-gnu and testing arm-none-eabi. Therefore, OK to backport to 4.8 as well? List-Archive: From: "Kyrylo Tkachov" Subject: RE: [PATCH][tree-optimization] Fix PR58088 Date: Thu, 8 Aug 2013 09:50:29 +0100 Also, the ChangeLog entries should be: 2013-08-08 Kyrylo Tkachov PR tree-optimization/58088 * gcc/fold-const.c (mask_with_trailing_zeros): New function. (fold_binary_loc): Make sure we don't recurse infinitely when the X in (X & C1) | C2 is a tree of the form (Y * K1) & K2. Use mask_with_trailing_zeros where appropriate. 2013-08-08 Kyrylo Tkachov PR tree-optimization/58088 * gcc.c-torture/compile/pr58088.c: New test. --- gcc-4.8.1/gcc/fold-const.c.~1~ 2013-05-17 10:52:36.000000000 +0200 +++ gcc-4.8.1/gcc/fold-const.c 2013-08-10 11:55:54.066202706 +0200 @@ -9851,6 +9851,24 @@ exact_inverse (tree type, tree cst) } } +/* Mask out the tz least significant bits of X of type TYPE where + tz is the number of trailing zeros in Y. */ +static double_int +mask_with_trailing_zeros (tree type, double_int x, double_int y) +{ + int tz = y.trailing_zeros (); + + if (tz > 0) + { + double_int mask; + + mask = ~double_int::mask (tz); + mask = mask.ext (TYPE_PRECISION (type), TYPE_UNSIGNED (type)); + return mask & x; + } + return x; +} + /* Fold a binary expression of code CODE and type TYPE with operands OP0 and OP1. LOC is the location of the resulting expression. Return the folded expression if folding is successful. Otherwise, @@ -11175,6 +11193,8 @@ fold_binary_loc (location_t loc, { double_int c1, c2, c3, msk; int width = TYPE_PRECISION (type), w; + bool valid = true; + c1 = tree_to_double_int (TREE_OPERAND (arg0, 1)); c2 = tree_to_double_int (arg1); @@ -11209,7 +11229,21 @@ fold_binary_loc (location_t loc, break; } } - if (c3 != c1) + /* If X is a tree of the form (Y * K1) & K2, this might conflict + with that optimization from the BIT_AND_EXPR optimizations. + This could end up in an infinite recursion. */ + if (TREE_CODE (TREE_OPERAND (arg0, 0)) == MULT_EXPR + && TREE_CODE (TREE_OPERAND (TREE_OPERAND (arg0, 0), 1)) + == INTEGER_CST) + { + tree t = TREE_OPERAND (TREE_OPERAND (arg0, 0), 1); + double_int masked + = mask_with_trailing_zeros (type, c3, tree_to_double_int (t)); + + valid = masked != c1; + } + + if (c3 != c1 && valid) return fold_build2_loc (loc, BIT_IOR_EXPR, type, fold_build2_loc (loc, BIT_AND_EXPR, type, TREE_OPERAND (arg0, 0), @@ -11599,22 +11633,17 @@ fold_binary_loc (location_t loc, && TREE_CODE (arg0) == MULT_EXPR && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST) { - int arg1tz - = tree_to_double_int (TREE_OPERAND (arg0, 1)).trailing_zeros (); - if (arg1tz > 0) - { - double_int arg1mask, masked; - arg1mask = ~double_int::mask (arg1tz); - arg1mask = arg1mask.ext (TYPE_PRECISION (type), - TYPE_UNSIGNED (type)); - masked = arg1mask & tree_to_double_int (arg1); - if (masked.is_zero ()) - return omit_two_operands_loc (loc, type, build_zero_cst (type), - arg0, arg1); - else if (masked != tree_to_double_int (arg1)) - return fold_build2_loc (loc, code, type, op0, - double_int_to_tree (type, masked)); - } + tree t = TREE_OPERAND (arg0, 1); + double_int masked + = mask_with_trailing_zeros (type, tree_to_double_int (arg1), + tree_to_double_int (t)); + + if (masked.is_zero ()) + return omit_two_operands_loc (loc, type, build_zero_cst (type), + arg0, arg1); + else if (masked != tree_to_double_int (arg1)) + return fold_build2_loc (loc, code, type, op0, + double_int_to_tree (type, masked)); } /* For constants M and N, if M == (1LL << cst) - 1 && (N & M) == M, --- gcc-4.8.1/gcc/testsuite/gcc.c-torture/compile/pr58088.c.~1~ 1970-01-01 01:00:00.000000000 +0100 +++ gcc-4.8.1/gcc/testsuite/gcc.c-torture/compile/pr58088.c 2013-08-10 11:55:54.066202706 +0200 @@ -0,0 +1,5 @@ +int +bar (int i) +{ + return 1 | ((i * 2) & 254); +}