re PR middle-end/50865 (Invalid code generation for INT64_MIN % 1 on x86_64)
PR middle-end/50865 PR tree-optimization/69097 * fold-const.h (expr_not_equal_to): New prototype. * fold-const.c: Include stringpool.h and tree-ssanames.h. (expr_not_equal_to): New function. * match.pd (X % -Y is the same as X % Y): Don't optimize unless X is known not to be equal to minimum or Y is known not to be equal to -1. * tree-vrp.c (simplify_div_or_mod_using_ranges): Add GSI argument. fold TRUNC_MOD_EXPR if the second argument is not a power of two. (simplify_stmt_using_ranges): Adjust caller. (vrp_finalize): Call set_value_range on SSA_NAMEs before calling substitute_and_fold. * gcc.c-torture/execute/pr50865.c: New test. * gcc.c-torture/execute/pr69097-1.c: New test. * gcc.c-torture/execute/pr69097-2.c: New test. * gcc.dg/pr69097-1.c: New test. * gcc.dg/pr69097-2.c: New test. From-SVN: r232188
This commit is contained in:
parent
c50e614be6
commit
20b8d7342c
|
@ -1,3 +1,19 @@
|
|||
2016-01-09 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR middle-end/50865
|
||||
PR tree-optimization/69097
|
||||
* fold-const.h (expr_not_equal_to): New prototype.
|
||||
* fold-const.c: Include stringpool.h and tree-ssanames.h.
|
||||
(expr_not_equal_to): New function.
|
||||
* match.pd (X % -Y is the same as X % Y): Don't optimize
|
||||
unless X is known not to be equal to minimum or Y is known
|
||||
not to be equal to -1.
|
||||
* tree-vrp.c (simplify_div_or_mod_using_ranges): Add GSI argument.
|
||||
fold TRUNC_MOD_EXPR if the second argument is not a power of two.
|
||||
(simplify_stmt_using_ranges): Adjust caller.
|
||||
(vrp_finalize): Call set_value_range on SSA_NAMEs before calling
|
||||
substitute_and_fold.
|
||||
|
||||
2016-01-09 Jan Hubicka <hubicka@ucw.cz>
|
||||
|
||||
* ipa-icf.c (sem_item_optimizer::merge_classes): Do not ICE on VAR_DECL
|
||||
|
|
|
@ -74,6 +74,8 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "tree-into-ssa.h"
|
||||
#include "md5.h"
|
||||
#include "case-cfn-macros.h"
|
||||
#include "stringpool.h"
|
||||
#include "tree-ssanames.h"
|
||||
|
||||
#ifndef LOAD_EXTEND_OP
|
||||
#define LOAD_EXTEND_OP(M) UNKNOWN
|
||||
|
@ -9101,6 +9103,45 @@ tree_expr_nonzero_p (tree t)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Return true if T is known not to be equal to an integer W. */
|
||||
|
||||
bool
|
||||
expr_not_equal_to (tree t, const wide_int &w)
|
||||
{
|
||||
wide_int min, max, nz;
|
||||
value_range_type rtype;
|
||||
switch (TREE_CODE (t))
|
||||
{
|
||||
case INTEGER_CST:
|
||||
return wi::ne_p (t, w);
|
||||
|
||||
case SSA_NAME:
|
||||
if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
|
||||
return false;
|
||||
rtype = get_range_info (t, &min, &max);
|
||||
if (rtype == VR_RANGE)
|
||||
{
|
||||
if (wi::lt_p (max, w, TYPE_SIGN (TREE_TYPE (t))))
|
||||
return true;
|
||||
if (wi::lt_p (w, min, TYPE_SIGN (TREE_TYPE (t))))
|
||||
return true;
|
||||
}
|
||||
else if (rtype == VR_ANTI_RANGE
|
||||
&& wi::le_p (min, w, TYPE_SIGN (TREE_TYPE (t)))
|
||||
&& wi::le_p (w, max, TYPE_SIGN (TREE_TYPE (t))))
|
||||
return true;
|
||||
/* If T has some known zero bits and W has any of those bits set,
|
||||
then T is known not to be equal to W. */
|
||||
if (wi::ne_p (wi::zext (wi::bit_and_not (w, get_nonzero_bits (t)),
|
||||
TYPE_PRECISION (TREE_TYPE (t))), 0))
|
||||
return true;
|
||||
return false;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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,
|
||||
|
|
|
@ -177,6 +177,7 @@ extern bool merge_ranges (int *, tree *, tree *, int, tree, tree, int,
|
|||
tree, tree);
|
||||
extern tree sign_bit_p (tree, const_tree);
|
||||
extern tree exact_inverse (tree, tree);
|
||||
extern bool expr_not_equal_to (tree t, const wide_int &);
|
||||
extern tree const_unop (enum tree_code, tree, tree);
|
||||
extern tree const_binop (enum tree_code, tree, tree, tree);
|
||||
extern bool negate_mathfn_p (combined_fn);
|
||||
|
|
|
@ -295,7 +295,13 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
|
|||
(trunc_mod @0 (convert? (negate @1)))
|
||||
(if (!TYPE_UNSIGNED (type)
|
||||
&& !TYPE_OVERFLOW_TRAPS (type)
|
||||
&& tree_nop_conversion_p (type, TREE_TYPE (@1)))
|
||||
&& tree_nop_conversion_p (type, TREE_TYPE (@1))
|
||||
/* Avoid this transformation if X might be INT_MIN or
|
||||
Y might be -1, because we would then change valid
|
||||
INT_MIN % -(-1) into invalid INT_MIN % -1. */
|
||||
&& (expr_not_equal_to (@0, TYPE_MIN_VALUE (type))
|
||||
|| expr_not_equal_to (@1, wi::minus_one (TYPE_PRECISION
|
||||
(TREE_TYPE (@1))))))
|
||||
(trunc_mod @0 (convert @1))))
|
||||
|
||||
/* X - (X / Y) * Y is the same as X % Y. */
|
||||
|
|
|
@ -1,3 +1,13 @@
|
|||
2016-01-09 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR middle-end/50865
|
||||
PR tree-optimization/69097
|
||||
* gcc.c-torture/execute/pr50865.c: New test.
|
||||
* gcc.c-torture/execute/pr69097-1.c: New test.
|
||||
* gcc.c-torture/execute/pr69097-2.c: New test.
|
||||
* gcc.dg/pr69097-1.c: New test.
|
||||
* gcc.dg/pr69097-2.c: New test.
|
||||
|
||||
2016-01-09 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR c++/69164
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/* PR middle-end/50865 */
|
||||
|
||||
#define INT64_MIN (-__LONG_LONG_MAX__ - 1)
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
volatile long long l1 = 1;
|
||||
volatile long long l2 = -1;
|
||||
volatile long long l3 = -1;
|
||||
|
||||
if ((INT64_MIN % 1LL) != 0)
|
||||
__builtin_abort ();
|
||||
if ((INT64_MIN % l1) != 0)
|
||||
__builtin_abort ();
|
||||
if (l2 == -1)
|
||||
{
|
||||
if ((INT64_MIN % 1LL) != 0)
|
||||
__builtin_abort ();
|
||||
}
|
||||
else if ((INT64_MIN % -l2) != 0)
|
||||
__builtin_abort ();
|
||||
if ((INT64_MIN % -l3) != 0)
|
||||
__builtin_abort ();
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
/* PR tree-optimization/69097 */
|
||||
|
||||
int a, b;
|
||||
unsigned int c;
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
int d = b;
|
||||
b = ~(~a + (~d | b));
|
||||
a = ~(~c >> b);
|
||||
c = a % b;
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/* PR tree-optimization/69097 */
|
||||
|
||||
__attribute__((noinline, noclone)) int
|
||||
f1 (int x, int y)
|
||||
{
|
||||
return x % y;
|
||||
}
|
||||
|
||||
__attribute__((noinline, noclone)) int
|
||||
f2 (int x, int y)
|
||||
{
|
||||
return x % -y;
|
||||
}
|
||||
|
||||
__attribute__((noinline, noclone)) int
|
||||
f3 (int x, int y)
|
||||
{
|
||||
int z = -y;
|
||||
return x % z;
|
||||
}
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
if (f1 (-__INT_MAX__ - 1, 1) != 0
|
||||
|| f2 (-__INT_MAX__ - 1, -1) != 0
|
||||
|| f3 (-__INT_MAX__ - 1, -1) != 0)
|
||||
__builtin_abort ();
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
/* PR tree-optimization/69097 */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdump-tree-optimized" } */
|
||||
/* All the x % -y below should be optimized into x % y, as
|
||||
it should never be INT_MIN % -(-1). */
|
||||
/* { dg-final { scan-tree-dump-not "-y" "optimized" } } */
|
||||
|
||||
int
|
||||
f1 (int x, int y)
|
||||
{
|
||||
if (x == -__INT_MAX__ - 1)
|
||||
__builtin_unreachable ();
|
||||
return x % -y;
|
||||
}
|
||||
|
||||
int
|
||||
f2 (int x, int y)
|
||||
{
|
||||
if (x < -__INT_MAX__)
|
||||
__builtin_unreachable ();
|
||||
return x % -y;
|
||||
}
|
||||
|
||||
int
|
||||
f3 (int x, int y)
|
||||
{
|
||||
if (y == -1)
|
||||
__builtin_unreachable ();
|
||||
return x % -y;
|
||||
}
|
||||
|
||||
int
|
||||
f4 (int x, int y)
|
||||
{
|
||||
if (y < 0)
|
||||
__builtin_unreachable ();
|
||||
return x % -y;
|
||||
}
|
||||
|
||||
int
|
||||
f5 (int x, int y)
|
||||
{
|
||||
if (y >= -1)
|
||||
__builtin_unreachable ();
|
||||
return x % -y;
|
||||
}
|
||||
|
||||
int
|
||||
f6 (int x, int y)
|
||||
{
|
||||
if (y < 0 || y > 24)
|
||||
__builtin_unreachable ();
|
||||
return x % -y;
|
||||
}
|
||||
|
||||
int
|
||||
f7 (int x, int y)
|
||||
{
|
||||
if (y <= -17 || y >= -1)
|
||||
__builtin_unreachable ();
|
||||
return x % -y;
|
||||
}
|
||||
|
||||
int
|
||||
f8 (int x, int y)
|
||||
{
|
||||
if (y >= -13 && y <= 15)
|
||||
__builtin_unreachable ();
|
||||
return x % -y;
|
||||
}
|
||||
|
||||
int
|
||||
f9 (int x, int y)
|
||||
{
|
||||
return x % -(y & ~4);
|
||||
}
|
||||
|
||||
int
|
||||
f10 (int x, int y)
|
||||
{
|
||||
if (x != -__INT_MAX__ - 1)
|
||||
return x % -y;
|
||||
return 34;
|
||||
}
|
||||
|
||||
int
|
||||
f11 (int x, int y)
|
||||
{
|
||||
if (x >= -__INT_MAX__)
|
||||
return x % -y;
|
||||
return 34;
|
||||
}
|
||||
|
||||
int
|
||||
f12 (int x, int y)
|
||||
{
|
||||
if (y != -1)
|
||||
return x % -y;
|
||||
return 34;
|
||||
}
|
||||
|
||||
int
|
||||
f13 (int x, int y)
|
||||
{
|
||||
if (y >= 0)
|
||||
return x % -y;
|
||||
return 34;
|
||||
}
|
||||
|
||||
int
|
||||
f14 (int x, int y)
|
||||
{
|
||||
if (y < -1)
|
||||
return x % -y;
|
||||
return 34;
|
||||
}
|
||||
|
||||
int
|
||||
f15 (int x, int y)
|
||||
{
|
||||
if (y >= 0 && y <= 24)
|
||||
return x % -y;
|
||||
return 34;
|
||||
}
|
||||
|
||||
int
|
||||
f16 (int x, int y)
|
||||
{
|
||||
if (y > -17 && y < -1)
|
||||
return x % -y;
|
||||
return 34;
|
||||
}
|
||||
|
||||
int
|
||||
f17 (int x, int y)
|
||||
{
|
||||
if (y < -13 || y > 15)
|
||||
return x % -y;
|
||||
return 34;
|
||||
}
|
|
@ -0,0 +1,138 @@
|
|||
/* PR tree-optimization/69097 */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdump-tree-optimized" } */
|
||||
/* { dg-final { scan-tree-dump-times "-y" 17 "optimized" } } */
|
||||
|
||||
int
|
||||
f1 (int x, int y)
|
||||
{
|
||||
if (x == -__INT_MAX__)
|
||||
__builtin_unreachable ();
|
||||
return x % -y;
|
||||
}
|
||||
|
||||
int
|
||||
f2 (int x, int y)
|
||||
{
|
||||
if (x >= -__INT_MAX__ + 1)
|
||||
__builtin_unreachable ();
|
||||
return x % -y;
|
||||
}
|
||||
|
||||
int
|
||||
f3 (int x, int y)
|
||||
{
|
||||
if (y == -2)
|
||||
__builtin_unreachable ();
|
||||
return x % -y;
|
||||
}
|
||||
|
||||
int
|
||||
f4 (int x, int y)
|
||||
{
|
||||
if (y < -1)
|
||||
__builtin_unreachable ();
|
||||
return x % -y;
|
||||
}
|
||||
|
||||
int
|
||||
f5 (int x, int y)
|
||||
{
|
||||
if (y >= 0)
|
||||
__builtin_unreachable ();
|
||||
return x % -y;
|
||||
}
|
||||
|
||||
int
|
||||
f6 (int x, int y)
|
||||
{
|
||||
if (y < -1 || y > 24)
|
||||
__builtin_unreachable ();
|
||||
return x % -y;
|
||||
}
|
||||
|
||||
int
|
||||
f7 (int x, int y)
|
||||
{
|
||||
if (y <= -17 || y >= 0)
|
||||
__builtin_unreachable ();
|
||||
return x % -y;
|
||||
}
|
||||
|
||||
int
|
||||
f8 (int x, int y)
|
||||
{
|
||||
if (y >= -13 && y <= -2)
|
||||
__builtin_unreachable ();
|
||||
return x % -y;
|
||||
}
|
||||
|
||||
int
|
||||
f9 (int x, int y)
|
||||
{
|
||||
return x % -y;
|
||||
}
|
||||
|
||||
int
|
||||
f10 (int x, int y)
|
||||
{
|
||||
if (x != -__INT_MAX__)
|
||||
return x % -y;
|
||||
return 34;
|
||||
}
|
||||
|
||||
int
|
||||
f11 (int x, int y)
|
||||
{
|
||||
if (x < -__INT_MAX__ + 2)
|
||||
return x % -y;
|
||||
return 34;
|
||||
}
|
||||
|
||||
int
|
||||
f12 (int x, int y)
|
||||
{
|
||||
if (y != -2)
|
||||
return x % -y;
|
||||
return 34;
|
||||
}
|
||||
|
||||
int
|
||||
f13 (int x, int y)
|
||||
{
|
||||
if (y >= -1)
|
||||
return x % -y;
|
||||
return 34;
|
||||
}
|
||||
|
||||
int
|
||||
f14 (int x, int y)
|
||||
{
|
||||
if (y < 0)
|
||||
return x % -y;
|
||||
return 34;
|
||||
}
|
||||
|
||||
int
|
||||
f15 (int x, int y)
|
||||
{
|
||||
if (y >= -1 && y <= 24)
|
||||
return x % -y;
|
||||
return 34;
|
||||
}
|
||||
|
||||
int
|
||||
f16 (int x, int y)
|
||||
{
|
||||
if (y > -17 && y < 0)
|
||||
return x % -y;
|
||||
return 34;
|
||||
}
|
||||
|
||||
int
|
||||
f17 (int x, int y)
|
||||
{
|
||||
if (y < -13 || y > -4)
|
||||
return x % -y;
|
||||
return 34;
|
||||
}
|
|
@ -8942,7 +8942,7 @@ simplify_truth_ops_using_ranges (gimple_stmt_iterator *gsi, gimple *stmt)
|
|||
modulo. */
|
||||
|
||||
static bool
|
||||
simplify_div_or_mod_using_ranges (gimple *stmt)
|
||||
simplify_div_or_mod_using_ranges (gimple_stmt_iterator *gsi, gimple *stmt)
|
||||
{
|
||||
enum tree_code rhs_code = gimple_assign_rhs_code (stmt);
|
||||
tree val = NULL;
|
||||
|
@ -8971,12 +8971,19 @@ simplify_div_or_mod_using_ranges (gimple *stmt)
|
|||
}
|
||||
|
||||
if (!integer_pow2p (op1))
|
||||
return false;
|
||||
{
|
||||
/* X % -Y can be only optimized into X % Y either if
|
||||
X is not INT_MIN, or Y is not -1. Fold it now, as after
|
||||
remove_range_assertions the range info might be not available
|
||||
anymore. */
|
||||
if (rhs_code == TRUNC_MOD_EXPR
|
||||
&& fold_stmt (gsi, follow_single_use_edges))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (TYPE_UNSIGNED (TREE_TYPE (op0)))
|
||||
{
|
||||
val = integer_one_node;
|
||||
}
|
||||
val = integer_one_node;
|
||||
else
|
||||
{
|
||||
bool sop = false;
|
||||
|
@ -9890,7 +9897,7 @@ simplify_stmt_using_ranges (gimple_stmt_iterator *gsi)
|
|||
case TRUNC_MOD_EXPR:
|
||||
if (TREE_CODE (rhs1) == SSA_NAME
|
||||
&& INTEGRAL_TYPE_P (TREE_TYPE (rhs1)))
|
||||
return simplify_div_or_mod_using_ranges (stmt);
|
||||
return simplify_div_or_mod_using_ranges (gsi, stmt);
|
||||
break;
|
||||
|
||||
/* Transform ABS (X) into X or -X as appropriate. */
|
||||
|
@ -10200,16 +10207,6 @@ vrp_finalize (bool warn_array_bounds_p)
|
|||
fprintf (dump_file, "\n");
|
||||
}
|
||||
|
||||
substitute_and_fold (op_with_constant_singleton_value_range,
|
||||
vrp_fold_stmt, false);
|
||||
|
||||
if (warn_array_bounds && warn_array_bounds_p)
|
||||
check_all_array_refs ();
|
||||
|
||||
/* We must identify jump threading opportunities before we release
|
||||
the datastructures built by VRP. */
|
||||
identify_jump_threads ();
|
||||
|
||||
/* Set value range to non pointer SSA_NAMEs. */
|
||||
for (i = 0; i < num_vr_values; i++)
|
||||
if (vr_value[i])
|
||||
|
@ -10230,6 +10227,16 @@ vrp_finalize (bool warn_array_bounds_p)
|
|||
vr_value[i]->max);
|
||||
}
|
||||
|
||||
substitute_and_fold (op_with_constant_singleton_value_range,
|
||||
vrp_fold_stmt, false);
|
||||
|
||||
if (warn_array_bounds && warn_array_bounds_p)
|
||||
check_all_array_refs ();
|
||||
|
||||
/* We must identify jump threading opportunities before we release
|
||||
the datastructures built by VRP. */
|
||||
identify_jump_threads ();
|
||||
|
||||
/* Free allocated memory. */
|
||||
for (i = 0; i < num_vr_values; i++)
|
||||
if (vr_value[i])
|
||||
|
|
Loading…
Reference in New Issue