aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorEric Botcazou <ebotcazou@adacore.com>2020-11-10 10:26:35 +0100
committerEric Botcazou <ebotcazou@adacore.com>2020-11-10 12:11:34 +0100
commit61dd8dab1f0b349fb4124cfd8e2a11a161f13e4a (patch)
tree1347f21e992fa9cb9a58d151204f5a0b5ed12968 /gcc
parent15e5f41a1c88fce773cd9d13fe02052ace1803ce (diff)
downloadgcc-61dd8dab1f0b349fb4124cfd8e2a11a161f13e4a.zip
gcc-61dd8dab1f0b349fb4124cfd8e2a11a161f13e4a.tar.gz
gcc-61dd8dab1f0b349fb4124cfd8e2a11a161f13e4a.tar.bz2
Fix wrong code for boolean negation in condition at -O2
The problem is the bitwise/logical dichotomy for operators and the transition from the former to the latter for boolean types: if they are 1-bit, that's straightforward but, if they are larger, then you need to be careful because you cannot, on the one hand, turn a bitwise AND into a logical AND and, on the other hand, *not* turn e.g. a bitwise NOT into a logical NOT if they occur in the same computation, as the first change will drop the masking that may need to be applied after the bitwise NOT if it is not also changed. Given that the ranger turns bitwise AND/OR into logical AND/OR for booleans, the patch does the same for bitwise NOT. gcc/ChangeLog: * range-op.cc (operator_logical_not::fold_range): Tidy up. (operator_logical_not::op1_range): Call above method. (operator_bitwise_not::fold_range): If the type is compatible with boolean, call op_logical_not.fold_range. (operator_bitwise_not::op1_range): If the type is compatible with boolean, call op_logical_not.op1_range. gcc/testsuite/ChangeLog: * gnat.dg/opt88.adb: New test.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/range-op.cc28
-rw-r--r--gcc/testsuite/gnat.dg/opt88.adb52
2 files changed, 66 insertions, 14 deletions
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index bbb2a61..aff9383 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -2706,27 +2706,21 @@ operator_logical_not::fold_range (irange &r, tree type,
if (empty_range_varying (r, type, lh, rh))
return true;
- if (lh.varying_p () || lh.undefined_p ())
- r = lh;
- else
- {
- r = lh;
- r.invert ();
- }
- gcc_checking_assert (lh.type() == type);
+ r = lh;
+ if (!lh.varying_p () && !lh.undefined_p ())
+ r.invert ();
+
return true;
}
bool
operator_logical_not::op1_range (irange &r,
- tree type ATTRIBUTE_UNUSED,
+ tree type,
const irange &lhs,
- const irange &op2 ATTRIBUTE_UNUSED) const
+ const irange &op2) const
{
- r = lhs;
- if (!lhs.varying_p () && !lhs.undefined_p ())
- r.invert ();
- return true;
+ // Logical NOT is involutary...do it again.
+ return fold_range (r, type, lhs, op2);
}
@@ -2749,6 +2743,9 @@ operator_bitwise_not::fold_range (irange &r, tree type,
if (empty_range_varying (r, type, lh, rh))
return true;
+ if (types_compatible_p (type, boolean_type_node))
+ return op_logical_not.fold_range (r, type, lh, rh);
+
// ~X is simply -1 - X.
int_range<1> minusone (type, wi::minus_one (TYPE_PRECISION (type)),
wi::minus_one (TYPE_PRECISION (type)));
@@ -2761,6 +2758,9 @@ operator_bitwise_not::op1_range (irange &r, tree type,
const irange &lhs,
const irange &op2) const
{
+ if (types_compatible_p (type, boolean_type_node))
+ return op_logical_not.op1_range (r, type, lhs, op2);
+
// ~X is -1 - X and since bitwise NOT is involutary...do it again.
return fold_range (r, type, lhs, op2);
}
diff --git a/gcc/testsuite/gnat.dg/opt88.adb b/gcc/testsuite/gnat.dg/opt88.adb
new file mode 100644
index 0000000..a6abd01
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/opt88.adb
@@ -0,0 +1,52 @@
+-- { dg-do run }
+-- { dg-options "-O -ftree-vrp -fno-inline" }
+
+procedure Opt88 is
+
+ Val : Integer := 1;
+
+ procedure Dummy (B : out Boolean) is
+ begin
+ B := True;
+ end;
+
+ function Test return Boolean is
+ begin
+ return False;
+ end;
+
+ procedure Do_It (OK : out Boolean) is
+
+ Blue : Boolean := False;
+ Red : Boolean := False;
+
+ begin
+ OK := True;
+ Blue := True;
+ Dummy (Red);
+
+ if Red then
+ Red := False;
+
+ if Test then
+ Dummy (Red);
+ end if;
+ end if;
+
+ if Blue and not Red then
+ Val := 0;
+ end if;
+
+ if Red then
+ OK := False;
+ end if;
+ end;
+
+ OK : Boolean;
+
+begin
+ Do_It (OK);
+ if not OK then
+ raise Program_Error;
+ end if;
+end;