OSDN Git Service

PR middle-end/44813
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 7 Jul 2010 01:00:42 +0000 (01:00 +0000)
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 7 Jul 2010 01:00:42 +0000 (01:00 +0000)
* 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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@161898 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/ipa-split.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/torture/pr44813.C [new file with mode: 0644]
gcc/testsuite/g++.dg/torture/pr44826.C [new file with mode: 0644]
gcc/tree-inline.c
gcc/tree-ssa-ccp.c
gcc/tree-ssa-structalias.c
gcc/tree-ssa-uninit.c
gcc/tree-ssa.c
gcc/tree.c

index 6d32d9a..7c4c89d 100644 (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
index 1bd9d24..28f96b2 100644 (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
index ccb722d..63a468b 100644 (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
diff --git a/gcc/testsuite/g++.dg/torture/pr44813.C b/gcc/testsuite/g++.dg/torture/pr44813.C
new file mode 100644 (file)
index 0000000..1dc01b0
--- /dev/null
@@ -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 (file)
index 0000000..aece140
--- /dev/null
@@ -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);
+}
+
index e295a6a..98cadde 100644 (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);
index 1e2309a..5223c27 100644 (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;
index 5a84b58..48a42bd 100644 (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);
 
index 6d58f5b..51f3bc9 100644 (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;
index 2ea2e68..f3a7a10 100644 (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",
index 4247047..dda9287 100644 (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)));
 }