From 500e4868bf5c89a3136fb329293872d29632ffad Mon Sep 17 00:00:00 2001
From: Jakub Jelinek <jakub@redhat.com>
Date: Mon, 20 May 2019 23:33:46 +0200
Subject: [PATCH] re PR c++/59813 (tail-call elimination didn't fire for
 left-shift of char to cout)

	PR c++/59813
	PR target/90418
	* function.h (struct function): Add calls_eh_return member.
	* gimplify.c (gimplify_call_expr): Set cfun->calls_eh_return when
	gimplifying __builtin_eh_return call.
	* tree-inline.c (initialize_cfun): Copy calls_eh_return from src_cfun
	to cfun.
	(expand_call_inline): Or in src_cfun->calls_eh_return into
	dst_cfun->calls_eh_return.
	* tree-tailcall.c (suitable_for_tail_call_opt_p): Return false if
	cfun->calls_eh_return.
	* lto-streamer-in.c (input_struct_function_base): Read calls_eh_return.
	* lto-streamer-out.c (output_struct_function_base): Write
	calls_eh_return.

From-SVN: r271440
---
 gcc/ChangeLog          | 17 +++++++++++++++++
 gcc/function.h         |  3 +++
 gcc/gimplify.c         |  4 ++++
 gcc/lto-streamer-in.c  |  1 +
 gcc/lto-streamer-out.c |  1 +
 gcc/tree-inline.c      |  2 ++
 gcc/tree-tailcall.c    |  6 ++++++
 7 files changed, 34 insertions(+)

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 5d300cab8166..1c4e714e7d10 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,20 @@
+2019-05-20  Jakub Jelinek  <jakub@redhat.com>
+
+	PR c++/59813
+	PR target/90418
+	* function.h (struct function): Add calls_eh_return member.
+	* gimplify.c (gimplify_call_expr): Set cfun->calls_eh_return when
+	gimplifying __builtin_eh_return call.
+	* tree-inline.c (initialize_cfun): Copy calls_eh_return from src_cfun
+	to cfun.
+	(expand_call_inline): Or in src_cfun->calls_eh_return into
+	dst_cfun->calls_eh_return.
+	* tree-tailcall.c (suitable_for_tail_call_opt_p): Return false if
+	cfun->calls_eh_return.
+	* lto-streamer-in.c (input_struct_function_base): Read calls_eh_return.
+	* lto-streamer-out.c (output_struct_function_base): Write
+	calls_eh_return.
+
 2019-05-20  Marc Glisse  <marc.glisse@inria.fr>
 
 	PR rtl-optimization/43147
diff --git a/gcc/function.h b/gcc/function.h
index cef093c81467..bfe9919a760f 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -327,6 +327,9 @@ struct GTY(()) function {
      either as a subroutine or builtin.  */
   unsigned int calls_alloca : 1;
 
+  /* Nonzero if function being compiled can call __builtin_eh_return.  */
+  unsigned int calls_eh_return : 1;
+
   /* Nonzero if function being compiled receives nonlocal gotos
      from nested functions.  */
   unsigned int has_nonlocal_label : 1;
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index bc2000d4d803..5bacb255ba75 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -3297,6 +3297,10 @@ gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, bool want_value)
 	  break;
 	}
 
+      case BUILT_IN_EH_RETURN:
+	cfun->calls_eh_return = true;
+	break;
+
       default:
         ;
       }
diff --git a/gcc/lto-streamer-in.c b/gcc/lto-streamer-in.c
index b78b7cb1ad2e..49fd5730c703 100644
--- a/gcc/lto-streamer-in.c
+++ b/gcc/lto-streamer-in.c
@@ -1005,6 +1005,7 @@ input_struct_function_base (struct function *fn, struct data_in *data_in,
   fn->has_forced_label_in_static = bp_unpack_value (&bp, 1);
   fn->calls_alloca = bp_unpack_value (&bp, 1);
   fn->calls_setjmp = bp_unpack_value (&bp, 1);
+  fn->calls_eh_return = bp_unpack_value (&bp, 1);
   fn->has_force_vectorize_loops = bp_unpack_value (&bp, 1);
   fn->has_simduid_loops = bp_unpack_value (&bp, 1);
   fn->va_list_fpr_size = bp_unpack_value (&bp, 8);
diff --git a/gcc/lto-streamer-out.c b/gcc/lto-streamer-out.c
index b6e395b53fd9..e22a9e596e1d 100644
--- a/gcc/lto-streamer-out.c
+++ b/gcc/lto-streamer-out.c
@@ -2029,6 +2029,7 @@ output_struct_function_base (struct output_block *ob, struct function *fn)
   bp_pack_value (&bp, fn->has_forced_label_in_static, 1);
   bp_pack_value (&bp, fn->calls_alloca, 1);
   bp_pack_value (&bp, fn->calls_setjmp, 1);
+  bp_pack_value (&bp, fn->calls_eh_return, 1);
   bp_pack_value (&bp, fn->has_force_vectorize_loops, 1);
   bp_pack_value (&bp, fn->has_simduid_loops, 1);
   bp_pack_value (&bp, fn->va_list_fpr_size, 8);
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index 7598674f39c5..719846ac9a2e 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -2662,6 +2662,7 @@ initialize_cfun (tree new_fndecl, tree callee_fndecl, profile_count count)
   cfun->va_list_gpr_size = src_cfun->va_list_gpr_size;
   cfun->va_list_fpr_size = src_cfun->va_list_fpr_size;
   cfun->has_nonlocal_label = src_cfun->has_nonlocal_label;
+  cfun->calls_eh_return = src_cfun->calls_eh_return;
   cfun->stdarg = src_cfun->stdarg;
   cfun->after_inlining = src_cfun->after_inlining;
   cfun->can_throw_non_call_exceptions
@@ -4778,6 +4779,7 @@ expand_call_inline (basic_block bb, gimple *stmt, copy_body_data *id)
   src_properties = id->src_cfun->curr_properties & prop_mask;
   if (src_properties != prop_mask)
     dst_cfun->curr_properties &= src_properties | ~prop_mask;
+  dst_cfun->calls_eh_return |= id->src_cfun->calls_eh_return;
 
   gcc_assert (!id->src_cfun->after_inlining);
 
diff --git a/gcc/tree-tailcall.c b/gcc/tree-tailcall.c
index f4835854e00b..a99cd113ce66 100644
--- a/gcc/tree-tailcall.c
+++ b/gcc/tree-tailcall.c
@@ -140,6 +140,7 @@ suitable_for_tail_opt_p (void)
 
   return true;
 }
+
 /* Returns false when the function is not suitable for tail call optimization
    for some reason (e.g. if it takes variable number of arguments).
    This test must pass in addition to suitable_for_tail_opt_p in order to make
@@ -168,6 +169,11 @@ suitable_for_tail_call_opt_p (void)
   if (cfun->calls_setjmp)
     return false;
 
+  /* Various targets don't handle tail calls correctly in functions
+     that call __builtin_eh_return.  */
+  if (cfun->calls_eh_return)
+    return false;
+
   /* ??? It is OK if the argument of a function is taken in some cases,
      but not in all cases.  See PR15387 and PR19616.  Revisit for 4.1.  */
   for (param = DECL_ARGUMENTS (current_function_decl);
-- 
GitLab