From 6938f93f2ec91e5c8f68469512593efba643caef Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Wed, 7 Jul 2010 03:00:42 +0200 Subject: 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 --- gcc/ChangeLog | 22 ++++++++++++ gcc/ipa-split.c | 64 +++++++++++++++++++++++++++------- gcc/testsuite/ChangeLog | 6 ++++ gcc/testsuite/g++.dg/torture/pr44813.C | 60 +++++++++++++++++++++++++++++++ gcc/testsuite/g++.dg/torture/pr44826.C | 44 +++++++++++++++++++++++ gcc/tree-inline.c | 34 ++++++++++++++---- gcc/tree-ssa-ccp.c | 3 +- gcc/tree-ssa-structalias.c | 9 +++-- gcc/tree-ssa-uninit.c | 6 ++++ gcc/tree-ssa.c | 7 ++++ gcc/tree.c | 1 + 11 files changed, 234 insertions(+), 22 deletions(-) create mode 100644 gcc/testsuite/g++.dg/torture/pr44813.C create mode 100644 gcc/testsuite/g++.dg/torture/pr44826.C diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6d32d9a..7c4c89d 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,25 @@ +2010-07-07 Jan Hubicka + + 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 PR rtl-optimization/44787 diff --git a/gcc/ipa-split.c b/gcc/ipa-split.c index 1bd9d24..28f96b2 100644 --- a/gcc/ipa-split.c +++ b/gcc/ipa-split.c @@ -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 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index ccb722d..63a468b 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2010-07-07 Jan Hubicka + + PR middle-end/44813 + * g++.dg/torture/pr44813.C: New testcase. + * g++.dg/torture/pr44826.C: New testcase. + 2010-07-07 Bernd Schmidt PR rtl-optimization/44787 diff --git a/gcc/testsuite/g++.dg/torture/pr44813.C b/gcc/testsuite/g++.dg/torture/pr44813.C new file mode 100644 index 0000000..1dc01b0 --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/pr44813.C @@ -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(this)->EnsureTextRun(); + PropertyProvider provider(const_cast(this), iter); +} diff --git a/gcc/testsuite/g++.dg/torture/pr44826.C b/gcc/testsuite/g++.dg/torture/pr44826.C new file mode 100644 index 0000000..aece140 --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/pr44826.C @@ -0,0 +1,44 @@ +typedef unsigned short PRUint16; +typedef PRUint16 PRUnichar; +template 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 struct variant_storage_traits { + typedef DataType ConstructorType; + typedef DataType StorageType; + static inline StorageType storage_conversion(ConstructorType aData) { + return aData; + } +}; +template class Variant : public nsIVariant { +public: + Variant(typename variant_storage_traits::ConstructorType aData) + : mData(variant_storage_traits::storage_conversion(aData)) {} + typename variant_storage_traits::StorageType mData; +}; +typedef Variant TextVariant; +class Row { + void initialize(sqlite3_stmt *aStatement); +}; +void Row::initialize(sqlite3_stmt *aStatement) +{ + nsDependentString str(static_cast(::sqlite3_column_text16(aStatement, 0))); + new TextVariant(str); +} + diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index e295a6a..98cadde 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -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); diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c index 1e2309a..5223c27 100644 --- a/gcc/tree-ssa-ccp.c +++ b/gcc/tree-ssa-ccp.c @@ -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; diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c index 5a84b58..48a42bd 100644 --- a/gcc/tree-ssa-structalias.c +++ b/gcc/tree-ssa-structalias.c @@ -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); diff --git a/gcc/tree-ssa-uninit.c b/gcc/tree-ssa-uninit.c index 6d58f5b..51f3bc9 100644 --- a/gcc/tree-ssa-uninit.c +++ b/gcc/tree-ssa-uninit.c @@ -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; diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c index 2ea2e68..f3a7a10 100644 --- a/gcc/tree-ssa.c +++ b/gcc/tree-ssa.c @@ -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", diff --git a/gcc/tree.c b/gcc/tree.c index 4247047..dda9287 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -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))); } -- cgit v1.1