https://gcc.gnu.org/g:684c9811dee6573fdb8b01c9bef16e68054fc87c

commit r17-5633-g684c9811dee6573fdb8b01c9bef16e68054fc87c
Author: Josef Melcr <[email protected]>
Date:   Wed Sep 16 13:54:18 2026 +0200

    ipa: Create a callback edge when encountering an internal .ASSUME call
    
    This patch adds logic which creates an internal callback edge when it
    encounters an IFN_ASSUME internal call.  It acts as a trigger for most
    of the patches in this series.  ipa_compute_jump_functions_for_edge has
    to be called separately for the new edge, as all jump functions would
    have been computed at this point in the code.  I squashed the patch
    adding testcases into this commit.
    
            PR ipa/109112
    
    gcc/ChangeLog:
    
            * ipa-prop.cc (ipa_analyze_call_uses): Create an internal
            callback edge when dealing with a .ASSUME internal call.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/ipa/ipa-cp-assume-2.C: New test.
            * g++.dg/ipa/ipa-cp-assume-3.C: New test.
            * g++.dg/ipa/ipa-cp-assume.C: New test.
            * g++.dg/ipa/ipa-sra-assume-2.C: New test.
            * g++.dg/ipa/ipa-sra-assume-3.C: New test.
            * g++.dg/ipa/ipa-sra-assume.C: New test.
            * g++.dg/lto/ipa-cp-assume_0.C: New test.
            * g++.dg/lto/ipa-cp-assume_1.C: New test.
            * g++.dg/lto/ipa-sra-assume_0.C: New test.
            * g++.dg/lto/ipa-sra-assume_1.C: New test.
            * g++.dg/lto/ipa-cp-assume-1_0.C: New test.
            * g++.dg/lto/ipa-cp-assume-2_0.C: New test.
            * g++.dg/lto/ipa-cp-assume-3_0.C: New test.
            * g++.dg/lto/ipa-sra-assume-1_0.C: New test.
            * g++.dg/lto/ipa-sra-assume-2_0.C: New test.
            * g++.dg/lto/ipa-sra-assume-3_0.C: New test.
    
    Signed-off-by: Josef Melcr <[email protected]>

Diff:
---
 gcc/ipa-prop.cc                               | 13 +++++++
 gcc/testsuite/g++.dg/ipa/ipa-cp-assume-2.C    | 40 +++++++++++++++++++++
 gcc/testsuite/g++.dg/ipa/ipa-cp-assume-3.C    | 51 +++++++++++++++++++++++++++
 gcc/testsuite/g++.dg/ipa/ipa-cp-assume.C      | 26 ++++++++++++++
 gcc/testsuite/g++.dg/ipa/ipa-sra-assume-2.C   | 33 +++++++++++++++++
 gcc/testsuite/g++.dg/ipa/ipa-sra-assume-3.C   | 34 ++++++++++++++++++
 gcc/testsuite/g++.dg/ipa/ipa-sra-assume.C     | 37 +++++++++++++++++++
 gcc/testsuite/g++.dg/lto/ipa-cp-assume-1_0.C  | 16 +++++++++
 gcc/testsuite/g++.dg/lto/ipa-cp-assume-2_0.C  | 16 +++++++++
 gcc/testsuite/g++.dg/lto/ipa-cp-assume-3_0.C  | 18 ++++++++++
 gcc/testsuite/g++.dg/lto/ipa-cp-assume_0.C    | 27 ++++++++++++++
 gcc/testsuite/g++.dg/lto/ipa-cp-assume_1.C    | 13 +++++++
 gcc/testsuite/g++.dg/lto/ipa-sra-assume-1_0.C | 22 ++++++++++++
 gcc/testsuite/g++.dg/lto/ipa-sra-assume-2_0.C |  6 ++++
 gcc/testsuite/g++.dg/lto/ipa-sra-assume-3_0.C |  6 ++++
 gcc/testsuite/g++.dg/lto/ipa-sra-assume_0.C   | 28 +++++++++++++++
 gcc/testsuite/g++.dg/lto/ipa-sra-assume_1.C   | 11 ++++++
 17 files changed, 397 insertions(+)

diff --git a/gcc/ipa-prop.cc b/gcc/ipa-prop.cc
index 54c40691932b..c614ddccbbb0 100644
--- a/gcc/ipa-prop.cc
+++ b/gcc/ipa-prop.cc
@@ -3214,6 +3214,19 @@ ipa_analyze_call_uses (struct ipa_func_body_info *fbi, 
gcall *call)
 {
   tree target = gimple_call_fn (call);
 
+  /* Internal .ASSUME call.  Create a callback edge to its body, calculate its
+     jump functions and return.  This is done here as the main creation route 
in
+     ipa_compute_jump_functions_for_edge doesn't analyze call statements.  */
+  if (callback_ifn_assume_call_p (call))
+    {
+      tree callee_decl = TREE_OPERAND (gimple_call_arg (call, 0), 0);
+      cgraph_node *target = cgraph_node::get_create (callee_decl);
+      cgraph_edge *cbei
+       = cgraph_edge::make_callback_internal (fbi->node, target, call);
+      ipa_compute_jump_functions_for_edge (fbi, cbei);
+      return;
+    }
+
   if (!target
       || (TREE_CODE (target) != SSA_NAME
           && !virtual_method_call_p (target)))
diff --git a/gcc/testsuite/g++.dg/ipa/ipa-cp-assume-2.C 
b/gcc/testsuite/g++.dg/ipa/ipa-cp-assume-2.C
new file mode 100644
index 000000000000..d9f7af46ec9f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ipa/ipa-cp-assume-2.C
@@ -0,0 +1,40 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fdump-ipa-cp-details -fdump-tree-optimized" } */
+
+/* Should propagate in chain baz -> foo -> assume and fold body of foo
+   accordingly.  Works because bar can be inlined (otherwise we can't derive 
the
+   value range for x).  */
+
+void do_something ();
+
+inline bool
+bar (int x, int y)
+{
+  return x < y;
+}
+
+static bool __attribute__ ((noinline))
+foo (int x, int a)
+{
+  [[assume (bar (x, a))]];
+  bool ret = x < 42;
+
+  if (!__builtin_constant_p (ret))
+    __builtin_abort ();
+
+  return ret;
+}
+
+void
+baz (int x)
+{
+  bool should_do_something = false;
+  for (int i = 0; i < 1000000; i++)
+    should_do_something = foo (x, 42);
+
+  if (!should_do_something)
+    do_something ();
+}
+
+/* { dg-final { scan-ipa-dump-times "replacing param #1 a with const 42" 2 
"cp" } } */
+/* { dg-final { scan-tree-dump-not "abort" "optimized" } } */
diff --git a/gcc/testsuite/g++.dg/ipa/ipa-cp-assume-3.C 
b/gcc/testsuite/g++.dg/ipa/ipa-cp-assume-3.C
new file mode 100644
index 000000000000..4b79480b4f3b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ipa/ipa-cp-assume-3.C
@@ -0,0 +1,51 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fdump-ipa-cp-details -fdump-ipa-sra-details 
-fdump-tree-optimized" } */
+
+/* Should propagate baz -> foo -> assume, split the parameter, derive the range
+   for s->x and fold foo accordingly.  */
+
+void something ();
+
+struct S
+{
+  int x, y;
+};
+
+inline bool
+bar (int x, int y)
+{
+  return x < y;
+}
+
+static bool __attribute__ ((noinline))
+foo (struct S *s)
+{
+  [[assume (bar (s->x, s->y))]];
+  bool ret = s->x < 42;
+  bool ahoj = s->x < s->y;
+
+  if (!__builtin_constant_p (ret))
+    __builtin_abort ();
+
+  if (!__builtin_constant_p (ahoj))
+    __builtin_abort ();
+
+  return ret;
+}
+
+void
+baz (int x)
+{
+  struct S s;
+  s.x = x;
+  s.y = 42;
+  bool shouldnt_do_something = foo (&s);
+
+  if (!shouldnt_do_something)
+    something ();
+}
+
+/* { dg-final { scan-ipa-dump "Aggregate replacements: 0\\\[4]=42" "cp" } } */
+/* { dg-final { scan-ipa-dump ".*assume.*constprop.* Will split parameter 0" 
"sra" } } */
+/* { dg-final { scan-ipa-dump "assume.*constprop\\.isra" "sra" } } */
+/* { dg-final { scan-tree-dump-not "abort" "optimized" } } */
diff --git a/gcc/testsuite/g++.dg/ipa/ipa-cp-assume.C 
b/gcc/testsuite/g++.dg/ipa/ipa-cp-assume.C
new file mode 100644
index 000000000000..6eeebd4ad5c8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ipa/ipa-cp-assume.C
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fdump-ipa-cp-details -fdump-tree-optimized" } */
+
+/* Should propagate 'a' into the assume body and fold foo.  */
+
+inline bool
+bar (int x, int y)
+{
+  return x < y;
+}
+
+bool
+foo (int x)
+{
+  int a = 42;
+  [[assume (bar (x, a))]];
+  bool ret = x < 42;
+
+  if (!__builtin_constant_p (ret))
+    __builtin_abort ();
+
+  return ret;
+}
+
+/* { dg-final { scan-ipa-dump "replacing param #1 a with const 42" "cp" } } */
+/* { dg-final { scan-tree-dump-not "abort" "optimized" } } */
diff --git a/gcc/testsuite/g++.dg/ipa/ipa-sra-assume-2.C 
b/gcc/testsuite/g++.dg/ipa/ipa-sra-assume-2.C
new file mode 100644
index 000000000000..009b315ac42b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ipa/ipa-sra-assume-2.C
@@ -0,0 +1,33 @@
+/* Test that the assume can be copied before creating the edges.  */
+
+/* { dg-do compile } */
+/* { dg-options "-O3" } */
+
+struct S
+{
+  int x, y;
+};
+
+inline bool
+baz (S x)
+{
+  return x.x < 42;
+}
+
+inline bool
+qux (S x, int h)
+{
+  [[assume (baz (x))]];
+  return x.x < 42 && x.y > 52 && h < 50;
+}
+
+void
+corge (S x, S y, S z, bool *p)
+{
+  for (int i = 0; i < x.x + x.y; i++)
+    {
+      p[0] = qux (x, 41);
+      p[1] = qux (y, 60);
+      p[2] = qux (z, 20);
+    }
+}
diff --git a/gcc/testsuite/g++.dg/ipa/ipa-sra-assume-3.C 
b/gcc/testsuite/g++.dg/ipa/ipa-sra-assume-3.C
new file mode 100644
index 000000000000..fd15c957794a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ipa/ipa-sra-assume-3.C
@@ -0,0 +1,34 @@
+/* Test that the assume can be copied after creating the edges.  */
+
+/* { dg-do compile } */
+/* { dg-options "-O3 -fno-early-inlining" } */
+
+struct S
+{
+  int x, y;
+};
+
+inline bool
+baz (S x)
+{
+  return x.x < 42;
+}
+
+[[gnu::always_inline]]
+inline bool
+qux (S x, int h)
+{
+  [[assume (baz (x))]];
+  return x.x < 42 && x.y > 52 && h < 50;
+}
+
+void
+corge (S x, S y, S z, bool *p)
+{
+  for (int i = 0; i < x.x + x.y; i++)
+    {
+      p[0] = qux (x, 41);
+      p[1] = qux (y, 60);
+      p[2] = qux (z, 20);
+    }
+}
diff --git a/gcc/testsuite/g++.dg/ipa/ipa-sra-assume.C 
b/gcc/testsuite/g++.dg/ipa/ipa-sra-assume.C
new file mode 100644
index 000000000000..91b6366eb6af
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ipa/ipa-sra-assume.C
@@ -0,0 +1,37 @@
+/* Test that ipa-sra can  work with .ASSUME outlined bodies.  */
+
+/* { dg-do compile } */
+/* { dg-options "-O2 -fipa-sra -fdump-ipa-sra-details -fdump-tree-optimized" } 
*/
+
+struct S
+{
+  bool x;
+  int y;
+};
+
+void
+split_struct (struct S s)
+{
+  [[assume (!s.x)]];
+  if (s.x)
+    __builtin_abort ();
+}
+
+void
+remove_ptr (bool *x)
+{
+  [[assume (!*x)]];
+  if (*x)
+    __builtin_abort ();
+}
+
+void
+two_values (struct S s)
+{
+  [[assume (s.y == 3 || s.y == 4)]];
+  if (s.y == 5)
+    __builtin_abort ();
+}
+
+/* { dg-final { scan-ipa-dump-times "Will split parameter 0" 3 "sra" } } */
+/* { dg-final { scan-tree-dump-not "abort" "optimized" } } */
diff --git a/gcc/testsuite/g++.dg/lto/ipa-cp-assume-1_0.C 
b/gcc/testsuite/g++.dg/lto/ipa-cp-assume-1_0.C
new file mode 100644
index 000000000000..1111087d8006
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lto/ipa-cp-assume-1_0.C
@@ -0,0 +1,16 @@
+/* { dg-lto-do link } */
+/* { dg-lto-options {{ -O3 -fdump-ipa-cp-details -fdump-tree-optimized -flto 
}} } */
+
+#include "../ipa/ipa-cp-assume.C"
+
+int
+main ()
+{
+  int x;
+  __builtin_scanf ("%d", &x);
+  foo (x);
+  return 0;
+}
+
+/* { dg-final { scan-wpa-ipa-dump "replacing param #1 int with const 42" "cp" 
} } */
+/* { dg-final { scan-ltrans-tree-dump-not "abort" "optimized" } } */
diff --git a/gcc/testsuite/g++.dg/lto/ipa-cp-assume-2_0.C 
b/gcc/testsuite/g++.dg/lto/ipa-cp-assume-2_0.C
new file mode 100644
index 000000000000..caafb9c3c93f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lto/ipa-cp-assume-2_0.C
@@ -0,0 +1,16 @@
+/* { dg-lto-do link } */
+/* { dg-lto-options {{ -O3 -fdump-ipa-cp-details -fdump-tree-optimized -flto 
}} } */
+
+#include "../ipa/ipa-cp-assume-2.C"
+
+int
+main ()
+{
+  int x;
+  __builtin_scanf ("%d", &x);
+  baz (x);
+  return 0;
+}
+
+/* { dg-final { scan-wpa-ipa-dump-times "replacing param #1 int with const 42" 
2 "cp" } } */
+/* { dg-final { scan-ltrans-tree-dump-not "abort" "optimized" } } */
diff --git a/gcc/testsuite/g++.dg/lto/ipa-cp-assume-3_0.C 
b/gcc/testsuite/g++.dg/lto/ipa-cp-assume-3_0.C
new file mode 100644
index 000000000000..8ca3c99d8aa2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lto/ipa-cp-assume-3_0.C
@@ -0,0 +1,18 @@
+/* { dg-lto-do link } */
+/* { dg-lto-options  {{ -O3 -fdump-ipa-cp-details -fdump-ipa-sra-details 
-fdump-tree-optimized -flto }} } */
+
+#include "../ipa/ipa-cp-assume-3.C"
+
+int
+main ()
+{
+  int x;
+  __builtin_scanf ("%d", &x);
+  baz (x);
+  return 0;
+}
+
+/* { dg-final { scan-wpa-ipa-dump "Aggregate replacements: 0\\\[4]=42" "cp" } 
} */
+/* { dg-final { scan-wpa-ipa-dump ".*assume.*constprop.* Will split parameter 
0" "sra" } } */
+/* { dg-final { scan-wpa-ipa-dump "assume.*constprop\\.isra" "sra" } } */
+/* { dg-final { scan-ltrans-tree-dump-not "abort" "optimized" } } */
diff --git a/gcc/testsuite/g++.dg/lto/ipa-cp-assume_0.C 
b/gcc/testsuite/g++.dg/lto/ipa-cp-assume_0.C
new file mode 100644
index 000000000000..3f69250f33b3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lto/ipa-cp-assume_0.C
@@ -0,0 +1,27 @@
+/* { dg-lto-options {{ -O3 -flto -fdump-tree-optimized }} } */
+/* { dg-lto-do link } */
+
+/* The point of this test is to propagate the constant into the assume body in
+   the other file, infer the value range for 'x', evaluate bar to 0, meaning
+   that the loop will never run and the abort would never be executed.  */
+
+int bar (int, int);
+
+void
+foo (int x, int y)
+{
+  int c = bar (x, y);
+  for (int i = 0; i < c; i++)
+    __builtin_abort ();
+}
+
+int
+main ()
+{
+  int x;
+  __builtin_scanf ("%d", &x);
+  foo (x, 67);
+  return 0;
+}
+
+/* { dg-final { scan-ltrans-tree-dump-not "__builtin_abort" "optimized" } } */
diff --git a/gcc/testsuite/g++.dg/lto/ipa-cp-assume_1.C 
b/gcc/testsuite/g++.dg/lto/ipa-cp-assume_1.C
new file mode 100644
index 000000000000..4ac52422d372
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lto/ipa-cp-assume_1.C
@@ -0,0 +1,13 @@
+inline bool
+baz (int x, int y)
+{
+  return x < y;
+}
+
+int
+bar (int x, int y)
+{
+  [[assume (baz (x, y))]];
+  __builtin_printf ("%d %d", x, y);
+  return x > y;
+}
diff --git a/gcc/testsuite/g++.dg/lto/ipa-sra-assume-1_0.C 
b/gcc/testsuite/g++.dg/lto/ipa-sra-assume-1_0.C
new file mode 100644
index 000000000000..5d55efa44975
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lto/ipa-sra-assume-1_0.C
@@ -0,0 +1,22 @@
+/* { dg-lto-do link } */
+/* { dg-lto-options {{ -O2 -fno-inline -fipa-sra -fdump-ipa-sra-details 
-fdump-tree-optimized -flto }} } */
+
+#include "../ipa/ipa-sra-assume.C"
+
+int
+main ()
+{
+  int x, y, z;
+  __builtin_scanf ("%d %d %d", &x, &y, &z);
+
+  struct S s = {.x = (bool) x, .y = y};
+  bool a = z;
+
+  split_struct (s);
+  remove_ptr (&a);
+  two_values (s);
+  return 0;
+}
+
+/* { dg-final { scan-wpa-ipa-dump-times "Will split parameter 0" 6 "sra" } } */
+/* { dg-final { scan-ltrans-tree-dump-not "abort" "optimized" } } */
diff --git a/gcc/testsuite/g++.dg/lto/ipa-sra-assume-2_0.C 
b/gcc/testsuite/g++.dg/lto/ipa-sra-assume-2_0.C
new file mode 100644
index 000000000000..d3d0251ce5da
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lto/ipa-sra-assume-2_0.C
@@ -0,0 +1,6 @@
+/* Test that the assume can be copied before creating the edges.  */
+
+/* { dg-lto-do assemble } */
+/* { dg-lto-options  {{ -O3 -flto }} } */
+
+#include "../ipa/ipa-sra-assume-2.C"
diff --git a/gcc/testsuite/g++.dg/lto/ipa-sra-assume-3_0.C 
b/gcc/testsuite/g++.dg/lto/ipa-sra-assume-3_0.C
new file mode 100644
index 000000000000..432cfcfd5f35
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lto/ipa-sra-assume-3_0.C
@@ -0,0 +1,6 @@
+/* Test that the assume can be copied after creating the edges.  */
+
+/* { dg-lto-do assemble } */
+/* { dg-lto-options  {{ -O3 -fno-early-inlining -flto }} } */
+
+#include "../ipa/ipa-sra-assume-3.C"
diff --git a/gcc/testsuite/g++.dg/lto/ipa-sra-assume_0.C 
b/gcc/testsuite/g++.dg/lto/ipa-sra-assume_0.C
new file mode 100644
index 000000000000..c4de5f86d3c3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lto/ipa-sra-assume_0.C
@@ -0,0 +1,28 @@
+/* { dg-lto-options {{ -O3 -flto -fdump-tree-optimized }} } */
+/* { dg-lto-do link } */
+
+struct S
+{
+  int x;
+};
+
+int bar (struct S);
+
+void
+foo (struct S s)
+{
+  int c = bar (s);
+  for (int i = 0; i < c; i++)
+    __builtin_abort ();
+}
+
+int
+main ()
+{
+  int x;
+  __builtin_scanf ("%d", &x);
+  foo ({x});
+  return 0;
+}
+
+/* { dg-final { scan-ltrans-tree-dump-not "__builtin_abort" "optimized" } } */
diff --git a/gcc/testsuite/g++.dg/lto/ipa-sra-assume_1.C 
b/gcc/testsuite/g++.dg/lto/ipa-sra-assume_1.C
new file mode 100644
index 000000000000..a33ed888a32f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lto/ipa-sra-assume_1.C
@@ -0,0 +1,11 @@
+struct S
+{
+  int x;
+};
+
+int
+bar (struct S s)
+{
+  [[assume (s.x < 0)]];
+  return s.x;
+}

Reply via email to