]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Refine COND_EXPR ranges better.
authorAndrew MacLeod <amacleod@redhat.com>
Fri, 24 Oct 2025 19:09:51 +0000 (15:09 -0400)
committerAndrew MacLeod <amacleod@redhat.com>
Fri, 24 Oct 2025 21:36:28 +0000 (17:36 -0400)
Recognize COND_EXPRs where there is only one ssa_name used in the
condition as well as one of the fields in the COND_EXPR.  ie:

  cond = ssa_name < 20
  result = cond ? ssa_name : 20

Adjust the range of ssa_name to reflect the conditional value of ssa_name
relative to whether its in the TRUE or FALSE part of the COND_EXPR.

PR tree-optimization/114025
gcc/
* gimple-range-fold.cc (fold_using_range::condexpr_adjust): Handle
the same ssa_name in the condition and the COND_EXPR better.

gcc/testsuite/
* g++.dg/pr114025.C: New.

gcc/gimple-range-fold.cc
gcc/testsuite/g++.dg/pr114025.C [new file with mode: 0644]

index d18b37b33800e978e61121790153e1d4fd53ce22..06c645f3d08174f64a68aceba3f89b10e03596f7 100644 (file)
@@ -1187,6 +1187,17 @@ fold_using_range::condexpr_adjust (vrange &r1, vrange &r2, gimple *, tree cond,
          ssa2, src))
        r2.intersect (tmp2);
     }
+  // If the same name is specified in the condition and COND_EXPR,
+  // combine the calculated condition range and the other one provided. ie:
+  // c_1 = b_2 < 10
+  // f_3 = c_1 ? 0 : b_2
+  // With b_2 providing the false value, the value of f_3 will be
+  // either 0 UNION  (0 = b_2 < 10), which is [-INF, 9].
+  // COND_EXPR is
+  if (ssa1 && cond_name == ssa1)
+    r1 = cond_true;
+  else if (ssa2 && cond_name == ssa2)
+    r2 = cond_false;
   return true;
 }
 
diff --git a/gcc/testsuite/g++.dg/pr114025.C b/gcc/testsuite/g++.dg/pr114025.C
new file mode 100644 (file)
index 0000000..61bb8f1
--- /dev/null
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options " -O3 -std=gnu++17 -ffinite-math-only -fdump-tree-optimized" } */
+
+#include <algorithm>
+#include <stdexcept>
+
+#define AINLINE
+
+class TestClass
+{
+public:
+    AINLINE void SetValue(float value);
+
+private:
+    float m_Value;
+};
+
+AINLINE
+void TestClass::SetValue(float value)
+{
+    if (value >= 0.0f && value <= 100.0f) {
+        m_Value = value;
+    }
+    else {
+        throw std::out_of_range("Value must be [0, 100].");
+    }
+}
+
+void TestFunc(TestClass& t, float value)
+{
+    value = std::clamp(value, 30.0f, 50.0f);
+    // When TestClass::SetValue is inlined, the exception throwing code is not eliminated.
+    // Given that at this point we can prove that 'value' lies in the range [30.0f, 50.0f] well within the range required by the setter function, we can rid the not taken paths of code.
+    t.SetValue(value);
+}
+
+
+/* { dg-final { scan-tree-dump-times "std::out_of_range::out_of_range" 1 "optimized" } } */
+