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:
parent
1d8f4f9171
commit
6938f93f2e
11 changed files with 234 additions and 22 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
60
gcc/testsuite/g++.dg/torture/pr44813.C
Normal file
60
gcc/testsuite/g++.dg/torture/pr44813.C
Normal 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);
|
||||
}
|
44
gcc/testsuite/g++.dg/torture/pr44826.C
Normal file
44
gcc/testsuite/g++.dg/torture/pr44826.C
Normal 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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue