https://gcc.gnu.org/g:6683f2cd1ce07fc8470b19dc3c1578b3e0645c25

commit r15-9644-g6683f2cd1ce07fc8470b19dc3c1578b3e0645c25
Author: Eric Botcazou <ebotca...@adacore.com>
Date:   Fri May 9 17:45:27 2025 +0200

    Fix wrong optimization of complex boolean expression
    
    The VRP2 pass turns:
    
      # prephitmp_3 = PHI <0(4)>
      _1 = prephitmp_3 == 0;
      _5 = stretch_14(D) ^ 1;
      _39 = _1 & _5;
      _40 = _39 | last_20(D);
    
    into
    
      _5 = stretch_14(D) ^ 1;
      _42 = ~stretch_14(D);
      _39 = _42;
      _40 = last_20(D) | _39;
    
    using the following step:
    
    Folding statement: _1 = prephitmp_3 == 0;
    Queued stmt for removal.  Folds to: 1
    Folding statement: _5 = stretch_14(D) ^ 1;
    Not folded
    Folding statement: _39 = _1 & _5;
    gimple_simplified to _42 = ~stretch_14(D);
    _39 = _42 & 1;
    Folded into: _39 = _42;
    
    Folding statement: _40 = _39 | last_20(D);
    Folded into: _40 = last_20(D) | _39;
    
    but stretch_14 is a 8-bit boolean so the two forms are not equivalent, that
    is to say dropping the "& 1" is wrong.  It's another instance of the issue:
      https://gcc.gnu.org/pipermail/gcc-patches/2020-November/558537.html
    
    Here it's the reverse case: the bitwise NOT (~) is treated as logical by the
    machinery in range-op.cc but the bitwise AND (&) is *not* treated as logical
    by that of vr-values.cc, leading to the same problematic outcome.
    
    gcc/
            * vr-values.cc (simplify_using_ranges::simplify) <BIT_AND_EXPR>:
            Do not call simplify_bit_ops_using_ranges for boolean types whose
            precision is not 1.
    
    gcc/testsuite/
            * gnat.dg/opt106.adb: New test.
            * gnat.dg/opt106_pkg1.ads, gnat.dg/opt106_pkg1.adb: New helper.
            * gnat.dg/opt106_pkg2.ads, gnat.dg/opt106_pkg2.adb: Likewise.

Diff:
---
 gcc/testsuite/gnat.dg/opt106.adb      | 11 ++++++++++
 gcc/testsuite/gnat.dg/opt106_pkg1.adb | 39 +++++++++++++++++++++++++++++++++++
 gcc/testsuite/gnat.dg/opt106_pkg1.ads | 16 ++++++++++++++
 gcc/testsuite/gnat.dg/opt106_pkg2.adb | 11 ++++++++++
 gcc/testsuite/gnat.dg/opt106_pkg2.ads |  8 +++++++
 gcc/vr-values.cc                      | 11 ++++++----
 6 files changed, 92 insertions(+), 4 deletions(-)

diff --git a/gcc/testsuite/gnat.dg/opt106.adb b/gcc/testsuite/gnat.dg/opt106.adb
new file mode 100644
index 000000000000..525930b47439
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/opt106.adb
@@ -0,0 +1,11 @@
+-- { dg-do run }
+-- { dg-options "-O2" }
+
+with Opt106_Pkg1; use Opt106_Pkg1;
+
+procedure Opt106 is
+  Obj : T := (False, 0, 0, 0, True);
+
+begin
+  Proc (Obj, 0, False, True);
+end;
diff --git a/gcc/testsuite/gnat.dg/opt106_pkg1.adb 
b/gcc/testsuite/gnat.dg/opt106_pkg1.adb
new file mode 100644
index 000000000000..154b13f34ec7
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/opt106_pkg1.adb
@@ -0,0 +1,39 @@
+with Opt106_Pkg2; use Opt106_Pkg2;
+
+package body Opt106_Pkg1 is
+
+  procedure Proc (Obj     : in out T;
+                  Data    : Integer;
+                  Last    : Boolean;
+                  Stretch : Boolean) is
+
+  begin
+    if Stretch and then (Obj.Delayed /= 0 or else not Obj.Attach_Last) then
+      raise Program_Error;
+    end if;
+
+    if Obj.Delayed /= 0 then
+      Stop (Obj.Delayed, Obj.Before, Data, False);
+    end if;
+
+    if Last or (Obj.Delayed = 0 and not Stretch) then
+      Stop (Data, Obj.Before, 0, Last);
+
+      if Last then
+        Obj.Initialized := False;
+      else
+        Obj.Next := 0;
+        Obj.Before := Data;
+      end if;
+
+    else
+      if Stretch then
+        Obj.Next := 1;
+      else
+        Obj.Before := Obj.Delayed;
+      end if;
+      Obj.Delayed := Data;
+    end if;
+  end;
+
+end Opt106_Pkg1;
diff --git a/gcc/testsuite/gnat.dg/opt106_pkg1.ads 
b/gcc/testsuite/gnat.dg/opt106_pkg1.ads
new file mode 100644
index 000000000000..85ac24dc8a95
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/opt106_pkg1.ads
@@ -0,0 +1,16 @@
+package Opt106_Pkg1 is
+
+  type T is record
+    Initialized   : Boolean;
+    Before        : Integer;
+    Delayed       : Integer;
+    Next          : Integer;
+    Attach_Last   : Boolean;
+  end record;
+
+  procedure Proc (Obj     : in out T;
+                  Data    : Integer;
+                  Last    : Boolean;
+                  Stretch : Boolean);
+
+end Opt106_Pkg1;
diff --git a/gcc/testsuite/gnat.dg/opt106_pkg2.adb 
b/gcc/testsuite/gnat.dg/opt106_pkg2.adb
new file mode 100644
index 000000000000..cf639567fcb7
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/opt106_pkg2.adb
@@ -0,0 +1,11 @@
+package body Opt106_Pkg2 is
+
+  procedure Stop (Delayed : Integer;
+                  Before  : Integer;
+                  After   : Integer;
+                  Last    : Boolean) is
+  begin
+     raise Program_Error;
+  end;
+
+end Opt106_Pkg2;
diff --git a/gcc/testsuite/gnat.dg/opt106_pkg2.ads 
b/gcc/testsuite/gnat.dg/opt106_pkg2.ads
new file mode 100644
index 000000000000..77e5b40da97f
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/opt106_pkg2.ads
@@ -0,0 +1,8 @@
+package Opt106_Pkg2 is
+
+  procedure Stop (Delayed : Integer;
+                  Before  : Integer;
+                  After   : Integer;
+                  Last    : Boolean);
+
+end Opt106_Pkg2;
diff --git a/gcc/vr-values.cc b/gcc/vr-values.cc
index 6603d90c392c..4c787593b95a 100644
--- a/gcc/vr-values.cc
+++ b/gcc/vr-values.cc
@@ -1996,10 +1996,13 @@ simplify_using_ranges::simplify (gimple_stmt_iterator 
*gsi)
 
        case BIT_AND_EXPR:
        case BIT_IOR_EXPR:
-         /* Optimize away BIT_AND_EXPR and BIT_IOR_EXPR
-            if all the bits being cleared are already cleared or
-            all the bits being set are already set.  */
-         if (INTEGRAL_TYPE_P (TREE_TYPE (rhs1)))
+         /* Optimize away BIT_AND_EXPR and BIT_IOR_EXPR if all the bits
+            being cleared are already cleared or all the bits being set
+            are already set.  Beware that boolean types must be handled
+            logically (see range-op.cc) unless they have precision 1.  */
+         if (INTEGRAL_TYPE_P (TREE_TYPE (rhs1))
+             && (TREE_CODE (TREE_TYPE (rhs1)) != BOOLEAN_TYPE
+                 || TYPE_PRECISION (TREE_TYPE (rhs1)) == 1))
            return simplify_bit_ops_using_ranges (gsi, stmt);
          break;

Reply via email to