diff mbox series

[PR,91579] Avoid creating redundant PHI nodes in tail-call pass

Message ID ri6r254bawg.fsf@suse.cz
State New
Headers show
Series [PR,91579] Avoid creating redundant PHI nodes in tail-call pass | expand

Commit Message

Martin Jambor Aug. 29, 2019, 9:04 a.m. UTC
Hi,

when turning a tail-recursive call into a loop, the tail-call pass
creates a phi node for each gimple_reg function parameter that has any
use at all, even when the value passed to the original call is the same
as the received one, when it is the parameter's default definition.
This results in a redundant phi node in which one argument is the
default definition and all others are the LHS of the same phi node.  See
the Bugzilla entry for an example.  These phi nodes in turn confuses
ipa-prop.c which cannot skip them and may not create a pass-through jump
function when it should.

Fixed by the following patch which just adds a bitmap to remember where
there are non-default-defs passed to a tail-recursive call and then
creates phi nodes only for such parameters.  It has passed bootstrap and
testing on x86_64-linux.

OK for trunk?

Martin


2019-08-28  Martin Jambor  <mjambor@suse.cz>

	tree-optimization/91579
	* tree-tailcall.c (tailr_non_ddef_args): New variable.
	(find_tail_calls): Allocate tailr_non_ddef_args and set its bits as
	appropriate.
	(arg_needs_copy_p): New parameter idx.  Also check
	tailr_non_ddef_args.
	(tree_optimize_tail_calls_1): Free tailr_non_ddef_args.

	testsuite/
	* gcc.dg/tree-ssa/pr91579.c: New test.
---
 gcc/testsuite/gcc.dg/tree-ssa/pr91579.c | 22 ++++++++++++++
 gcc/tree-tailcall.c                     | 38 +++++++++++++++++++------
 2 files changed, 52 insertions(+), 8 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr91579.c

Comments

Richard Biener Aug. 29, 2019, 9:31 a.m. UTC | #1
On Thu, Aug 29, 2019 at 11:04 AM Martin Jambor <mjambor@suse.cz> wrote:
>
> Hi,
>
> when turning a tail-recursive call into a loop, the tail-call pass
> creates a phi node for each gimple_reg function parameter that has any
> use at all, even when the value passed to the original call is the same
> as the received one, when it is the parameter's default definition.
> This results in a redundant phi node in which one argument is the
> default definition and all others are the LHS of the same phi node.  See
> the Bugzilla entry for an example.  These phi nodes in turn confuses
> ipa-prop.c which cannot skip them and may not create a pass-through jump
> function when it should.
>
> Fixed by the following patch which just adds a bitmap to remember where
> there are non-default-defs passed to a tail-recursive call and then
> creates phi nodes only for such parameters.  It has passed bootstrap and
> testing on x86_64-linux.
>
> OK for trunk?

OK.  Eventually arg_needs_copy_p can be elided completely
and pre-computed into the bitmap so we can just check
the positional?  And rename the bitmap to arg_need_copy itself.

Thanks,
Richard.

>
> Martin
>
>
> 2019-08-28  Martin Jambor  <mjambor@suse.cz>
>
>         tree-optimization/91579
>         * tree-tailcall.c (tailr_non_ddef_args): New variable.
>         (find_tail_calls): Allocate tailr_non_ddef_args and set its bits as
>         appropriate.
>         (arg_needs_copy_p): New parameter idx.  Also check
>         tailr_non_ddef_args.
>         (tree_optimize_tail_calls_1): Free tailr_non_ddef_args.
>
>         testsuite/
>         * gcc.dg/tree-ssa/pr91579.c: New test.
> ---
>  gcc/testsuite/gcc.dg/tree-ssa/pr91579.c | 22 ++++++++++++++
>  gcc/tree-tailcall.c                     | 38 +++++++++++++++++++------
>  2 files changed, 52 insertions(+), 8 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr91579.c
>
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr91579.c b/gcc/testsuite/gcc.dg/tree-ssa/pr91579.c
> new file mode 100644
> index 00000000000..ee752be1a85
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr91579.c
> @@ -0,0 +1,22 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fdump-tree-tailr1" } */
> +
> +typedef long unsigned int size_t;
> +typedef int (*compare_t)(const void *, const void *);
> +
> +int partition (void *base, size_t nmemb, size_t size, compare_t cmp);
> +
> +void
> +my_qsort (void *base, size_t nmemb, size_t size, compare_t cmp)
> +{
> +  int pt;
> +  if (nmemb > 1)
> +    {
> +      pt = partition (base, nmemb, size, cmp);
> +      my_qsort (base, pt + 1, size, cmp);
> +      my_qsort ((void*)((char*) base + (pt + 1) * size),
> +               nmemb - pt - 1, size, cmp);
> +    }
> +}
> +
> +/* { dg-final { scan-tree-dump-not "cmp\[^\r\n\]*PHI" "tailr1" } } */
> diff --git a/gcc/tree-tailcall.c b/gcc/tree-tailcall.c
> index a4b563efd73..23d60f492da 100644
> --- a/gcc/tree-tailcall.c
> +++ b/gcc/tree-tailcall.c
> @@ -126,6 +126,13 @@ struct tailcall
>     accumulator.  */
>  static tree m_acc, a_acc;
>
> +/* Bitmap with a bit for each function parameter which is set to true if in a
> +   tail-recursion we pass to the actual argument something else than the
> +   default definition of the corresponding formal parameter.  It has no meaning
> +   for non-gimple-register parameters.  */
> +
> +static bitmap tailr_non_ddef_args;
> +
>  static bool optimize_tail_call (struct tailcall *, bool);
>  static void eliminate_tail_call (struct tailcall *);
>
> @@ -727,6 +734,17 @@ find_tail_calls (basic_block bb, struct tailcall **ret)
>           gimple_stmt_iterator mgsi = gsi_for_stmt (stmt);
>           gsi_move_before (&mgsi, &gsi);
>         }
> +      if (!tailr_non_ddef_args)
> +       tailr_non_ddef_args = BITMAP_ALLOC (NULL);
> +      for (param = DECL_ARGUMENTS (current_function_decl), idx = 0;
> +          param;
> +          param = DECL_CHAIN (param), idx++)
> +       {
> +         tree arg = gimple_call_arg (call, idx);
> +         if (is_gimple_reg (param)
> +             && (arg != ssa_default_def (cfun, param)))
> +           bitmap_set_bit (tailr_non_ddef_args, idx);
> +       }
>      }
>
>    nw = XNEW (struct tailcall);
> @@ -905,11 +923,11 @@ decrease_profile (basic_block bb, profile_count count)
>      }
>  }
>
> -/* Returns true if argument PARAM of the tail recursive call needs to be copied
> -   when the call is eliminated.  */
> +/* Returns true if PARAM, which is the IDX-th argument of the tail recursively
> +   called function, needs to be copied when the call is eliminated.  */
>
>  static bool
> -arg_needs_copy_p (tree param)
> +arg_needs_copy_p (tree param, unsigned idx)
>  {
>    tree def;
>
> @@ -918,7 +936,7 @@ arg_needs_copy_p (tree param)
>
>    /* Parameters that are only defined but never used need not be copied.  */
>    def = ssa_default_def (cfun, param);
> -  if (!def)
> +  if (!def || !bitmap_bit_p (tailr_non_ddef_args, idx))
>      return false;
>
>    return true;
> @@ -1005,7 +1023,7 @@ eliminate_tail_call (struct tailcall *t)
>         param;
>         param = DECL_CHAIN (param), idx++)
>      {
> -      if (!arg_needs_copy_p (param))
> +      if (!arg_needs_copy_p (param, idx))
>         continue;
>
>        arg = gimple_call_arg (stmt, idx);
> @@ -1139,10 +1157,11 @@ tree_optimize_tail_calls_1 (bool opt_tailcalls)
>               split_edge (single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
>
>           /* Copy the args if needed.  */
> -         for (param = DECL_ARGUMENTS (current_function_decl);
> +         unsigned idx;
> +         for (param = DECL_ARGUMENTS (current_function_decl), idx = 0;
>                param;
> -              param = DECL_CHAIN (param))
> -           if (arg_needs_copy_p (param))
> +              param = DECL_CHAIN (param), idx++)
> +           if (arg_needs_copy_p (param, idx))
>               {
>                 tree name = ssa_default_def (cfun, param);
>                 tree new_name = make_ssa_name (param, SSA_NAME_DEF_STMT (name));
> @@ -1206,6 +1225,9 @@ tree_optimize_tail_calls_1 (bool opt_tailcalls)
>    if (phis_constructed)
>      mark_virtual_operands_for_renaming (cfun);
>
> +  if (tailr_non_ddef_args)
> +    BITMAP_FREE (tailr_non_ddef_args);
> +
>    if (changed)
>      return TODO_cleanup_cfg | TODO_update_ssa_only_virtuals;
>    return 0;
> --
> 2.22.0
>
Martin Jambor Aug. 29, 2019, 1:56 p.m. UTC | #2
Hi,

On Thu, Aug 29 2019, Richard Biener wrote:
> On Thu, Aug 29, 2019 at 11:04 AM Martin Jambor <mjambor@suse.cz> wrote:
>>
>> Hi,
>>
>> when turning a tail-recursive call into a loop, the tail-call pass
>> creates a phi node for each gimple_reg function parameter that has any
>> use at all, even when the value passed to the original call is the same
>> as the received one, when it is the parameter's default definition.
>> This results in a redundant phi node in which one argument is the
>> default definition and all others are the LHS of the same phi node.  See
>> the Bugzilla entry for an example.  These phi nodes in turn confuses
>> ipa-prop.c which cannot skip them and may not create a pass-through jump
>> function when it should.
>>
>> Fixed by the following patch which just adds a bitmap to remember where
>> there are non-default-defs passed to a tail-recursive call and then
>> creates phi nodes only for such parameters.  It has passed bootstrap and
>> testing on x86_64-linux.
>>
>> OK for trunk?
>
> OK.  Eventually arg_needs_copy_p can be elided completely
> and pre-computed into the bitmap so we can just check
> the positional?  And rename the bitmap to arg_need_copy itself.

Like this?  Bootstrapped and tested on x86_64-linux.

Thanks,

Martin


2019-08-29  Martin Jambor  <mjambor@suse.cz>

	tree-optimization/91579
	* tree-tailcall.c (tailr_arg_needs_copy): New variable.
	(find_tail_calls): Allocate tailr_arg_needs_copy and set its bits as
	appropriate.
	(arg_needs_copy_p): Removed.
	(eliminate_tail_call): Test tailr_arg_needs_copy instead of calling
	arg_needs_copy_p.
	(tree_optimize_tail_calls_1): Likewise.  Free tailr_arg_needs_copy.

	testsuite/
	* gcc.dg/tree-ssa/pr91579.c: New test.
---
 gcc/testsuite/gcc.dg/tree-ssa/pr91579.c | 22 ++++++++++++
 gcc/tree-tailcall.c                     | 48 +++++++++++++------------
 2 files changed, 47 insertions(+), 23 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr91579.c

diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr91579.c b/gcc/testsuite/gcc.dg/tree-ssa/pr91579.c
new file mode 100644
index 00000000000..ee752be1a85
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr91579.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-tailr1" } */
+
+typedef long unsigned int size_t;
+typedef int (*compare_t)(const void *, const void *);
+
+int partition (void *base, size_t nmemb, size_t size, compare_t cmp);
+
+void
+my_qsort (void *base, size_t nmemb, size_t size, compare_t cmp)
+{
+  int pt;
+  if (nmemb > 1)
+    {
+      pt = partition (base, nmemb, size, cmp);
+      my_qsort (base, pt + 1, size, cmp);
+      my_qsort ((void*)((char*) base + (pt + 1) * size),
+		nmemb - pt - 1, size, cmp);
+    }
+}
+
+/* { dg-final { scan-tree-dump-not "cmp\[^\r\n\]*PHI" "tailr1" } } */
diff --git a/gcc/tree-tailcall.c b/gcc/tree-tailcall.c
index a4b563efd73..4824a5e650f 100644
--- a/gcc/tree-tailcall.c
+++ b/gcc/tree-tailcall.c
@@ -126,6 +126,11 @@ struct tailcall
    accumulator.  */
 static tree m_acc, a_acc;
 
+/* Bitmap with a bit for each function parameter which is set to true if we
+   have to copy the parameter for conversion of tail-recursive calls.  */
+
+static bitmap tailr_arg_needs_copy;
+
 static bool optimize_tail_call (struct tailcall *, bool);
 static void eliminate_tail_call (struct tailcall *);
 
@@ -727,6 +732,18 @@ find_tail_calls (basic_block bb, struct tailcall **ret)
 	  gimple_stmt_iterator mgsi = gsi_for_stmt (stmt);
 	  gsi_move_before (&mgsi, &gsi);
 	}
+      if (!tailr_arg_needs_copy)
+	tailr_arg_needs_copy = BITMAP_ALLOC (NULL);
+      for (param = DECL_ARGUMENTS (current_function_decl), idx = 0;
+	   param;
+	   param = DECL_CHAIN (param), idx++)
+	{
+	  tree ddef, arg = gimple_call_arg (call, idx);
+	  if (is_gimple_reg (param)
+	      && (ddef = ssa_default_def (cfun, param))
+	      && (arg != ddef))
+	    bitmap_set_bit (tailr_arg_needs_copy, idx);
+	}
     }
 
   nw = XNEW (struct tailcall);
@@ -905,25 +922,6 @@ decrease_profile (basic_block bb, profile_count count)
     }
 }
 
-/* Returns true if argument PARAM of the tail recursive call needs to be copied
-   when the call is eliminated.  */
-
-static bool
-arg_needs_copy_p (tree param)
-{
-  tree def;
-
-  if (!is_gimple_reg (param))
-    return false;
-
-  /* Parameters that are only defined but never used need not be copied.  */
-  def = ssa_default_def (cfun, param);
-  if (!def)
-    return false;
-
-  return true;
-}
-
 /* Eliminates tail call described by T.  TMP_VARS is a list of
    temporary variables used to copy the function arguments.  */
 
@@ -1005,7 +1003,7 @@ eliminate_tail_call (struct tailcall *t)
        param;
        param = DECL_CHAIN (param), idx++)
     {
-      if (!arg_needs_copy_p (param))
+      if (!bitmap_bit_p (tailr_arg_needs_copy, idx))
 	continue;
 
       arg = gimple_call_arg (stmt, idx);
@@ -1139,10 +1137,11 @@ tree_optimize_tail_calls_1 (bool opt_tailcalls)
 	      split_edge (single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
 
 	  /* Copy the args if needed.  */
-	  for (param = DECL_ARGUMENTS (current_function_decl);
+	  unsigned idx;
+	  for (param = DECL_ARGUMENTS (current_function_decl), idx = 0;
 	       param;
-	       param = DECL_CHAIN (param))
-	    if (arg_needs_copy_p (param))
+	       param = DECL_CHAIN (param), idx++)
+	    if (bitmap_bit_p (tailr_arg_needs_copy, idx))
 	      {
 		tree name = ssa_default_def (cfun, param);
 		tree new_name = make_ssa_name (param, SSA_NAME_DEF_STMT (name));
@@ -1206,6 +1205,9 @@ tree_optimize_tail_calls_1 (bool opt_tailcalls)
   if (phis_constructed)
     mark_virtual_operands_for_renaming (cfun);
 
+  if (tailr_arg_needs_copy)
+    BITMAP_FREE (tailr_arg_needs_copy);
+
   if (changed)
     return TODO_cleanup_cfg | TODO_update_ssa_only_virtuals;
   return 0;
Richard Biener Aug. 30, 2019, 7:40 a.m. UTC | #3
On Thu, Aug 29, 2019 at 3:56 PM Martin Jambor <mjambor@suse.cz> wrote:
>
> Hi,
>
> On Thu, Aug 29 2019, Richard Biener wrote:
> > On Thu, Aug 29, 2019 at 11:04 AM Martin Jambor <mjambor@suse.cz> wrote:
> >>
> >> Hi,
> >>
> >> when turning a tail-recursive call into a loop, the tail-call pass
> >> creates a phi node for each gimple_reg function parameter that has any
> >> use at all, even when the value passed to the original call is the same
> >> as the received one, when it is the parameter's default definition.
> >> This results in a redundant phi node in which one argument is the
> >> default definition and all others are the LHS of the same phi node.  See
> >> the Bugzilla entry for an example.  These phi nodes in turn confuses
> >> ipa-prop.c which cannot skip them and may not create a pass-through jump
> >> function when it should.
> >>
> >> Fixed by the following patch which just adds a bitmap to remember where
> >> there are non-default-defs passed to a tail-recursive call and then
> >> creates phi nodes only for such parameters.  It has passed bootstrap and
> >> testing on x86_64-linux.
> >>
> >> OK for trunk?
> >
> > OK.  Eventually arg_needs_copy_p can be elided completely
> > and pre-computed into the bitmap so we can just check
> > the positional?  And rename the bitmap to arg_need_copy itself.
>
> Like this?  Bootstrapped and tested on x86_64-linux.

Yes.  This is OK.

Thanks,
Richard.

> Thanks,
>
> Martin
>
>
> 2019-08-29  Martin Jambor  <mjambor@suse.cz>
>
>         tree-optimization/91579
>         * tree-tailcall.c (tailr_arg_needs_copy): New variable.
>         (find_tail_calls): Allocate tailr_arg_needs_copy and set its bits as
>         appropriate.
>         (arg_needs_copy_p): Removed.
>         (eliminate_tail_call): Test tailr_arg_needs_copy instead of calling
>         arg_needs_copy_p.
>         (tree_optimize_tail_calls_1): Likewise.  Free tailr_arg_needs_copy.
>
>         testsuite/
>         * gcc.dg/tree-ssa/pr91579.c: New test.
> ---
>  gcc/testsuite/gcc.dg/tree-ssa/pr91579.c | 22 ++++++++++++
>  gcc/tree-tailcall.c                     | 48 +++++++++++++------------
>  2 files changed, 47 insertions(+), 23 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr91579.c
>
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr91579.c b/gcc/testsuite/gcc.dg/tree-ssa/pr91579.c
> new file mode 100644
> index 00000000000..ee752be1a85
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr91579.c
> @@ -0,0 +1,22 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fdump-tree-tailr1" } */
> +
> +typedef long unsigned int size_t;
> +typedef int (*compare_t)(const void *, const void *);
> +
> +int partition (void *base, size_t nmemb, size_t size, compare_t cmp);
> +
> +void
> +my_qsort (void *base, size_t nmemb, size_t size, compare_t cmp)
> +{
> +  int pt;
> +  if (nmemb > 1)
> +    {
> +      pt = partition (base, nmemb, size, cmp);
> +      my_qsort (base, pt + 1, size, cmp);
> +      my_qsort ((void*)((char*) base + (pt + 1) * size),
> +               nmemb - pt - 1, size, cmp);
> +    }
> +}
> +
> +/* { dg-final { scan-tree-dump-not "cmp\[^\r\n\]*PHI" "tailr1" } } */
> diff --git a/gcc/tree-tailcall.c b/gcc/tree-tailcall.c
> index a4b563efd73..4824a5e650f 100644
> --- a/gcc/tree-tailcall.c
> +++ b/gcc/tree-tailcall.c
> @@ -126,6 +126,11 @@ struct tailcall
>     accumulator.  */
>  static tree m_acc, a_acc;
>
> +/* Bitmap with a bit for each function parameter which is set to true if we
> +   have to copy the parameter for conversion of tail-recursive calls.  */
> +
> +static bitmap tailr_arg_needs_copy;
> +
>  static bool optimize_tail_call (struct tailcall *, bool);
>  static void eliminate_tail_call (struct tailcall *);
>
> @@ -727,6 +732,18 @@ find_tail_calls (basic_block bb, struct tailcall **ret)
>           gimple_stmt_iterator mgsi = gsi_for_stmt (stmt);
>           gsi_move_before (&mgsi, &gsi);
>         }
> +      if (!tailr_arg_needs_copy)
> +       tailr_arg_needs_copy = BITMAP_ALLOC (NULL);
> +      for (param = DECL_ARGUMENTS (current_function_decl), idx = 0;
> +          param;
> +          param = DECL_CHAIN (param), idx++)
> +       {
> +         tree ddef, arg = gimple_call_arg (call, idx);
> +         if (is_gimple_reg (param)
> +             && (ddef = ssa_default_def (cfun, param))
> +             && (arg != ddef))
> +           bitmap_set_bit (tailr_arg_needs_copy, idx);
> +       }
>      }
>
>    nw = XNEW (struct tailcall);
> @@ -905,25 +922,6 @@ decrease_profile (basic_block bb, profile_count count)
>      }
>  }
>
> -/* Returns true if argument PARAM of the tail recursive call needs to be copied
> -   when the call is eliminated.  */
> -
> -static bool
> -arg_needs_copy_p (tree param)
> -{
> -  tree def;
> -
> -  if (!is_gimple_reg (param))
> -    return false;
> -
> -  /* Parameters that are only defined but never used need not be copied.  */
> -  def = ssa_default_def (cfun, param);
> -  if (!def)
> -    return false;
> -
> -  return true;
> -}
> -
>  /* Eliminates tail call described by T.  TMP_VARS is a list of
>     temporary variables used to copy the function arguments.  */
>
> @@ -1005,7 +1003,7 @@ eliminate_tail_call (struct tailcall *t)
>         param;
>         param = DECL_CHAIN (param), idx++)
>      {
> -      if (!arg_needs_copy_p (param))
> +      if (!bitmap_bit_p (tailr_arg_needs_copy, idx))
>         continue;
>
>        arg = gimple_call_arg (stmt, idx);
> @@ -1139,10 +1137,11 @@ tree_optimize_tail_calls_1 (bool opt_tailcalls)
>               split_edge (single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
>
>           /* Copy the args if needed.  */
> -         for (param = DECL_ARGUMENTS (current_function_decl);
> +         unsigned idx;
> +         for (param = DECL_ARGUMENTS (current_function_decl), idx = 0;
>                param;
> -              param = DECL_CHAIN (param))
> -           if (arg_needs_copy_p (param))
> +              param = DECL_CHAIN (param), idx++)
> +           if (bitmap_bit_p (tailr_arg_needs_copy, idx))
>               {
>                 tree name = ssa_default_def (cfun, param);
>                 tree new_name = make_ssa_name (param, SSA_NAME_DEF_STMT (name));
> @@ -1206,6 +1205,9 @@ tree_optimize_tail_calls_1 (bool opt_tailcalls)
>    if (phis_constructed)
>      mark_virtual_operands_for_renaming (cfun);
>
> +  if (tailr_arg_needs_copy)
> +    BITMAP_FREE (tailr_arg_needs_copy);
> +
>    if (changed)
>      return TODO_cleanup_cfg | TODO_update_ssa_only_virtuals;
>    return 0;
> --
> 2.22.0
>
diff mbox series

Patch

diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr91579.c b/gcc/testsuite/gcc.dg/tree-ssa/pr91579.c
new file mode 100644
index 00000000000..ee752be1a85
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr91579.c
@@ -0,0 +1,22 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-tailr1" } */
+
+typedef long unsigned int size_t;
+typedef int (*compare_t)(const void *, const void *);
+
+int partition (void *base, size_t nmemb, size_t size, compare_t cmp);
+
+void
+my_qsort (void *base, size_t nmemb, size_t size, compare_t cmp)
+{
+  int pt;
+  if (nmemb > 1)
+    {
+      pt = partition (base, nmemb, size, cmp);
+      my_qsort (base, pt + 1, size, cmp);
+      my_qsort ((void*)((char*) base + (pt + 1) * size),
+		nmemb - pt - 1, size, cmp);
+    }
+}
+
+/* { dg-final { scan-tree-dump-not "cmp\[^\r\n\]*PHI" "tailr1" } } */
diff --git a/gcc/tree-tailcall.c b/gcc/tree-tailcall.c
index a4b563efd73..23d60f492da 100644
--- a/gcc/tree-tailcall.c
+++ b/gcc/tree-tailcall.c
@@ -126,6 +126,13 @@  struct tailcall
    accumulator.  */
 static tree m_acc, a_acc;
 
+/* Bitmap with a bit for each function parameter which is set to true if in a
+   tail-recursion we pass to the actual argument something else than the
+   default definition of the corresponding formal parameter.  It has no meaning
+   for non-gimple-register parameters.  */
+
+static bitmap tailr_non_ddef_args;
+
 static bool optimize_tail_call (struct tailcall *, bool);
 static void eliminate_tail_call (struct tailcall *);
 
@@ -727,6 +734,17 @@  find_tail_calls (basic_block bb, struct tailcall **ret)
 	  gimple_stmt_iterator mgsi = gsi_for_stmt (stmt);
 	  gsi_move_before (&mgsi, &gsi);
 	}
+      if (!tailr_non_ddef_args)
+	tailr_non_ddef_args = BITMAP_ALLOC (NULL);
+      for (param = DECL_ARGUMENTS (current_function_decl), idx = 0;
+	   param;
+	   param = DECL_CHAIN (param), idx++)
+	{
+	  tree arg = gimple_call_arg (call, idx);
+	  if (is_gimple_reg (param)
+	      && (arg != ssa_default_def (cfun, param)))
+	    bitmap_set_bit (tailr_non_ddef_args, idx);
+	}
     }
 
   nw = XNEW (struct tailcall);
@@ -905,11 +923,11 @@  decrease_profile (basic_block bb, profile_count count)
     }
 }
 
-/* Returns true if argument PARAM of the tail recursive call needs to be copied
-   when the call is eliminated.  */
+/* Returns true if PARAM, which is the IDX-th argument of the tail recursively
+   called function, needs to be copied when the call is eliminated.  */
 
 static bool
-arg_needs_copy_p (tree param)
+arg_needs_copy_p (tree param, unsigned idx)
 {
   tree def;
 
@@ -918,7 +936,7 @@  arg_needs_copy_p (tree param)
 
   /* Parameters that are only defined but never used need not be copied.  */
   def = ssa_default_def (cfun, param);
-  if (!def)
+  if (!def || !bitmap_bit_p (tailr_non_ddef_args, idx))
     return false;
 
   return true;
@@ -1005,7 +1023,7 @@  eliminate_tail_call (struct tailcall *t)
        param;
        param = DECL_CHAIN (param), idx++)
     {
-      if (!arg_needs_copy_p (param))
+      if (!arg_needs_copy_p (param, idx))
 	continue;
 
       arg = gimple_call_arg (stmt, idx);
@@ -1139,10 +1157,11 @@  tree_optimize_tail_calls_1 (bool opt_tailcalls)
 	      split_edge (single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
 
 	  /* Copy the args if needed.  */
-	  for (param = DECL_ARGUMENTS (current_function_decl);
+	  unsigned idx;
+	  for (param = DECL_ARGUMENTS (current_function_decl), idx = 0;
 	       param;
-	       param = DECL_CHAIN (param))
-	    if (arg_needs_copy_p (param))
+	       param = DECL_CHAIN (param), idx++)
+	    if (arg_needs_copy_p (param, idx))
 	      {
 		tree name = ssa_default_def (cfun, param);
 		tree new_name = make_ssa_name (param, SSA_NAME_DEF_STMT (name));
@@ -1206,6 +1225,9 @@  tree_optimize_tail_calls_1 (bool opt_tailcalls)
   if (phis_constructed)
     mark_virtual_operands_for_renaming (cfun);
 
+  if (tailr_non_ddef_args)
+    BITMAP_FREE (tailr_non_ddef_args);
+
   if (changed)
     return TODO_cleanup_cfg | TODO_update_ssa_only_virtuals;
   return 0;