From 127f604d54518a7449caad40740f9fef31f27d9f Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Wed, 14 May 2014 17:10:37 -0400
Subject: [PATCH 22/29] Introduce greturn

This corresponds to:
  "[PATCH 21/89] Introduce gimple_return"
    https://gcc.gnu.org/ml/gcc-patches/2014-04/msg01180.html
from v1 of the patch series.

gcc/
	* coretypes.h (greturn): Add forward declaration.

	* gimple.h (greturn): New subclass of gimple_with_memory_ops,
	adding the invariant that stmt->code == GIMPLE_RETURN.
	(is_a_helper <greturn *>::test): New.
	(gimple_build_return): Return a greturn rather
	than a plain gimple.

	* gimple.c (gimple_build_return): Return a greturn rather
	than a plain gimple.

	* cgraphunit.c (expand_thunk): Convert local from a gimple to
	a greturn.

	* gimple-low.c (struct return_statements_t): Convert field "stmt"
	from a gimple to a greturn.
	(lower_gimple_return): Convert local from a gimple to a
	greturn.

	* gimple-pretty-print.c (dump_gimple_return): Require a
	greturn rather than a plain gimple.
	(pp_gimple_stmt_1): Add a checked cast to greturn within
	case GIMPLE_RETURN of switch statement.

	* gimplify.c (gimplify_return_expr): Convert locals from
	gimple to greturn.

	* ipa-split.c (split_function): Likewise.

	* tree-cfg.c (verify_gimple_assign): Require a greturn
	rather than a plain gimple.
	(verify_gimple_stmt): Add checked cast to greturn within
	case GIMPLE_RETURN of switch statement.

	* tree-tailcall.c (adjust_return_value): Convert local from
	gimple to greturn.

	* doc/gimple.texi: Update for above changes.
---
 gcc/cgraphunit.c          |  2 +-
 gcc/coretypes.h           |  1 +
 gcc/doc/gimple.texi       | 10 ++++++----
 gcc/gimple-low.c          |  4 ++--
 gcc/gimple-pretty-print.c |  4 ++--
 gcc/gimple.c              |  5 +++--
 gcc/gimple.h              | 20 +++++++++++++++++++-
 gcc/gimplify.c            |  4 ++--
 gcc/ipa-split.c           |  2 +-
 gcc/tree-cfg.c            |  4 ++--
 gcc/tree-tailcall.c       |  2 +-
 11 files changed, 40 insertions(+), 18 deletions(-)

diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index eb25f73..f411010 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -1532,7 +1532,7 @@ expand_thunk (struct cgraph_node *node, bool output_asm_thunks)
       tree restmp = NULL;
 
       gcall *call;
-      gimple *ret;
+      greturn *ret;
 
       if (in_lto_p)
 	cgraph_get_body (node);
diff --git a/gcc/coretypes.h b/gcc/coretypes.h
index 9b2197d..32b338a 100644
--- a/gcc/coretypes.h
+++ b/gcc/coretypes.h
@@ -76,6 +76,7 @@ class glabel;
 class gswitch;
 class gassign;
 class gcall;
+class greturn;
 class gbind;
 class gphi;
 
diff --git a/gcc/doc/gimple.texi b/gcc/doc/gimple.texi
index 6a5e9b5..af188a9 100644
--- a/gcc/doc/gimple.texi
+++ b/gcc/doc/gimple.texi
@@ -330,11 +330,13 @@ kinds, along with their relationships to @code{GSS_} values (layouts) and
      |       |    layout: GSS_WITH_MEM_OPS_BASE
      |       |
      |       + gimple_with_memory_ops
-     |       |   |    layout: GSS_WITH_MEM_OPS.
-     |       |   |    used for code GIMPLE_RETURN.
+     |       |   |    layout: GSS_WITH_MEM_OPS
      |       |   |
      |       |   + gassign
-     |       |           code: GIMPLE_ASSIGN
+     |       |   |       code: GIMPLE_ASSIGN
+     |       |   |
+     |       |   + gassign
+     |       |           code: GIMPLE_RETURN
      |       |
      |       + gcall
      |       |        layout: GSS_CALL, code: GIMPLE_CALL
@@ -2246,7 +2248,7 @@ Set @code{REGION} to be the region number for @code{GIMPLE_RESX} @code{G}.
 @subsection @code{GIMPLE_RETURN}
 @cindex @code{GIMPLE_RETURN}
 
-@deftypefn {GIMPLE function} gimple *gimple_build_return (tree retval)
+@deftypefn {GIMPLE function} greturn *gimple_build_return (tree retval)
 Build a @code{GIMPLE_RETURN} statement whose return value is retval.
 @end deftypefn
 
diff --git a/gcc/gimple-low.c b/gcc/gimple-low.c
index 310c97d..1dc958e 100644
--- a/gcc/gimple-low.c
+++ b/gcc/gimple-low.c
@@ -60,7 +60,7 @@ along with GCC; see the file COPYING3.  If not see
 struct return_statements_t
 {
   tree label;
-  gimple *stmt;
+  greturn *stmt;
 };
 typedef struct return_statements_t return_statements_t;
 
@@ -620,7 +620,7 @@ gimple_seq_may_fallthru (gimple_seq seq)
 static void
 lower_gimple_return (gimple_stmt_iterator *gsi, struct lower_data *data)
 {
-  gimple *stmt = gsi_stmt (*gsi);
+  greturn *stmt = as_a <greturn *> (gsi_stmt (*gsi));
   gimple *t;
   int i;
   return_statements_t tmp_rs;
diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c
index ab068e5..98b2e81 100644
--- a/gcc/gimple-pretty-print.c
+++ b/gcc/gimple-pretty-print.c
@@ -545,7 +545,7 @@ dump_gimple_assign (pretty_printer *buffer, gassign *gs, int spc, int flags)
    pp_gimple_stmt_1.  */
 
 static void
-dump_gimple_return (pretty_printer *buffer, gimple *gs, int spc, int flags)
+dump_gimple_return (pretty_printer *buffer, greturn *gs, int spc, int flags)
 {
   tree t;
 
@@ -2116,7 +2116,7 @@ pp_gimple_stmt_1 (pretty_printer *buffer, gimple *gs, int spc, int flags)
       break;
 
     case GIMPLE_RETURN:
-      dump_gimple_return (buffer, gs, spc, flags);
+      dump_gimple_return (buffer, as_a <greturn *> (gs), spc, flags);
       break;
 
     case GIMPLE_SWITCH:
diff --git a/gcc/gimple.c b/gcc/gimple.c
index 9acffa2..6232661 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -177,10 +177,11 @@ gimple_build_with_ops_stat (enum gimple_code code, unsigned subcode,
 
 /* Build a GIMPLE_RETURN statement returning RETVAL.  */
 
-gimple *
+greturn *
 gimple_build_return (tree retval)
 {
-  gimple *s = gimple_build_with_ops (GIMPLE_RETURN, ERROR_MARK, 1);
+  greturn *s = as_a <greturn *> (gimple_build_with_ops (GIMPLE_RETURN,
+							ERROR_MARK, 1));
   if (retval)
     gimple_return_set_retval (s, retval);
   return s;
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 8522967..bf15c07 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -810,6 +810,16 @@ struct GTY((tag("GSS_WITH_MEM_OPS")))
   /* no additional fields; this uses the layout for GSS_WITH_MEM_OPS. */
 };
 
+/* A statement with the invariant that
+      stmt->code == GIMPLE_RETURN
+   i.e. a return statement.  */
+
+struct GTY((tag("GSS_WITH_MEM_OPS")))
+  greturn : public gimple_with_memory_ops
+{
+  /* no additional fields; this uses the layout for GSS_WITH_MEM_OPS. */
+};
+
 template <>
 template <>
 inline bool
@@ -1037,6 +1047,14 @@ is_a_helper <gswitch *>::test (gimple *gs)
 template <>
 template <>
 inline bool
+is_a_helper <greturn *>::test (gimple *gs)
+{
+  return gs->code == GIMPLE_RETURN;
+}
+
+template <>
+template <>
+inline bool
 is_a_helper <gtransaction *>::test (gimple *gs)
 {
   return gs->code == GIMPLE_TRANSACTION;
@@ -1255,7 +1273,7 @@ extern gimple *currently_expanding_gimple_stmt;
 
 #define gimple_alloc(c, n) gimple_alloc_stat (c, n MEM_STAT_INFO)
 gimple *gimple_alloc_stat (enum gimple_code, unsigned MEM_STAT_DECL);
-gimple *gimple_build_return (tree);
+greturn *gimple_build_return (tree);
 void gimple_call_reset_alias_info (gcall *);
 gcall *gimple_build_call_vec (tree, vec<tree> );
 gcall *gimple_build_call (tree, unsigned, ...);
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 4668fd2..22afe63 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -1172,7 +1172,7 @@ gimplify_bind_expr (tree *expr_p, gimple_seq *pre_p)
 static enum gimplify_status
 gimplify_return_expr (tree stmt, gimple_seq *pre_p)
 {
-  gimple *ret;
+  greturn *ret;
   tree ret_expr = TREE_OPERAND (stmt, 0);
   tree result_decl, result;
 
@@ -1192,7 +1192,7 @@ gimplify_return_expr (tree stmt, gimple_seq *pre_p)
       || TREE_CODE (ret_expr) == RESULT_DECL
       || ret_expr == error_mark_node)
     {
-      gimple *ret = gimple_build_return (ret_expr);
+      greturn *ret = gimple_build_return (ret_expr);
       gimple_set_no_warning (ret, TREE_NO_WARNING (stmt));
       gimplify_seq_add_stmt (pre_p, ret);
       return GS_ALL_DONE;
diff --git a/gcc/ipa-split.c b/gcc/ipa-split.c
index 2450e95..55f585d 100644
--- a/gcc/ipa-split.c
+++ b/gcc/ipa-split.c
@@ -1465,7 +1465,7 @@ split_function (struct split_point *split_point)
 	 */
       else
 	{
-	  gimple *ret;
+	  greturn *ret;
 	  if (split_point->split_part_set_retval
 	      && !VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))))
 	    {
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index c324110..b2062a3 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -4200,7 +4200,7 @@ verify_gimple_assign (gassign *stmt)
    is a problem, otherwise false.  */
 
 static bool
-verify_gimple_return (gimple *stmt)
+verify_gimple_return (greturn *stmt)
 {
   tree op = gimple_return_retval (stmt);
   tree restype = TREE_TYPE (TREE_TYPE (cfun->decl));
@@ -4448,7 +4448,7 @@ verify_gimple_stmt (gimple *stmt)
       return verify_gimple_switch (as_a <gswitch *> (stmt));
 
     case GIMPLE_RETURN:
-      return verify_gimple_return (stmt);
+      return verify_gimple_return (as_a <greturn *> (stmt));
 
     case GIMPLE_ASM:
       return false;
diff --git a/gcc/tree-tailcall.c b/gcc/tree-tailcall.c
index 935281f..12b1615 100644
--- a/gcc/tree-tailcall.c
+++ b/gcc/tree-tailcall.c
@@ -747,7 +747,7 @@ static void
 adjust_return_value (basic_block bb, tree m, tree a)
 {
   tree retval;
-  gimple *ret_stmt = gimple_seq_last_stmt (bb_seq (bb));
+  greturn *ret_stmt = as_a <greturn *> (gimple_seq_last_stmt (bb_seq (bb)));
   gimple_stmt_iterator gsi = gsi_last_bb (bb);
 
   gcc_assert (gimple_code (ret_stmt) == GIMPLE_RETURN);
-- 
1.8.5.3

