This is the mail archive of the mailing list for the GCC project.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RFC: PATCH to gimplify_modify_expr_rhs to make return slot explicit

This patch makes the return slot argument explicit whenever a the return
value of a function that returns in memory is used.  This addresses the
problem in mudflap/19319 that a variable whose address is passed as a
return slot doesn't get TREE_ADDRESSABLE, and also avoids the redundant
copy discussed in the thread about Mark's patch for 16405.

An early version of this patch performed this transformation
unconditionally, as the rtl version in expand_call does.  However, a
problem occurred to me:  if we elide both the copy from the user variable
(the NRV optimization) and the copy from the return slot (this
optimization), we can end up combining a local variable in the called
function with a globally visible object:

// Test that the NRV optimization doesn't cause a1 to change too soon.
// { dg-do run }

#ifdef __cplusplus
extern "C" void abort();

struct A
  int i[200];

struct A a1;
int i;

struct A f ()
  struct A a2;
  a2.i[0] = 42;
  // a1.i[0] should still be 0 until we return.
  i = a1.i[0];
  return a2;

int main()
  a1 = f();
  if (i == 42)
    abort ();
  return 0;

This test breaks without my patch under C++, and would break under C except
that the language-independent NRV pass seems to have been broken by rth's
changes to RETURN_EXPR gimplification.

The fix would seem to be to insert a temporary if the object on the lhs
might escape.  The patch below just checks is_gimple_non_addressable, which
I believe to be the best we can do before actual escape analysis.

Unfortunately, this will unnecessarily pessimize some code by adding an
additional copy of the return value when calling functions that don't use
the NRV optimization.  I don't see what to do about this.

Any thoughts?

2005-01-12  Jason Merrill  <>

	* gimplify.c (gimplify_modify_expr_rhs) [CALL_EXPR]: Make return
	slot explicit.

*** gimplify.c.~1~	2005-01-11 19:13:24.000000000 -0500
--- gimplify.c	2005-01-12 21:20:27.829403345 -0500
*************** gimplify_modify_expr_rhs (tree *expr_p, 
*** 2883,2888 ****
--- 2884,2933 ----
  	  ret = GS_UNHANDLED;
+       case CALL_EXPR:
+ 	/* For calls that return in memory, give *to_p as the CALL_EXPR's
+ 	   return slot so that we don't generate a temporary.  */
+ 	if (aggregate_value_p (*from_p, *from_p))
+ 	  {
+ 	    tree init = *from_p;
+ 	    tree fn = TREE_OPERAND (init, 0);
+ 	    tree args = TREE_OPERAND (init, 1);
+ 	    tree rettype = TREE_TYPE (TREE_TYPE (TREE_TYPE (fn)));
+ 	    tree arg = *to_p;
+ 	    tree type;
+ 	    /* Only use the original target if *to_p isn't 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.  */
+ 	    bool use_temp = !is_gimple_non_addressable (*to_p);
+ 	    if (use_temp)
+ 	      {
+ 		arg = create_tmp_var (rettype, "ret");
+ 		*from_p = arg;
+ 	      }
+ 	    type = TREE_TYPE (arg);
+ 	    lang_hooks.mark_addressable (arg);
+ 	    arg = build1 (ADDR_EXPR, build_pointer_type (type), arg);
+ 	    /* The return type might have different cv-quals from arg.  */
+ 	    arg = convert (build_pointer_type (rettype), arg);
+ 	    args = tree_cons (NULL_TREE, arg, args);
+ 	    init = build3 (CALL_EXPR, rettype, fn, args, NULL_TREE);
+ 	    if (use_temp)
+ 	      gimplify_and_add (init, pre_p);
+ 	    else if (want_value)
+ 	      {
+ 		gimplify_and_add (init, pre_p);
+ 		*expr_p = *to_p;
+ 	      }
+ 	    else
+ 	      *expr_p = init;
+ 	    return GS_OK;
+ 	  }
  	ret = GS_UNHANDLED;

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]