- /* If we found a return statement using a different variable
- than previous return statements, then we can not perform
- NRV optimizations. */
- if (found != TREE_OPERAND (ret_expr, 1))
- return;
+ /* In a function with an aggregate return value, the
+ gimplifier has changed all non-empty RETURN_EXPRs to
+ return the RESULT_DECL. */
+ ret_val = gimple_return_retval (stmt);
+ if (ret_val)
+ gcc_assert (ret_val == result);
+ }
+ else if (gimple_has_lhs (stmt)
+ && gimple_get_lhs (stmt) == result)
+ {
+ tree rhs;
+
+ if (!gimple_assign_copy_p (stmt))
+ return 0;
+
+ rhs = gimple_assign_rhs1 (stmt);
+
+ /* Now verify that this return statement uses the same value
+ as any previously encountered return statement. */
+ if (found != NULL)
+ {
+ /* If we found a return statement using a different variable
+ than previous return statements, then we can not perform
+ NRV optimizations. */
+ if (found != rhs)
+ return 0;
+ }
+ else
+ found = rhs;
+
+ /* The returned value must be a local automatic variable of the
+ same type and alignment as the function's result. */
+ if (TREE_CODE (found) != VAR_DECL
+ || TREE_THIS_VOLATILE (found)
+ || DECL_CONTEXT (found) != current_function_decl
+ || TREE_STATIC (found)
+ || TREE_ADDRESSABLE (found)
+ || DECL_ALIGN (found) > DECL_ALIGN (result)
+ || !useless_type_conversion_p (result_type,
+ TREE_TYPE (found)))
+ return 0;
+ }
+ else if (gimple_has_lhs (stmt))
+ {
+ tree addr = get_base_address (gimple_get_lhs (stmt));
+ /* If there's any MODIFY of component of RESULT,
+ then bail out. */
+ if (addr && addr == result)
+ return 0;