aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Hubicka <jh@suse.cz>2010-07-07 03:00:42 +0200
committerJan Hubicka <hubicka@gcc.gnu.org>2010-07-07 01:00:42 +0000
commit6938f93f2ec91e5c8f68469512593efba643caef (patch)
tree94d7441216e1549f60d0ca9d9c850b862731a503
parent1d8f4f9171a9bf20221425decc286348bb91ab15 (diff)
downloadgcc-6938f93f2ec91e5c8f68469512593efba643caef.zip
gcc-6938f93f2ec91e5c8f68469512593efba643caef.tar.gz
gcc-6938f93f2ec91e5c8f68469512593efba643caef.tar.bz2
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
-rw-r--r--gcc/ChangeLog22
-rw-r--r--gcc/ipa-split.c64
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/g++.dg/torture/pr44813.C60
-rw-r--r--gcc/testsuite/g++.dg/torture/pr44826.C44
-rw-r--r--gcc/tree-inline.c34
-rw-r--r--gcc/tree-ssa-ccp.c3
-rw-r--r--gcc/tree-ssa-structalias.c9
-rw-r--r--gcc/tree-ssa-uninit.c6
-rw-r--r--gcc/tree-ssa.c7
-rw-r--r--gcc/tree.c1
11 files changed, 234 insertions, 22 deletions
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 <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
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 <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
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<nsTextFrame*>(this)->EnsureTextRun();
+ PropertyProvider provider(const_cast<nsTextFrame*>(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 <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);
+}
+
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)));
}