Jim Blandy wrote:
Is this optimization really legit?
I've never come across an ABI which actually requires functions that
return structures by value to leave the return value buffer untouched
until just before they return.
The optimization checks first that the address is not exposed:
else if (!is_gimple_non_addressable (*to_p))
/* Don't use the original target if it's already addressable;
if its address escapes, and the called function uses the
NRV optimization, a conforming program could see *to_p
change before the called function returns; see c++/19317.
When optimizing, the return_slot pass marks more functions
as safe after we have escape info. */
use_target = false;
is_gimple_non_addressable checks needs_to_live_in_memory:
bool
needs_to_live_in_memory (tree t)
{
return (TREE_ADDRESSABLE (t)
|| is_global_var (t)
|| (TREE_CODE (t) == RESULT_DECL
&& aggregate_value_p (t, current_function_decl)));
}
Consider code like this:
struct f { int a, b };
struct f x;
struct f foo (void) { struct f y; y.a = 42; y.b = x.a; return y; }
struct f bar () { x = foo (); return x; }
The ABI's I've seen permit foo to actually store the 42 directly into
the 'a' slot of their return buffer, before fetching x.a. If bar then
passes x itself to foo as its return value buffer, then you wipe out
x.a before you have a chance to reference it.
This would be caught by the is_global_var check:
bool
is_global_var (tree t)
{
return (TREE_STATIC (t) || DECL_EXTERNAL (t));
}