/* Language independent return value optimizations
- Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2005, 2007, 2008, 2009, 2010
+ Free Software Foundation, Inc.
This file is part of GCC.
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
-#include "rtl.h"
#include "function.h"
#include "basic-block.h"
-#include "expr.h"
-#include "diagnostic.h"
+#include "tree-pretty-print.h"
#include "tree-flow.h"
#include "timevar.h"
#include "tree-dump.h"
#include "tree-pass.h"
#include "langhooks.h"
+#include "flags.h" /* For "optimize" in gate_pass_return_slot.
+ FIXME: That should be up to the pass manager,
+ but pass_nrv is not in pass_all_optimizations. */
/* This file implements return value optimizations for functions which
return aggregate types.
if (DECL_NAME (result))
return 0;
+ /* If the result has its address taken then it might be modified
+ by means not detected in the following loop. Bail out in this
+ case. */
+ if (TREE_ADDRESSABLE (result))
+ return 0;
+
/* Look through each block for assignments to the RESULT_DECL. */
FOR_EACH_BB (bb)
{
|| TREE_ADDRESSABLE (found)
|| DECL_ALIGN (found) > DECL_ALIGN (result)
|| !useless_type_conversion_p (result_type,
- TREE_TYPE (found)))
+ TREE_TYPE (found)))
return 0;
}
else if (gimple_has_lhs (stmt))
DECL_ABSTRACT_ORIGIN (result) = DECL_ABSTRACT_ORIGIN (found);
}
- TREE_ADDRESSABLE (result) = TREE_ADDRESSABLE (found);
+ TREE_ADDRESSABLE (result) |= TREE_ADDRESSABLE (found);
/* Now walk through the function changing all references to VAR to be
RESULT. */
}
}
+ SET_DECL_VALUE_EXPR (found, result);
+ DECL_HAS_VALUE_EXPR_P (found) = 1;
+
/* FOUND is no longer used. Ensure it gets removed. */
var_ann (found)->used = 0;
return 0;
optimization, where DEST is expected to be the LHS of a modify
expression where the RHS is a function returning an aggregate.
- We search for a base VAR_DECL and look to see if it is call clobbered.
- Note that we could do better, for example, by
- attempting to doing points-to analysis on INDIRECT_REFs. */
+ DEST is available if it is not clobbered or used by the call. */
static bool
-dest_safe_for_nrv_p (tree dest)
+dest_safe_for_nrv_p (gimple call)
{
- while (handled_component_p (dest))
- dest = TREE_OPERAND (dest, 0);
+ tree dest = gimple_call_lhs (call);
- if (! SSA_VAR_P (dest))
+ dest = get_base_address (dest);
+ if (! dest)
return false;
if (TREE_CODE (dest) == SSA_NAME)
- dest = SSA_NAME_VAR (dest);
+ return true;
- if (is_call_used (dest))
+ if (call_may_clobber_ref_p (call, dest)
+ || ref_maybe_used_by_stmt_p (call, dest))
return false;
return true;
&& gimple_call_lhs (stmt)
&& !gimple_call_return_slot_opt_p (stmt)
&& aggregate_value_p (TREE_TYPE (gimple_call_lhs (stmt)),
- gimple_call_fndecl (stmt))
- )
+ gimple_call_fndecl (stmt)))
{
/* Check if the location being assigned to is
- call-clobbered. */
- slot_opt_p = dest_safe_for_nrv_p (gimple_call_lhs (stmt));
+ clobbered by the call. */
+ slot_opt_p = dest_safe_for_nrv_p (stmt);
gimple_call_set_return_slot_opt (stmt, slot_opt_p);
}
}