From f9cddb4cf931826f09197ed0fc2d6d64e6ccc3c3 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacleod@redhat.com>
Date: Wed, 22 Nov 2023 17:24:42 -0500
Subject: [PATCH] Ensure wi_fold arguments match precisions.
Return VARYING if any of the required operands or types to wi_fold do
not match expected precisions.
PR tree-optimization/111922
gcc/
* range-op.cc (operator_plus::wi_fold): Check that precisions of
arguments and result type match.
(operator_widen_plus_signed::wi_fold): Ditto.
(operator_widen_plus_unsigned::wi_fold): Ditto.
(operator_minus::wi_fold): Ditto.
(operator_min::wi_fold): Ditto.
(operator_max::wi_fold): Ditto.
(operator_mult::wi_fold): Ditto.
(operator_widen_mult_signed::wi_fold): Ditto.
(operator_widen_mult_unsigned::wi_fold): Ditto.
(operator_div::wi_fold): Ditto.
(operator_lshift::wi_fold): Ditto.
(operator_rshift::wi_fold): Ditto.
(operator_bitwise_and::wi_fold): Ditto.
(operator_bitwise_or::wi_fold): Ditto.
(operator_bitwise_xor::wi_fold): Ditto.
(operator_trunc_mod::wi_fold): Ditto.
(operator_abs::wi_fold): Ditto.
(operator_absu::wi_fold): Ditto.
gcc/testsuite/
* gcc.dg/pr111922.c: New.
---
gcc/range-op.cc | 119 ++++++++++++++++++++++++++++++++
gcc/testsuite/gcc.dg/pr111922.c | 29 ++++++++
2 files changed, 148 insertions(+)
create mode 100644 gcc/testsuite/gcc.dg/pr111922.c
@@ -1651,6 +1651,13 @@ operator_plus::wi_fold (irange &r, tree type,
const wide_int &lh_lb, const wide_int &lh_ub,
const wide_int &rh_lb, const wide_int &rh_ub) const
{
+ // This operation requires all types to be the same precision.
+ if (lh_lb.get_precision () != rh_lb.get_precision ()
+ || lh_lb.get_precision () != TYPE_PRECISION (type))
+ {
+ r.set_varying (type);
+ return;
+ }
wi::overflow_type ov_lb, ov_ub;
signop s = TYPE_SIGN (type);
wide_int new_lb = wi::add (lh_lb, rh_lb, s, &ov_lb);
@@ -1797,6 +1804,12 @@ operator_widen_plus_signed::wi_fold (irange &r, tree type,
const wide_int &rh_lb,
const wide_int &rh_ub) const
{
+ // This operation requires both sides to be the same precision.
+ if (lh_lb.get_precision () != rh_lb.get_precision ())
+ {
+ r.set_varying (type);
+ return;
+ }
wi::overflow_type ov_lb, ov_ub;
signop s = TYPE_SIGN (type);
@@ -1830,6 +1843,12 @@ operator_widen_plus_unsigned::wi_fold (irange &r, tree type,
const wide_int &rh_lb,
const wide_int &rh_ub) const
{
+ // This operation requires both sides to be the same precision.
+ if (lh_lb.get_precision () != rh_lb.get_precision ())
+ {
+ r.set_varying (type);
+ return;
+ }
wi::overflow_type ov_lb, ov_ub;
signop s = TYPE_SIGN (type);
@@ -1858,6 +1877,14 @@ operator_minus::wi_fold (irange &r, tree type,
const wide_int &lh_lb, const wide_int &lh_ub,
const wide_int &rh_lb, const wide_int &rh_ub) const
{
+ // This operation requires all ranges and types to be the same precision.
+ if (lh_lb.get_precision () != rh_lb.get_precision ()
+ || lh_lb.get_precision () != TYPE_PRECISION (type))
+ {
+ r.set_varying (type);
+ return;
+ }
+
wi::overflow_type ov_lb, ov_ub;
signop s = TYPE_SIGN (type);
wide_int new_lb = wi::sub (lh_lb, rh_ub, s, &ov_lb);
@@ -2008,6 +2035,13 @@ operator_min::wi_fold (irange &r, tree type,
const wide_int &lh_lb, const wide_int &lh_ub,
const wide_int &rh_lb, const wide_int &rh_ub) const
{
+ // This operation requires all ranges and types to be the same precision.
+ if (lh_lb.get_precision () != rh_lb.get_precision ()
+ || lh_lb.get_precision () != TYPE_PRECISION (type))
+ {
+ r.set_varying (type);
+ return;
+ }
signop s = TYPE_SIGN (type);
wide_int new_lb = wi::min (lh_lb, rh_lb, s);
wide_int new_ub = wi::min (lh_ub, rh_ub, s);
@@ -2027,6 +2061,13 @@ operator_max::wi_fold (irange &r, tree type,
const wide_int &lh_lb, const wide_int &lh_ub,
const wide_int &rh_lb, const wide_int &rh_ub) const
{
+ // This operation requires all ranges and types to be the same precision.
+ if (lh_lb.get_precision () != rh_lb.get_precision ()
+ || lh_lb.get_precision () != TYPE_PRECISION (type))
+ {
+ r.set_varying (type);
+ return;
+ }
signop s = TYPE_SIGN (type);
wide_int new_lb = wi::max (lh_lb, rh_lb, s);
wide_int new_ub = wi::max (lh_ub, rh_ub, s);
@@ -2149,6 +2190,13 @@ operator_mult::wi_fold (irange &r, tree type,
const wide_int &lh_lb, const wide_int &lh_ub,
const wide_int &rh_lb, const wide_int &rh_ub) const
{
+ // This operation requires all ranges and types to be the same precision.
+ if (lh_lb.get_precision () != rh_lb.get_precision ()
+ || lh_lb.get_precision () != TYPE_PRECISION (type))
+ {
+ r.set_varying (type);
+ return;
+ }
if (TYPE_OVERFLOW_UNDEFINED (type))
{
wi_cross_product (r, type, lh_lb, lh_ub, rh_lb, rh_ub);
@@ -2253,6 +2301,12 @@ operator_widen_mult_signed::wi_fold (irange &r, tree type,
const wide_int &rh_lb,
const wide_int &rh_ub) const
{
+ // This operation requires both sides to be the same precision.
+ if (lh_lb.get_precision () != rh_lb.get_precision ())
+ {
+ r.set_varying (type);
+ return;
+ }
signop s = TYPE_SIGN (type);
wide_int lh_wlb = wide_int::from (lh_lb, wi::get_precision (lh_lb) * 2, SIGNED);
@@ -2285,6 +2339,12 @@ operator_widen_mult_unsigned::wi_fold (irange &r, tree type,
const wide_int &rh_lb,
const wide_int &rh_ub) const
{
+ // This operation requires both sides to be the same precision.
+ if (lh_lb.get_precision () != rh_lb.get_precision ())
+ {
+ r.set_varying (type);
+ return;
+ }
signop s = TYPE_SIGN (type);
wide_int lh_wlb = wide_int::from (lh_lb, wi::get_precision (lh_lb) * 2, UNSIGNED);
@@ -2364,6 +2424,13 @@ operator_div::wi_fold (irange &r, tree type,
const wide_int &lh_lb, const wide_int &lh_ub,
const wide_int &rh_lb, const wide_int &rh_ub) const
{
+ // This operation requires all ranges and types to be the same precision.
+ if (lh_lb.get_precision () != rh_lb.get_precision ()
+ || lh_lb.get_precision () != TYPE_PRECISION (type))
+ {
+ r.set_varying (type);
+ return;
+ }
const wide_int dividend_min = lh_lb;
const wide_int dividend_max = lh_ub;
const wide_int divisor_min = rh_lb;
@@ -2555,6 +2622,12 @@ operator_lshift::wi_fold (irange &r, tree type,
const wide_int &lh_lb, const wide_int &lh_ub,
const wide_int &rh_lb, const wide_int &rh_ub) const
{
+ // This operation requires left operand and type to be the same precision.
+ if (lh_lb.get_precision () != TYPE_PRECISION (type))
+ {
+ r.set_varying (type);
+ return;
+ }
signop sign = TYPE_SIGN (type);
unsigned prec = TYPE_PRECISION (type);
int overflow_pos = sign == SIGNED ? prec - 1 : prec;
@@ -2807,6 +2880,12 @@ operator_rshift::wi_fold (irange &r, tree type,
const wide_int &lh_lb, const wide_int &lh_ub,
const wide_int &rh_lb, const wide_int &rh_ub) const
{
+ // This operation requires left operand and type to be the same precision.
+ if (lh_lb.get_precision () != TYPE_PRECISION (type))
+ {
+ r.set_varying (type);
+ return;
+ }
wi_cross_product (r, type, lh_lb, lh_ub, rh_lb, rh_ub);
}
@@ -3319,6 +3398,13 @@ operator_bitwise_and::wi_fold (irange &r, tree type,
const wide_int &rh_lb,
const wide_int &rh_ub) const
{
+ // This operation requires all ranges and types to be the same precision.
+ if (lh_lb.get_precision () != rh_lb.get_precision ()
+ || lh_lb.get_precision () != TYPE_PRECISION (type))
+ {
+ r.set_varying (type);
+ return;
+ }
if (wi_optimize_and_or (r, BIT_AND_EXPR, type, lh_lb, lh_ub, rh_lb, rh_ub))
return;
@@ -3629,6 +3715,13 @@ operator_bitwise_or::wi_fold (irange &r, tree type,
const wide_int &rh_lb,
const wide_int &rh_ub) const
{
+ // This operation requires all ranges and types to be the same precision.
+ if (lh_lb.get_precision () != rh_lb.get_precision ()
+ || lh_lb.get_precision () != TYPE_PRECISION (type))
+ {
+ r.set_varying (type);
+ return;
+ }
if (wi_optimize_and_or (r, BIT_IOR_EXPR, type, lh_lb, lh_ub, rh_lb, rh_ub))
return;
@@ -3722,6 +3815,13 @@ operator_bitwise_xor::wi_fold (irange &r, tree type,
const wide_int &rh_lb,
const wide_int &rh_ub) const
{
+ // This operation requires all ranges and types to be the same precision.
+ if (lh_lb.get_precision () != rh_lb.get_precision ()
+ || lh_lb.get_precision () != TYPE_PRECISION (type))
+ {
+ r.set_varying (type);
+ return;
+ }
signop sign = TYPE_SIGN (type);
wide_int maybe_nonzero_lh, mustbe_nonzero_lh;
wide_int maybe_nonzero_rh, mustbe_nonzero_rh;
@@ -3865,6 +3965,13 @@ operator_trunc_mod::wi_fold (irange &r, tree type,
const wide_int &rh_lb,
const wide_int &rh_ub) const
{
+ // This operation requires all ranges and types to be the same precision.
+ if (lh_lb.get_precision () != rh_lb.get_precision ()
+ || lh_lb.get_precision () != TYPE_PRECISION (type))
+ {
+ r.set_varying (type);
+ return;
+ }
wide_int new_lb, new_ub, tmp;
signop sign = TYPE_SIGN (type);
unsigned prec = TYPE_PRECISION (type);
@@ -4151,6 +4258,12 @@ operator_abs::wi_fold (irange &r, tree type,
const wide_int &rh_lb ATTRIBUTE_UNUSED,
const wide_int &rh_ub ATTRIBUTE_UNUSED) const
{
+ // This operation requires the operand and type to be the same precision.
+ if (lh_lb.get_precision () != TYPE_PRECISION (type))
+ {
+ r.set_varying (type);
+ return;
+ }
wide_int min, max;
signop sign = TYPE_SIGN (type);
unsigned prec = TYPE_PRECISION (type);
@@ -4274,6 +4387,12 @@ operator_absu::wi_fold (irange &r, tree type,
const wide_int &rh_lb ATTRIBUTE_UNUSED,
const wide_int &rh_ub ATTRIBUTE_UNUSED) const
{
+ // This operation requires the operand and type to be the same precision.
+ if (lh_lb.get_precision () != TYPE_PRECISION (type))
+ {
+ r.set_varying (type);
+ return;
+ }
wide_int new_lb, new_ub;
// Pass through VR0 the easy cases.
new file mode 100644
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fno-tree-fre" } */
+
+void f2 (void);
+void f4 (int, int, int);
+struct A { int a; };
+struct B { struct A *b; int c; } v;
+
+static int
+f1 (x, y)
+ struct C *x;
+ struct A *y;
+{
+ (v.c = v.b->a) || (v.c = v.b->a);
+ f2 ();
+}
+
+static void
+f3 (int x, int y)
+{
+ int b = f1 (0, ~x);
+ f4 (0, 0, v.c);
+}
+
+void
+f5 (void)
+{
+ f3 (0, 0);
+}
--
2.41.0