]> 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:24:48 +0000 (22:24 +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 b8c5cc0e0d30c740aad95089024d0747878f3737..89236637a59173dd8dc892537e45f93ef3377660 100644 (file)
@@ -319,11 +319,16 @@ factor_out_conditional_operation (edge e0, edge e1, gphi *phi,
       /* arg0_def_stmt should be conditional.  */
       if (dominated_by_p (CDI_DOMINATORS, gimple_bb (phi), gimple_bb (arg0_def_stmt)))
        return NULL;
-      /* If arg1 is an INTEGER_CST, fold it to new type.  */
+
+      /* 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))))
        {
          if (gimple_assign_cast_p (arg0_def_stmt))
            {
@@ -340,7 +345,7 @@ factor_out_conditional_operation (edge e0, edge e1, gphi *phi,
                 it will not generate any zero/sign extend in that case.  */
              if ((TYPE_PRECISION (TREE_TYPE (new_arg0))
                    != TYPE_PRECISION (TREE_TYPE (arg1)))
-                 && new_arg0 != gimple_cond_lhs (cond_stmt)
+                 && new_arg0 != gimple_cond_lhs (cond_stmt)
                  && new_arg0 != gimple_cond_rhs (cond_stmt)
                  && gimple_bb (arg0_def_stmt) == e0->src)
                {