]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Fix wrong optimization of conditional expression with enumeration type
authorEric Botcazou <ebotcazou@gcc.gnu.org>
Wed, 16 Apr 2025 20:01:31 +0000 (22:01 +0200)
committerEric Botcazou <ebotcazou@gcc.gnu.org>
Wed, 16 Apr 2025 20:05:00 +0000 (22:05 +0200)
This is a regression introduced on the mainline and 14 branch by:
  https://gcc.gnu.org/pipermail/gcc-cvs/2023-October/391658.html

The change bypasses int_fits_type_p (essentially) to work around the
signedness constraints, but in doing so disregards the peculiarities
of boolean types whose precision is not 1 dealt with by the predicate,
leading to the creation of a problematic conversion here.

Fixed by special-casing boolean types whose precision is not 1, as done
in several other places.

gcc/
* tree-ssa-phiopt.cc (factor_out_conditional_operation): Do not
bypass the int_fits_type_p test for boolean types whose precision
is not 1.

gcc/testsuite/
* gnat.dg/opt105.adb: New test.
* gnat.dg/opt105_pkg.ads, gnat.dg/opt105_pkg.adb: New helper.

gcc/testsuite/gnat.dg/opt105.adb [new file with mode: 0644]
gcc/testsuite/gnat.dg/opt105_pkg.adb [new file with mode: 0644]
gcc/testsuite/gnat.dg/opt105_pkg.ads [new file with mode: 0644]
gcc/tree-ssa-phiopt.cc

diff --git a/gcc/testsuite/gnat.dg/opt105.adb b/gcc/testsuite/gnat.dg/opt105.adb
new file mode 100644 (file)
index 0000000..eb2c197
--- /dev/null
@@ -0,0 +1,30 @@
+-- { dg-do run }
+-- { dg-options "-O" }
+
+with Opt105_Pkg; use Opt105_Pkg;
+
+procedure Opt105 is
+
+  Val : constant Enum :=
+          (if Enabled then (if Disabled then Two else One) else Three);
+
+begin
+  if Cond1 then
+    return;
+  end if;
+
+  if Cond2 then
+    return;
+  end if;
+
+  case Val is
+    when One =>
+      raise Program_Error;
+
+    when Two =>
+      raise Constraint_Error;
+
+    when Three =>
+      null;
+  end case;
+end;
diff --git a/gcc/testsuite/gnat.dg/opt105_pkg.adb b/gcc/testsuite/gnat.dg/opt105_pkg.adb
new file mode 100644 (file)
index 0000000..e00de94
--- /dev/null
@@ -0,0 +1,6 @@
+package body Opt105_Pkg is
+
+  function Cond1 return Boolean is (False);
+  function Cond2 return Boolean is (False);
+
+end Opt105_Pkg;
diff --git a/gcc/testsuite/gnat.dg/opt105_pkg.ads b/gcc/testsuite/gnat.dg/opt105_pkg.ads
new file mode 100644 (file)
index 0000000..2b373b7
--- /dev/null
@@ -0,0 +1,11 @@
+package Opt105_Pkg is
+
+  type Enum is (One, Two, Three);
+
+  Enabled  : Boolean := False;
+  Disabled : Boolean := False;
+
+  function Cond1 return Boolean;
+  function Cond2 return Boolean;
+
+end Opt105_Pkg;
index 7d2d1696ee70f26a68c64a1e1ba1f8fc32b5e6f7..a194bf675e4e26b550414dbec3dfc510d6b0c95e 100644 (file)
@@ -403,12 +403,15 @@ factor_out_conditional_operation (edge e0, edge e1, basic_block merge,
       if (dominated_by_p (CDI_DOMINATORS, gimple_bb (phi), gimple_bb (arg0_def_stmt)))
        return false;
 
-      /* Only handle if arg1 is a INTEGER_CST and one that fits
-        into the new type or if it is the same precision.  */
+      /* If arg1 is an INTEGER_CST, fold it to new type if it fits, or else
+        if the bits will not be modified during the conversion, except for
+        boolean types whose precision is not 1 (see int_fits_type_p).  */
       if (!INTEGRAL_TYPE_P (TREE_TYPE (new_arg0))
          || !(int_fits_type_p (arg1, TREE_TYPE (new_arg0))
               || (TYPE_PRECISION (TREE_TYPE (new_arg0))
-                  == TYPE_PRECISION (TREE_TYPE (arg1)))))
+                  == TYPE_PRECISION (TREE_TYPE (arg1))
+                  && (TREE_CODE (TREE_TYPE (new_arg0)) != BOOLEAN_TYPE
+                      || TYPE_PRECISION (TREE_TYPE (new_arg0)) == 1))))
        return false;
 
       /* For the INTEGER_CST case, we are just moving the