re PR middle-end/44813 (ipa-split causes ice in ptr_deref_may_alias_decl_p, at tree-ssa-alias.c:173)

PR middle-end/44813
	* tree-ssa-uninit.c (ssa_undefined_value_p): Result decl is defined
	for functions passed by reference.
	* tree.c (needs_to_live_in_memory): RESULT_DECL don't need to live
	in memory when passed by reference.
	* tree-ssa-ccp.c (get_default_value): Only VAR_DECL is undefined at
	beggining.
	* ipa-split.c (split_function): Cleanup way return value is passed;
	handle SSA DECL_BY_REFERENCE retvals.
	* tree-ssa.c (verify_def): Verify that RESULT_DECL is read only when
	DECL_BY_REFERENCE is set.
	* tree-ssa-structalias.c (get_constraint_for_ssa_var, get_fi_for_callee,
	find_what_p_points_to): Handle RESULT_DECL.
	* tree-inline.c (declare_return_variable): Get new entry_block argument;
	when passing by reference ensure that RESULT_DECL is gimple_val.
	(remap_gimple_op_r): Remap RESULT_DECL ssa name.
	(remap_gimple_stmt): Handle SSA DECL_BY_REFERENCE returns.
	* g++.dg/torture/pr44813.C: New testcase.
	* g++.dg/torture/pr44826.C: New testcase.

From-SVN: r161898
This commit is contained in:
Jan Hubicka 2010-07-07 03:00:42 +02:00 committed by Jan Hubicka
parent 1d8f4f9171
commit 6938f93f2e
11 changed files with 234 additions and 22 deletions

View file

@ -1,3 +1,25 @@
2010-07-07 Jan Hubicka <jh@suse.cz>
With parts by Richard Guenther
PR middle-end/44813
* tree-ssa-uninit.c (ssa_undefined_value_p): Result decl is defined
for functions passed by reference.
* tree.c (needs_to_live_in_memory): RESULT_DECL don't need to live
in memory when passed by reference.
* tree-ssa-ccp.c (get_default_value): Only VAR_DECL is undefined at
beggining.
* ipa-split.c (split_function): Cleanup way return value is passed;
handle SSA DECL_BY_REFERENCE retvals.
* tree-ssa.c (verify_def): Verify that RESULT_DECL is read only when
DECL_BY_REFERENCE is set.
* tree-ssa-structalias.c (get_constraint_for_ssa_var, get_fi_for_callee,
find_what_p_points_to): Handle RESULT_DECL.
* tree-inline.c (declare_return_variable): Get new entry_block argument;
when passing by reference ensure that RESULT_DECL is gimple_val.
(remap_gimple_op_r): Remap RESULT_DECL ssa name.
(remap_gimple_stmt): Handle SSA DECL_BY_REFERENCE returns.
2010-07-07 Bernd Schmidt <bernds@codesourcery.com>
PR rtl-optimization/44787

View file

@ -967,31 +967,47 @@ split_function (struct split_point *split_point)
return_bb == EXIT_BLOCK_PTR ? 0 : EDGE_FALLTHRU);
e->count = call_bb->count;
e->probability = REG_BR_PROB_BASE;
/* If there is return basic block, see what value we need to store
return value into and put call just before it. */
if (return_bb != EXIT_BLOCK_PTR)
{
real_retval = retval = find_retval (return_bb);
/* See if return value is computed by split part;
function might just return its argument, invariant or undefined
value. In this case we don't need to do any updating. */
if (real_retval
&& !is_gimple_min_invariant (retval)
&& (TREE_CODE (retval) != SSA_NAME
|| !SSA_NAME_IS_DEFAULT_DEF (retval)))
|| (!SSA_NAME_IS_DEFAULT_DEF (retval)
|| DECL_BY_REFERENCE
(DECL_RESULT (current_function_decl)))))
{
gimple_stmt_iterator psi;
/* See if there is PHI defining return value. */
for (psi = gsi_start_phis (return_bb);
!gsi_end_p (psi); gsi_next (&psi))
if (is_gimple_reg (gimple_phi_result (gsi_stmt (psi))))
break;
/* When we have PHI, update PHI. When there is no PHI,
update the return statement itself. */
if (TREE_CODE (retval) == SSA_NAME)
/* See if we need new SSA_NAME for the result.
When DECL_BY_REFERENCE is true, retval is actually pointer to
return value and it is constant in whole function. */
if (TREE_CODE (retval) == SSA_NAME
&& !DECL_BY_REFERENCE (DECL_RESULT (current_function_decl)))
{
retval = make_ssa_name (SSA_NAME_VAR (retval), call);
/* See if there is PHI defining return value. */
for (psi = gsi_start_phis (return_bb);
!gsi_end_p (psi); gsi_next (&psi))
if (is_gimple_reg (gimple_phi_result (gsi_stmt (psi))))
break;
/* When there is PHI, just update its value. */
if (TREE_CODE (retval) == SSA_NAME
&& !gsi_end_p (psi))
add_phi_arg (gsi_stmt (psi), retval, e, UNKNOWN_LOCATION);
else if (TREE_CODE (retval) == SSA_NAME)
/* Otherwise update the return BB itself.
find_return_bb allows at most one assignment to return value,
so update first statement. */
else
{
gimple_stmt_iterator bsi;
for (bsi = gsi_start_bb (return_bb); !gsi_end_p (bsi);
@ -1016,6 +1032,9 @@ split_function (struct split_point *split_point)
}
gsi_insert_after (&gsi, call, GSI_NEW_STMT);
}
/* We don't use return block (there is either no return in function or
multiple of them). So create new basic block with return statement.
*/
else
{
gimple ret;
@ -1030,7 +1049,28 @@ split_function (struct split_point *split_point)
&& !DECL_BY_REFERENCE (retval))
retval = create_tmp_reg (TREE_TYPE (retval), NULL);
if (is_gimple_reg (retval))
retval = make_ssa_name (retval, call);
{
/* When returning by reference, there is only one SSA name
assigned to RESULT_DECL (that is pointer to return value).
Look it up or create new one if it is missing. */
if (DECL_BY_REFERENCE (retval))
{
tree retval_name;
if ((retval_name = gimple_default_def (cfun, retval))
!= NULL)
retval = retval_name;
else
{
retval_name = make_ssa_name (retval,
gimple_build_nop ());
set_default_def (retval, retval_name);
retval = retval_name;
}
}
/* Otherwise produce new SSA name for return value. */
else
retval = make_ssa_name (retval, call);
}
if (DECL_BY_REFERENCE (DECL_RESULT (current_function_decl)))
gimple_call_set_lhs (call, build_simple_mem_ref (retval));
else

View file

@ -1,3 +1,9 @@
2010-07-07 Jan Hubicka <jh@suse.cz>
PR middle-end/44813
* g++.dg/torture/pr44813.C: New testcase.
* g++.dg/torture/pr44826.C: New testcase.
2010-07-07 Bernd Schmidt <bernds@codesourcery.com>
PR rtl-optimization/44787

View file

@ -0,0 +1,60 @@
typedef unsigned int PRUint32;
typedef int PRInt32;
typedef unsigned long PRUint64;
typedef int PRIntn;
typedef PRIntn PRBool;
struct nsRect {
nsRect(const nsRect& aRect) { }
};
enum nsCompatibility { eCompatibility_NavQuirks = 3 };
class gfxContext;
typedef PRUint64 nsFrameState;
class nsPresContext {
public:
nsCompatibility CompatibilityMode() const { }
};
class nsStyleContext {
public:
PRBool HasTextDecorations() const;
};
class nsIFrame {
public:
nsPresContext* PresContext() const;
nsStyleContext* GetStyleContext() const;
nsFrameState GetStateBits() const;
nsRect GetOverflowRect() const;
};
class nsFrame : public nsIFrame { };
class nsLineList_iterator { };
class nsLineList {
public:
typedef nsLineList_iterator iterator;
};
class gfxSkipCharsIterator { };
class gfxTextRun {
public:
class PropertyProvider { };
};
class nsTextFrame : public nsFrame
{
virtual nsRect ComputeTightBounds(gfxContext* aContext) const;
gfxSkipCharsIterator EnsureTextRun(gfxContext* aReferenceContext = 0L,
nsIFrame* aLineContainer = 0L,
const nsLineList::iterator* aLine = 0L,
PRUint32* aFlowEndInTextRun = 0L);
};
class PropertyProvider : public gfxTextRun::PropertyProvider
{
public:
PropertyProvider(nsTextFrame* aFrame, const gfxSkipCharsIterator& aStart);
PRInt32 mLength[64];
};
nsRect nsTextFrame::ComputeTightBounds(gfxContext* aContext) const
{
if ((GetStyleContext()->HasTextDecorations()
&& eCompatibility_NavQuirks == PresContext()->CompatibilityMode())
|| (GetStateBits() & (nsFrameState(1) << (23))))
return GetOverflowRect();
gfxSkipCharsIterator iter = const_cast<nsTextFrame*>(this)->EnsureTextRun();
PropertyProvider provider(const_cast<nsTextFrame*>(this), iter);
}

View file

@ -0,0 +1,44 @@
typedef unsigned short PRUint16;
typedef PRUint16 PRUnichar;
template <class CharT> struct nsCharTraits {
};
class nsAString_internal {
public:
typedef PRUnichar char_type;
};
class nsString : public nsAString_internal {
public:
typedef nsString self_type;
nsString( const self_type& str );
};
class nsDependentString : public nsString {
public:
explicit nsDependentString( const char_type* data );
};
typedef struct sqlite3_stmt sqlite3_stmt;
const void *sqlite3_column_text16(sqlite3_stmt*, int iCol);
class nsIVariant { };
template <typename DataType> struct variant_storage_traits {
typedef DataType ConstructorType;
typedef DataType StorageType;
static inline StorageType storage_conversion(ConstructorType aData) {
return aData;
}
};
template <typename DataType> class Variant : public nsIVariant {
public:
Variant(typename variant_storage_traits<DataType>::ConstructorType aData)
: mData(variant_storage_traits<DataType>::storage_conversion(aData)) {}
typename variant_storage_traits<DataType>::StorageType mData;
};
typedef Variant<nsString> TextVariant;
class Row {
void initialize(sqlite3_stmt *aStatement);
};
void Row::initialize(sqlite3_stmt *aStatement)
{
nsDependentString str(static_cast<const PRUnichar
*>(::sqlite3_column_text16(aStatement, 0)));
new TextVariant(str);
}

View file

@ -113,7 +113,7 @@ eni_weights eni_time_weights;
/* Prototypes. */
static tree declare_return_variable (copy_body_data *, tree, tree);
static tree declare_return_variable (copy_body_data *, tree, tree, basic_block);
static void remap_block (tree *, copy_body_data *);
static void copy_bind_expr (tree *, int *, copy_body_data *);
static tree mark_local_for_remap_r (tree *, int *, void *);
@ -817,6 +817,12 @@ remap_gimple_op_r (tree *tp, int *walk_subtrees, void *data)
tree decl = TREE_OPERAND (*tp, 0);
tree *n;
/* See remap_ssa_name. */
if (TREE_CODE (decl) == SSA_NAME
&& TREE_CODE (SSA_NAME_VAR (decl)) == RESULT_DECL
&& id->transform_return_to_modify)
decl = SSA_NAME_VAR (decl);
n = (tree *) pointer_map_contains (id->decl_map, decl);
if (n)
{
@ -1235,7 +1241,10 @@ remap_gimple_stmt (gimple stmt, copy_body_data *id)
If RETVAL is just the result decl, the result decl has
already been set (e.g. a recent "foo (&result_decl, ...)");
just toss the entire GIMPLE_RETURN. */
if (retval && TREE_CODE (retval) != RESULT_DECL)
if (retval
&& (TREE_CODE (retval) != RESULT_DECL
&& (TREE_CODE (retval) != SSA_NAME
|| TREE_CODE (SSA_NAME_VAR (retval)) != RESULT_DECL)))
{
copy = gimple_build_assign (id->retvar, retval);
/* id->retvar is already substituted. Skip it on later remapping. */
@ -2735,7 +2744,8 @@ initialize_inlined_parameters (copy_body_data *id, gimple stmt,
as seen by the caller. */
static tree
declare_return_variable (copy_body_data *id, tree return_slot, tree modify_dest)
declare_return_variable (copy_body_data *id, tree return_slot, tree modify_dest,
basic_block entry_bb)
{
tree callee = id->src_fn;
tree caller = id->dst_fn;
@ -2878,8 +2888,20 @@ declare_return_variable (copy_body_data *id, tree return_slot, tree modify_dest)
done:
/* Register the VAR_DECL as the equivalent for the RESULT_DECL; that
way, when the RESULT_DECL is encountered, it will be
automatically replaced by the VAR_DECL. */
insert_decl_map (id, result, var);
automatically replaced by the VAR_DECL.
When returning by reference, ensure that RESULT_DECL remaps to
gimple_val. */
if (DECL_BY_REFERENCE (result)
&& !is_gimple_val (var))
{
tree temp = create_tmp_var (TREE_TYPE (result), "retvalptr");
insert_decl_map (id, result, temp);
temp = remap_ssa_name (gimple_default_def (id->src_cfun, result), id);
insert_init_stmt (id, entry_bb, gimple_build_assign (temp, var));
}
else
insert_decl_map (id, result, var);
/* Remember this so we can ignore it in remap_decls. */
id->retvar = var;
@ -3983,7 +4005,7 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
}
/* Declare the return variable for the function. */
use_retvar = declare_return_variable (id, return_slot, modify_dest);
use_retvar = declare_return_variable (id, return_slot, modify_dest, bb);
/* Add local vars in this inlined callee to caller. */
add_local_variables (id->src_cfun, cfun, id, true);

View file

@ -300,7 +300,8 @@ get_default_value (tree var)
before being initialized. If VAR is a local variable, we
can assume initially that it is UNDEFINED, otherwise we must
consider it VARYING. */
if (is_gimple_reg (sym) && TREE_CODE (sym) != PARM_DECL)
if (is_gimple_reg (sym)
&& TREE_CODE (sym) == VAR_DECL)
val.lattice_val = UNDEFINED;
else
val.lattice_val = VARYING;

View file

@ -2836,7 +2836,8 @@ get_constraint_for_ssa_var (tree t, VEC(ce_s, heap) **results, bool address_p)
/* For parameters, get at the points-to set for the actual parm
decl. */
if (TREE_CODE (t) == SSA_NAME
&& TREE_CODE (SSA_NAME_VAR (t)) == PARM_DECL
&& (TREE_CODE (SSA_NAME_VAR (t)) == PARM_DECL
|| TREE_CODE (SSA_NAME_VAR (t)) == RESULT_DECL)
&& SSA_NAME_IS_DEFAULT_DEF (t))
{
get_constraint_for_ssa_var (SSA_NAME_VAR (t), results, address_p);
@ -3982,7 +3983,8 @@ get_fi_for_callee (gimple call)
if (TREE_CODE (decl) == SSA_NAME)
{
if (TREE_CODE (decl) == SSA_NAME
&& TREE_CODE (SSA_NAME_VAR (decl)) == PARM_DECL
&& (TREE_CODE (SSA_NAME_VAR (decl)) == PARM_DECL
|| TREE_CODE (SSA_NAME_VAR (decl)) == RESULT_DECL)
&& SSA_NAME_IS_DEFAULT_DEF (decl))
decl = SSA_NAME_VAR (decl);
return get_vi_for_tree (decl);
@ -5751,7 +5753,8 @@ find_what_p_points_to (tree p)
/* For parameters, get at the points-to set for the actual parm
decl. */
if (TREE_CODE (p) == SSA_NAME
&& TREE_CODE (SSA_NAME_VAR (p)) == PARM_DECL
&& (TREE_CODE (SSA_NAME_VAR (p)) == PARM_DECL
|| TREE_CODE (SSA_NAME_VAR (p)) == RESULT_DECL)
&& SSA_NAME_IS_DEFAULT_DEF (p))
lookup_p = SSA_NAME_VAR (p);

View file

@ -92,6 +92,12 @@ ssa_undefined_value_p (tree t)
if (TREE_CODE (var) == PARM_DECL)
return false;
/* When returning by reference the return address is actually a hidden
parameter. */
if (TREE_CODE (SSA_NAME_VAR (t)) == RESULT_DECL
&& DECL_BY_REFERENCE (SSA_NAME_VAR (t)))
return false;
/* Hard register variables get their initial value from the ether. */
if (TREE_CODE (var) == VAR_DECL && DECL_HARD_REGISTER (var))
return false;

View file

@ -638,6 +638,13 @@ verify_def (basic_block bb, basic_block *definition_block, tree ssa_name,
if (verify_ssa_name (ssa_name, is_virtual))
goto err;
if (TREE_CODE (SSA_NAME_VAR (ssa_name)) == RESULT_DECL
&& DECL_BY_REFERENCE (SSA_NAME_VAR (ssa_name)))
{
error ("RESULT_DECL should be read only when DECL_BY_REFERENCE is set.");
goto err;
}
if (definition_block[SSA_NAME_VERSION (ssa_name)])
{
error ("SSA_NAME created in two different blocks %i and %i",

View file

@ -9742,6 +9742,7 @@ needs_to_live_in_memory (const_tree t)
return (TREE_ADDRESSABLE (t)
|| is_global_var (t)
|| (TREE_CODE (t) == RESULT_DECL
&& !DECL_BY_REFERENCE (t)
&& aggregate_value_p (t, current_function_decl)));
}