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;