Hello, 

among other things, IPA-SRA checks whether splitting out a bit of an
aggregate or something passed by reference would lead into a clash
with an already known IPA-CP constant a way which would cause problems
later on.  Unfortunately the test is done only in
adjust_parameter_descriptions and is missing when accesses are
propagated from callees to callers, which leads to miscompilation
reported as PR 118243 (where the callee is a function created by
ipa-split).

The matter is then further complicated by the fact that we consider
complex numbers as scalars even though they can be modified piecemeal
(IPA-CP can detect and propagate the pieces separately too) which then
confuses the parameter manipulation machinery furter.

This patch simply adds the missing check to avoid the IPA-SRA
transform in these cases too, which should be suitable for backporting
to all affected release branches.  It is a bit of a shame as in the PR
testcase we do propagate both components of the complex number in
question and the transformation phase could recover.  I have some
prototype patches in this direction but that is something for (a)
stage 1.

Bootstrapped and tested on x86_64-linux.  OK for master and (assuming it
applies cleanly and passes the checks there too) to all active release
branches?

Thanks,

Martin


gcc/ChangeLog:

2025-02-10  Martin Jambor  <mjam...@suse.cz>

        PR ipa/118243
        * ipa-sra.cc (pull_accesses_from_callee): New parameters
        caller_ipcp_ts and param_idx.  Check that scalar pulled accesses would
        not clash with a known IPA-CP aggregate constant.
        (param_splitting_across_edge): Pass IPA-CP transformation summary and
        caller parameter index to pull_accesses_from_callee.

gcc/testsuite/ChangeLog:

2025-02-10  Martin Jambor  <mjam...@suse.cz>

        PR ipa/118243
        * g++.dg/ipa/pr118243.C: New test.
---
 gcc/ipa-sra.cc                      | 38 +++++++++++++++++++--------
 gcc/testsuite/g++.dg/ipa/pr118243.C | 40 +++++++++++++++++++++++++++++
 2 files changed, 68 insertions(+), 10 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ipa/pr118243.C

diff --git a/gcc/ipa-sra.cc b/gcc/ipa-sra.cc
index ad80d22f8ce..5d1703ed394 100644
--- a/gcc/ipa-sra.cc
+++ b/gcc/ipa-sra.cc
@@ -3640,15 +3640,19 @@ enum acc_prop_kind {ACC_PROP_DONT, ACC_PROP_COPY, 
ACC_PROP_CERTAIN};
 
 /* Attempt to propagate all definite accesses from ARG_DESC to PARAM_DESC,
    (which belongs to CALLER) if they would not violate some constraint there.
-   If successful, return NULL, otherwise return the string reason for failure
-   (which can be written to the dump file).  DELTA_OFFSET is the known offset
-   of the actual argument withing the formal parameter (so of ARG_DESCS within
-   PARAM_DESCS), ARG_SIZE is the size of the actual argument or zero, if not
-   known. In case of success, set *CHANGE_P to true if propagation actually
-   changed anything.  */
+   CALLER_IPCP_TS describes the caller, PARAM_IDX is the index of the parameter
+   described by PARAM_DESC.  If successful, return NULL, otherwise return the
+   string reason for failure (which can be written to the dump file).
+   DELTA_OFFSET is the known offset of the actual argument withing the formal
+   parameter (so of ARG_DESCS within PARAM_DESCS), ARG_SIZE is the size of the
+   actual argument or zero, if not known. In case of success, set *CHANGE_P to
+   true if propagation actually changed anything.  */
 
 static const char *
-pull_accesses_from_callee (cgraph_node *caller, isra_param_desc *param_desc,
+pull_accesses_from_callee (cgraph_node *caller,
+                          ipcp_transformation *caller_ipcp_ts,
+                          int param_idx,
+                          isra_param_desc *param_desc,
                           isra_param_desc *arg_desc,
                           unsigned delta_offset, unsigned arg_size,
                           bool *change_p)
@@ -3673,6 +3677,17 @@ pull_accesses_from_callee (cgraph_node *caller, 
isra_param_desc *param_desc,
        continue;
 
       unsigned offset = argacc->unit_offset + delta_offset;
+
+      if (caller_ipcp_ts && !AGGREGATE_TYPE_P (argacc->type))
+       {
+         ipa_argagg_value_list avl (caller_ipcp_ts);
+         tree value = avl.get_value (param_idx, offset);
+         if (value && ((tree_to_uhwi (TYPE_SIZE (TREE_TYPE (value)))
+                        / BITS_PER_UNIT)
+                       != argacc->unit_size))
+           return " propagated access would conflict with an IPA-CP constant";
+       }
+
       /* Given that accesses are initially stored according to increasing
         offset and decreasing size in case of equal offsets, the following
         searches could be written more efficiently if we kept the ordering
@@ -3781,6 +3796,8 @@ param_splitting_across_edge (cgraph_edge *cs)
   cgraph_node *callee = cs->callee->function_symbol (&availability);
   isra_func_summary *from_ifs = func_sums->get (cs->caller);
   gcc_checking_assert (from_ifs && from_ifs->m_parameters);
+  ipcp_transformation *caller_ipcp_ts
+    = ipcp_get_transformation_summary (cs->caller);
 
   isra_call_summary *csum = call_sums->get (cs);
   gcc_checking_assert (csum);
@@ -3851,8 +3868,8 @@ param_splitting_across_edge (cgraph_edge *cs)
          else
            {
              const char *pull_failure
-               = pull_accesses_from_callee (cs->caller, param_desc, arg_desc,
-                                            0, 0, &res);
+               = pull_accesses_from_callee (cs->caller, caller_ipcp_ts, idx,
+                                            param_desc, arg_desc, 0, 0, &res);
              if (pull_failure)
                {
                  if (dump_file && (dump_flags & TDF_DETAILS))
@@ -3913,7 +3930,8 @@ param_splitting_across_edge (cgraph_edge *cs)
          else
            {
              const char *pull_failure
-               = pull_accesses_from_callee (cs->caller, param_desc, arg_desc,
+               = pull_accesses_from_callee (cs->caller, caller_ipcp_ts, idx,
+                                            param_desc, arg_desc,
                                             ipf->unit_offset,
                                             ipf->unit_size, &res);
              if (pull_failure)
diff --git a/gcc/testsuite/g++.dg/ipa/pr118243.C 
b/gcc/testsuite/g++.dg/ipa/pr118243.C
new file mode 100644
index 00000000000..5efaa276da1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ipa/pr118243.C
@@ -0,0 +1,40 @@
+/* { dg-do run } */
+/* { dg-options "-O3 -std=gnu++11" } */
+
+using complex_t = int __complex__;
+
+struct A {
+    complex_t value;
+    A(double r) : value{0, r} {}
+};
+
+[[gnu::noipa]]
+void f(int a)
+{
+  if (a != 1)
+    __builtin_abort();
+}
+[[gnu::noipa]] void g(const char *, int x){}
+
+
+void test(const complex_t &c, const int &x) {
+    if (x < 0)
+        g("%d\n", x);
+    else
+    {
+        f( __imag__ c);
+    }
+}
+
+void f1() {
+    {
+        A a{1};
+        test(a.value, 123);
+    }
+}
+
+int main()
+{
+        f1();
+       return 0;
+}
-- 
2.47.1

Reply via email to