Hi,

the attached Ada testcase compiled with -O -flto exhibits a wrong code issue 
when the 3 optimizations NRV + RSO + inlining are applied to the same call: if 
the LHS of the call is marked write-only before inlining, then it will keep 
the mark after inlining although it may be read in GIMPLE from that point on.

The proposed fix is to always clear the flag during inlining in the RSO case.
Tested on x86-64/Linux, OK for the mainline?


2024-09-11  Eric Botcazou  <ebotca...@adacore.com>

        * tree-inline.cc (declare_return_variable): Clear writeonly flag on
        a global variable used directly as the return slot.

2024-09-11  Eric Botcazou  <ebotca...@adacore.com>

        * gnat.dg/lto27.adb: New test.
        * gnat.dg/lto27_pkg1.ads, gnat.dg/lto27_pkg2.ads,
        gnat.dg/lto27_pkg2.adb, gnat.dg/lto27_pkg3.ads: New helper.


-- 
Eric Botcazou
diff --git a/gcc/tree-inline.cc b/gcc/tree-inline.cc
index f31a34ac410..2bb1e1602b2 100644
--- a/gcc/tree-inline.cc
+++ b/gcc/tree-inline.cc
@@ -3782,6 +3782,11 @@ declare_return_variable (copy_body_data *id, tree return_slot, tree modify_dest,
 	  gcc_assert (TREE_CODE (var) != SSA_NAME);
 	  if (TREE_ADDRESSABLE (result))
 	    mark_addressable (var);
+	  /* RESULT may also be read in the callee, typically because the NRV
+	     optimization has been applied to the function, so VAR may also be
+	     read from now on.  */
+	  if (VAR_P (var) && (TREE_STATIC (var) || DECL_EXTERNAL (var)))
+	    varpool_node::get (var)->writeonly = 0;
 	}
       if (DECL_NOT_GIMPLE_REG_P (result)
 	  && DECL_P (var))
-- { dg-do run }
-- { dg-options "-O -flto" { target lto } }

with Lto27_Pkg1;

procedure Lto27 is
begin
   null;
end;
with Lto27_Pkg2;

package Lto27_Pkg1 is
   package I is new Lto27_Pkg2.G;
end Lto27_Pkg1;
package body Lto27_Pkg2 is

   function F return Lto27_Pkg3.Q_Rec is
   begin
      return Result : Lto27_Pkg3.Q_Rec := Lto27_Pkg3.Default_Q_Rec do
         Result.A := 1.0;
      end return;
   end;

end Lto27_Pkg2;
with Lto27_Pkg3;

package Lto27_Pkg2 is

   function F return Lto27_Pkg3.Q_Rec;

   generic
      Q_Conf : Lto27_Pkg3.Q_Rec := F;
   package G is end;

end Lto27_Pkg2;
package Lto27_Pkg3 is

   type Discr_Type is (P, Q);

   type Rec (Discr : Discr_Type) is record
      case Discr is
         when Q =>
            A : Duration := 0.0;
            B : Duration := 0.0;
         when P =>
            null;
      end case;
   end record;

   subtype Q_Rec is Rec (Q);

   Default_Q_Rec : constant Q_Rec := (Discr => Q, others => <>);

end Lto27_Pkg3;

Reply via email to