https://gcc.gnu.org/g:46520c0d388611586452cce8843d0d466eb4bb10

commit r16-7924-g46520c0d388611586452cce8843d0d466eb4bb10
Author: Jakub Jelinek <[email protected]>
Date:   Fri Mar 6 10:32:00 2026 +0100

    tree-inline: Fix up ICE on !is_gimple_reg is_gimple_reg_type copying 
[PR124135]
    
    The first testcase below ICEs e.g. with -O2 on s390x-linux, the
    second with -O2 -m32 on x86_64-linux.  We have
      <bb 2> [local count: 1073741824]:
      if (x_4(D) != 0)
        goto <bb 3>; [33.00%]
      else
        goto <bb 4>; [67.00%]
    
      <bb 3> [local count: 354334800]:
      _7 = qux (42);
      foo (0, &<retval>, _7);
    
      <bb 4> [local count: 1073741824]:
      return <retval>;
    on a target where <retval> has gimple reg type but is
    aggregate_value_p and TREE_ADDRESSABLE too.
    fnsplit splits this into
      <bb 2> [local count: 354334800]:
      _1 = qux (42);
      foo (0, &<retval>, _1);
    
      <bb 3> [local count: 354334800]:
      return <retval>;
    in the *.part.0 function and
      if (x_4(D) != 0)
        goto <bb 3>; [33.00%]
      else
        goto <bb 4>; [67.00%]
    
      <bb 3> [local count: 354334800]:
      <retval> = _Z3bari.part.0 ();
    
      <bb 4> [local count: 1073741824]:
      return <retval>;
    in the original function.  Now, dunno if already that isn't
    invalid because <retval> has TREE_ADDRESSABLE set in the latter, but
    at least it is accepted by tree-cfg.cc verification.
      tree lhs = gimple_call_lhs (stmt);
      if (lhs
          && (!is_gimple_reg (lhs)
              && (!is_gimple_lvalue (lhs)
                  || verify_types_in_gimple_reference
                       (TREE_CODE (lhs) == WITH_SIZE_EXPR
                        ? TREE_OPERAND (lhs, 0) : lhs, true))))
        {
          error ("invalid LHS in gimple call");
          return true;
        }
    While lhs is not is_gimple_reg, it is is_gimple_lvalue here.
    Now, inlining of the *.part.0 fn back into the original results
    in
      <retval> = a;
    statement which already is diagnosed by verify_gimple_assign_single:
        case VAR_DECL:
        case PARM_DECL:
          if (!is_gimple_reg (lhs)
              && !is_gimple_reg (rhs1)
              && is_gimple_reg_type (TREE_TYPE (lhs)))
            {
              error ("invalid RHS for gimple memory store: %qs", code_name);
              debug_generic_stmt (lhs);
              debug_generic_stmt (rhs1);
              return true;
            }
    __float128/long double are is_gimple_reg_type, but both operands
    aren't is_gimple_reg.
    
    The following patch fixes it by doing separate load and store, i.e.
      _42 = a;
      <retval> = 42;
    in this case.  If we want to change verify_gimple_assign to disallow
    !is_gimple_reg (lhs) for is_gimple_reg_type (TREE_TYPE (lhs)), we'd
    need to change fnsplit instead, but I'd be afraid such a change would
    be more stage1 material (and certainly nothing that should be
    even backported to release branches).
    
    2026-03-05  Jakub Jelinek  <[email protected]>
    
            PR tree-optimization/124135
            * tree-inline.cc (expand_call_inline): If both gimple_call_lhs 
(stmt)
            and use_retvar aren't gimple regs but have gimple reg type, use
            separate load of use_retva into SSA_NAME and then store of it
            into gimple_call_lhs (stmt).
    
            * g++.dg/torture/pr124135-1.C: New test.
            * g++.dg/torture/pr124135-2.C: New test.

Diff:
---
 gcc/testsuite/g++.dg/torture/pr124135-1.C | 20 ++++++++++++++++++++
 gcc/testsuite/g++.dg/torture/pr124135-2.C | 27 +++++++++++++++++++++++++++
 gcc/tree-inline.cc                        | 15 ++++++++++++++-
 3 files changed, 61 insertions(+), 1 deletion(-)

diff --git a/gcc/testsuite/g++.dg/torture/pr124135-1.C 
b/gcc/testsuite/g++.dg/torture/pr124135-1.C
new file mode 100644
index 000000000000..bf2d54e1a061
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/pr124135-1.C
@@ -0,0 +1,20 @@
+// PR tree-optimization/124135
+// { dg-do compile }
+
+void foo (char, long double *, int);
+int qux (int);
+
+long double
+bar (int x)
+{
+  long double a;
+  if (x)
+    foo (0, &a, qux (42));
+  return a;
+}
+
+void
+baz (int x)
+{
+  bar (x);
+}
diff --git a/gcc/testsuite/g++.dg/torture/pr124135-2.C 
b/gcc/testsuite/g++.dg/torture/pr124135-2.C
new file mode 100644
index 000000000000..4cd46e15cdeb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/pr124135-2.C
@@ -0,0 +1,27 @@
+// PR tree-optimization/124135
+// { dg-do compile }
+
+#ifdef __SIZEOF_FLOAT128__
+void foo (char, __float128 *, int);
+int qux (int);
+
+__float128
+bar (int x)
+{
+  __float128 a;
+  if (x)
+    foo (0, &a, qux (42));
+  return a;
+}
+
+void
+baz (int x)
+{
+  bar (x);
+}
+#else
+void
+baz ()
+{
+}
+#endif
diff --git a/gcc/tree-inline.cc b/gcc/tree-inline.cc
index 3ae342402fd6..98ef6310d063 100644
--- a/gcc/tree-inline.cc
+++ b/gcc/tree-inline.cc
@@ -5336,7 +5336,20 @@ expand_call_inline (basic_block bb, gimple *stmt, 
copy_body_data *id,
   if (use_retvar && gimple_call_lhs (stmt))
     {
       gimple *old_stmt = stmt;
-      stmt = gimple_build_assign (gimple_call_lhs (stmt), use_retvar);
+      tree lhs = gimple_call_lhs (stmt);
+      if (!is_gimple_reg (lhs)
+         && !is_gimple_reg (use_retvar)
+         && is_gimple_reg_type (TREE_TYPE (lhs)))
+       {
+         /* If both lhs and use_retvar aren't gimple regs, yet have
+            gimple reg type, copy through a temporary SSA_NAME.  */
+         gimple *g = gimple_build_assign (make_ssa_name (TREE_TYPE (lhs)),
+                                          use_retvar);
+         gimple_set_location (g, gimple_location (old_stmt));
+         gsi_insert_before (&stmt_gsi, g, GSI_SAME_STMT);
+         use_retvar = gimple_assign_lhs (g);
+       }
+      stmt = gimple_build_assign (lhs, use_retvar);
       gimple_set_location (stmt, gimple_location (old_stmt));
       gsi_replace (&stmt_gsi, stmt, false);
       maybe_clean_or_replace_eh_stmt (old_stmt, stmt);

Reply via email to