Hi,

this is a regression introduced on the mainline, 15 and 14 branches by:
  https://gcc.gnu.org/pipermail/gcc-patches/2023-December/639303.html
although one may consider that the problem was latent before.

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 at:
  https://gcc.gnu.org/pipermail/gcc-patches/2020-November/558537.html

"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."

Here it's the reverse case: the bitwise NOT (~) is treated as logical by the 
machinery in range-op.cc but the bitwise OR (|) is *not* treated as logical by 
that of vr-values.cc, leading to the same problematic outcome.

Tested on x86-64/Linux, OK for the mainline, 15 and 14 branches?


2025-05-09  Eric Botcazou  <ebotca...@adacore.com>

        * 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.


2025-05-09  Eric Botcazou  <ebotca...@adacore.com>

        * 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.

-- 
Eric Botcazou
diff --git a/gcc/vr-values.cc b/gcc/vr-values.cc
index 6603d90c392..4c787593b95 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;
 
-- { 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;
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;
package body Opt106_Pkg2 is

  procedure Stop (Delayed : Integer;
                  Before  : Integer;
                  After   : Integer;
                  Last    : Boolean) is
  begin
     raise Program_Error;
  end;

end Opt106_Pkg2;
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;
package Opt106_Pkg2 is

  procedure Stop (Delayed : Integer;
                  Before  : Integer;
                  After   : Integer;
                  Last    : Boolean);

end Opt106_Pkg2;

Reply via email to