diff options
author | Eric Botcazou <ebotcazou@adacore.com> | 2024-10-01 17:54:00 +0200 |
---|---|---|
committer | Eric Botcazou <ebotcazou@adacore.com> | 2024-10-01 18:03:38 +0200 |
commit | be2f7a1871ae7a256f34393eeba583ff575cb7e8 (patch) | |
tree | 51380cc7070b2ad2842c3f7fc7a7a0c735ce9583 /gcc/tree-inline.cc | |
parent | 97fd777248f3c22f6baa5a25f25f7dd510ca5e63 (diff) | |
download | gcc-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.cc | 16 |
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; } } |