aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-inline.cc
diff options
context:
space:
mode:
authorEric Botcazou <ebotcazou@adacore.com>2024-10-01 17:54:00 +0200
committerEric Botcazou <ebotcazou@adacore.com>2024-10-01 18:03:38 +0200
commitbe2f7a1871ae7a256f34393eeba583ff575cb7e8 (patch)
tree51380cc7070b2ad2842c3f7fc7a7a0c735ce9583 /gcc/tree-inline.cc
parent97fd777248f3c22f6baa5a25f25f7dd510ca5e63 (diff)
downloadgcc-be2f7a1871ae7a256f34393eeba583ff575cb7e8.zip
gcc-be2f7a1871ae7a256f34393eeba583ff575cb7e8.tar.gz
gcc-be2f7a1871ae7a256f34393eeba583ff575cb7e8.tar.bz2
Fix wrong code out of NRV + RSO + inlining
The testcase is miscompiled with -O -flto beccause the three optimizations NRV + RSO + inlining are applied to the same call: when the LHS of the call is marked write-only before inlining, it will keep the mark after inlining although it may be read in GIMPLE from that point on. The fix is to apply the removal of the store, that would have been applied later if the call was not inlined, right before inlining, which will prevent the problematic references to the LHS from being generated during inlining. gcc/ * tree-inline.cc (expand_call_inline): Remove the store to the return slot if it is a global variable that is only written to. gcc/testsuite/ * gnat.dg/lto28.adb: New test. * gnat.dg/lto28_pkg1.ads: New helper. * gnat.dg/lto28_pkg2.ads: Likewise. * gnat.dg/lto28_pkg2.adb: Likewise. * gnat.dg/lto28_pkg3.ads: Likewise.
Diffstat (limited to 'gcc/tree-inline.cc')
-rw-r--r--gcc/tree-inline.cc16
1 files changed, 15 insertions, 1 deletions
diff --git a/gcc/tree-inline.cc b/gcc/tree-inline.cc
index f31a34a..037fd1e 100644
--- a/gcc/tree-inline.cc
+++ b/gcc/tree-inline.cc
@@ -5130,9 +5130,23 @@ expand_call_inline (basic_block bb, gimple *stmt, copy_body_data *id,
if (DECL_P (modify_dest))
suppress_warning (modify_dest, OPT_Wuninitialized);
+ /* If we have a return slot, we can assign it the result directly,
+ except in the case where it is a global variable that is only
+ written to because, the callee being permitted to read or take
+ the address of its DECL_RESULT, this could invalidate the flag
+ on the global variable; instead we preventively remove the store,
+ which would have happened later if the call was not inlined. */
if (gimple_call_return_slot_opt_p (call_stmt))
{
- return_slot = modify_dest;
+ tree base = get_base_address (modify_dest);
+
+ if (VAR_P (base)
+ && (TREE_STATIC (base) || DECL_EXTERNAL (base))
+ && varpool_node::get (base)->writeonly)
+ return_slot = NULL;
+ else
+ return_slot = modify_dest;
+
modify_dest = NULL;
}
}