public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [tuples] gimple-low and assorted machinery
@ 2007-08-08 18:12 Aldy Hernandez
  2007-08-09 14:52 ` Diego Novillo
  0 siblings, 1 reply; 2+ messages in thread
From: Aldy Hernandez @ 2007-08-08 18:12 UTC (permalink / raw)
  To: dnovillo, amacleod, gcc-patches

Hi Diego.  Hi folks.

This is a fairly big patch.  I thought I could do it incrementally, but
unfortunately there was too much to change at once.  This patch converts
the entire gimple-low to tuples, but it hasn't been thoroughly tested,
since I am running into a GC problem with the pointer map we use for
gimple_body.  Consequently it is disabled for now.

A few things I'd like to point out.

1. I've implemented [most of] the rest of the gimple-iterator functions.
   They work as the tree-iterator ones, except that we have sequence
   and statement versions for things like:

	gsi_link_seq_before/gsi_link_before
	gsi_link_seq_after/gsi_link_after

   The only difference in functionality is that gsi_delink() will kill
   any next/prev links, to make sure no dangling pointers persist.  This
   way, you can remove a statement from a sequence, but still keep it
   and add it to another sequence.

2. There are now two versions of block_may_fallthru.  The other one is
   gimple_seq_may_fallthru which works for tuples.  The tree version is
   still needed for converting from GENERIC to gimple high, and in
   c_finish_bc_stmt in the C parser.

3. We have a version of call_expr_flags for tuples: gimple_call_flags.
   Yes, it sucks to have duplicate functionality, but we need a tuples
   version *and* a tree version.

4. ``struct gimple_statement_bind'' now has a `block' field.  This is
   the equivalent of BIND_EXPR_BLOCK in tree land, and is different from
   the `block' in gimple_statement_base which is analogous to TREE_BLOCK.

   Diego, could you please update the design document?

5. Much to my dismay, we need the equivalent of get_callee_fndecl() from
   tree land.  This function needs to return NULL if we don't have a
   FUNCTION_DECL (a function being called through a pointer).

   In the GIMPLE_CALL tuple, we store the result from
   get_callee_fndecl() as Diego had suggested, but we also need (after
   gimplification) to do things depending on whether we have a
   FUNCTION_DECL or not.

   So now we have gimple_call_fndecl() which behaves like
   get_callee_fndecl().  It was either this, or kludging get_callee_fndecl,
   or worse-- having to manually check whether the function being called
   was a VAR_DECL or a FUNCTION_DECL.

I am commiting the patch below, just to make sure we're all on the same
page, but I would greatly appreciate an extra set of eyes on this.

I am also disabling the pass for now, until I find out how to resolve
the pointer map collection problem wrt gimple_body.

So long, and thanks for all the fish.

	* gimple-low.c (struct return_statements_t): Declare.
	(struct lower_data): Make return_statements a vector.
	(lower_function_body): Adjust for tuples.
	(pass_lower_cf): Add PROP_gimple_any to properties_required.
	(lower_sequence): Rename from lower_stmt_body.
	Adjust for tuples.
	(lower_omp_directive): Adjust for tuples.
	(lower_stmt): Same.
	(lower_gimple_bind): Rename from lower_bind_expr.
	Adjust for tuples.
	(gimple_try_catch_may_fallthru): New.
	(gimple_seq_may_fallthru): New.
	(lower_gimple_return): Rename from lower_return_expr and adjust
	for tuples.
	(lower_builtin_setjmp): Adjust for tuples.
	* gimple-iterator.c: New.
	* gimple-iterator.h: Include gimple.h.
	(enum gsi_iterator_update): Declare.
	(gsi_link_seq_before): New prototype.
	(gsi_link_before): Same.
	(gsi_link_seq_after): Same.
	(gsi_link_after): Same.
	(gsi_delink): Same.
	* gimplify.c (gimplify_body): Comment out verify_gimple_1 call.
	* tree-flow.h (gimple_seq_may_fallthru): New prototype.
	* Makefile.in (OBJS-common): Add gimple-iterator.o.
	(gimple-iterator.o): New.
	(gimple-pretty-print.o): Do not depend on gimple-iterator.h.
	* gimple.c (set_gimple_prev): Move to gimple.h.
	(set_gimple_next): Same.
	(gimple_call_flags): New.
	* gimple.h (struct gimple_sequence): Add GTY marker.
	(struct gimple_statement_bind): Add block field.
	(set_gimple_prev): New.
	(set_gimple_next): New.
	(gimple_call_flags): Protoize.
	(gimple_call_fndecl): New.
	(gimple_bind_block): New.
	(gimple_bind_set_block): New.

Index: gimple-low.c
===================================================================
--- gimple-low.c	(revision 127301)
+++ gimple-low.c	(working copy)
@@ -40,24 +40,43 @@ along with GCC; see the file COPYING3.  
 #include "toplev.h"
 #include "tree-pass.h"
 
+/* FIXME tuples: vec.h says:
+
+   Due to the way GTY works, you must annotate
+   any structures you wish to insert or reference from a vector with a
+   GTY(()) tag.  You need to do this even if you never declare the GC
+   allocated variants.
+
+   Does this mean we need to GTY mark both struct return_statements_t
+   and struct lower_data.
+   ?? */
+struct return_statements_t
+{
+  tree label;
+  gimple stmt;
+};
+typedef struct return_statements_t return_statements_t;
+
+DEF_VEC_O(return_statements_t);
+DEF_VEC_ALLOC_O(return_statements_t,heap);
+
 struct lower_data
 {
   /* Block the current statement belongs to.  */
   tree block;
 
-  /* A TREE_LIST of label and return statements to be moved to the end
+  /* A vector of label and return statements to be moved to the end
      of the function.  */
-  tree return_statements;
+  VEC(return_statements_t,heap) *return_statements;
 
   /* True if the function calls __builtin_setjmp.  */
   bool calls_builtin_setjmp;
 };
 
-static void lower_stmt (tree_stmt_iterator *, struct lower_data *);
-static void lower_bind_expr (tree_stmt_iterator *, struct lower_data *);
-static void lower_cond_expr (tree_stmt_iterator *, struct lower_data *);
-static void lower_return_expr (tree_stmt_iterator *, struct lower_data *);
-static void lower_builtin_setjmp (tree_stmt_iterator *);
+static void lower_stmt (gimple_stmt_iterator *, struct lower_data *);
+static void lower_gimple_bind (gimple_stmt_iterator *, struct lower_data *);
+static void lower_gimple_return (gimple_stmt_iterator *, struct lower_data *);
+static void lower_builtin_setjmp (gimple_stmt_iterator *);
 
 /* Lower the body of current_function_decl.  */
 
@@ -65,55 +84,64 @@ static unsigned int
 lower_function_body (void)
 {
   struct lower_data data;
-  tree *body_p = &DECL_SAVED_TREE (current_function_decl);
-  tree bind = *body_p;
-  tree_stmt_iterator i;
-  tree t, x;
+  gimple_seq body_seq = gimple_body (current_function_decl);
+  gimple bind = gimple_seq_first (body_seq);
+  gimple_stmt_iterator *i;
+  tree t;
+  gimple x;
 
-  gcc_assert (TREE_CODE (bind) == BIND_EXPR);
+  gcc_assert (gimple_code (bind) == GIMPLE_BIND);
 
   memset (&data, 0, sizeof (data));
   data.block = DECL_INITIAL (current_function_decl);
   BLOCK_SUBBLOCKS (data.block) = NULL_TREE;
   BLOCK_CHAIN (data.block) = NULL_TREE;
   TREE_ASM_WRITTEN (data.block) = 1;
+  data.return_statements = VEC_alloc (return_statements_t, heap, 8);
 
-  *body_p = alloc_stmt_list ();
-  i = tsi_start (*body_p);
-  tsi_link_after (&i, bind, TSI_NEW_STMT);
-  lower_bind_expr (&i, &data);
+  gimple_seq_init (body_seq);
+  gimple_add (body_seq, bind);
+  i = gsi_start (body_seq);
+  lower_gimple_bind (i, &data);
 
-  i = tsi_last (*body_p);
+  i = gsi_last (body_seq);
 
   /* If the function falls off the end, we need a null return statement.
-     If we've already got one in the return_statements list, we don't
+     If we've already got one in the return_statements vector, we don't
      need to do anything special.  Otherwise build one by hand.  */
-  if (block_may_fallthru (*body_p)
-      && (data.return_statements == NULL
-          || TREE_OPERAND (TREE_VALUE (data.return_statements), 0) != NULL))
-    {
-      x = build1 (RETURN_EXPR, void_type_node, NULL);
-      SET_EXPR_LOCATION (x, cfun->function_end_locus);
-      tsi_link_after (&i, x, TSI_CONTINUE_LINKING);
+  if (gimple_seq_may_fallthru (body_seq)
+      && (VEC_empty (return_statements_t, data.return_statements)
+	  || gimple_return_retval
+	       (VEC_last (return_statements_t,
+			  data.return_statements)->stmt) != NULL))
+    {
+      x = build_gimple_return (false, NULL);
+      set_gimple_locus (x, cfun->function_end_locus);
+      gsi_link_after (i, x, GSI_CONTINUE_LINKING);
     }
 
   /* If we lowered any return statements, emit the representative
      at the end of the function.  */
-  for (t = data.return_statements ; t ; t = TREE_CHAIN (t))
+  while (!VEC_empty (return_statements_t, data.return_statements))
     {
-      x = build1 (LABEL_EXPR, void_type_node, TREE_PURPOSE (t));
-      tsi_link_after (&i, x, TSI_CONTINUE_LINKING);
+      return_statements_t t;
+
+      /* Unfortunately, we can't use VEC_pop because it returns void for
+	 objects.  */
+      t = *VEC_last (return_statements_t, data.return_statements);
+      VEC_truncate (return_statements_t,
+	  	    data.return_statements,
+	  	    VEC_length (return_statements_t,
+		      		data.return_statements) - 1);
+
+      x = build_gimple_label (t.label);
+      gsi_link_after (i, x, GSI_CONTINUE_LINKING);
 
       /* Remove the line number from the representative return statement.
 	 It now fills in for many such returns.  Failure to remove this
 	 will result in incorrect results for coverage analysis.  */
-      x = TREE_VALUE (t);
-#ifdef USE_MAPPED_LOCATION
-      SET_EXPR_LOCATION (x, UNKNOWN_LOCATION);
-#else
-      SET_EXPR_LOCUS (x, NULL);
-#endif
-      tsi_link_after (&i, x, TSI_CONTINUE_LINKING);
+      set_gimple_locus (t.stmt, unknown_location);
+      gsi_link_after (i, t.stmt, GSI_CONTINUE_LINKING);
     }
 
   /* If the function calls __builtin_setjmp, we need to emit the computed
@@ -127,21 +155,21 @@ lower_function_body (void)
       /* This mark will create forward edges from every call site.  */
       DECL_NONLOCAL (disp_label) = 1;
       current_function_has_nonlocal_label = 1;
-      x = build1 (LABEL_EXPR, void_type_node, disp_label);
-      tsi_link_after (&i, x, TSI_CONTINUE_LINKING);
+      x = build_gimple_label (disp_label);
+      gsi_link_after (i, x, GSI_CONTINUE_LINKING);
 
       /* Build 'DISP_VAR = __builtin_setjmp_dispatcher (DISP_LABEL);'
 	 and insert.  */
       disp_var = create_tmp_var (ptr_type_node, "setjmpvar");
       arg = build_addr (disp_label, current_function_decl);
       t = implicit_built_in_decls[BUILT_IN_SETJMP_DISPATCHER];
-      t = build_call_expr (t, 1, arg);
-      x = build_gimple_modify_stmt (disp_var, t);
+      x = build_gimple_call (t, 1, arg);
+      gimple_call_set_lhs (x, disp_var);
 
       /* Build 'goto DISP_VAR;' and insert.  */
-      tsi_link_after (&i, x, TSI_CONTINUE_LINKING);
-      x = build1 (GOTO_EXPR, void_type_node, disp_var);
-      tsi_link_after (&i, x, TSI_CONTINUE_LINKING);
+      gsi_link_after (i, x, GSI_CONTINUE_LINKING);
+      x = build_gimple_goto (disp_var);
+      gsi_link_after (i, x, GSI_CONTINUE_LINKING);
     }
 
   gcc_assert (data.block == DECL_INITIAL (current_function_decl));
@@ -149,6 +177,7 @@ lower_function_body (void)
     = blocks_nreverse (BLOCK_SUBBLOCKS (data.block));
 
   clear_block_marks (data.block);
+  VEC_free(return_statements_t, heap, data.return_statements);
   return 0;
 }
 
@@ -161,7 +190,14 @@ struct tree_opt_pass pass_lower_cf = 
   NULL,					/* next */
   0,					/* static_pass_number */
   0,					/* tv_id */
+  /* FIXME tuples: PROP_gimple_any is not available yet, because it
+     gets set through todo_flags_start in remove_useless_stmts, which
+     is still not converted.  */
+#if 0
   PROP_gimple_any,			/* properties_required */
+#else
+  0,
+#endif
   PROP_gimple_lcf,			/* properties_provided */
   0,					/* properties_destroyed */
   0,					/* todo_flags_start */
@@ -171,130 +207,126 @@ struct tree_opt_pass pass_lower_cf = 
 };
 
 
-/* Lower the EXPR.  Unlike gimplification the statements are not relowered
+/* Lower sequence SEQ.  Unlike gimplification the statements are not relowered
    when they are changed -- if this has to be done, the lowering routine must
    do it explicitly.  DATA is passed through the recursion.  */
 
 static void
-lower_stmt_body (tree expr, struct lower_data *data)
+lower_sequence (gimple_seq seq, struct lower_data *data)
 {
-  tree_stmt_iterator tsi;
+  gimple_stmt_iterator *gsi;
 
-  for (tsi = tsi_start (expr); !tsi_end_p (tsi); )
-    lower_stmt (&tsi, data);
+  for (gsi = gsi_start (seq); !gsi_end_p (gsi); )
+    lower_stmt (gsi, data);
 }
 
 
-/* Lower the OpenMP directive statement pointed by TSI.  DATA is
+/* Lower the OpenMP directive statement pointed by GSI.  DATA is
    passed through the recursion.  */
 
 static void
-lower_omp_directive (tree_stmt_iterator *tsi, struct lower_data *data)
+lower_omp_directive (gimple_stmt_iterator *gsi, struct lower_data *data)
 {
-  tree stmt;
+  gimple stmt;
   
-  stmt = tsi_stmt (*tsi);
+  stmt = gsi_stmt (gsi);
 
-  lower_stmt_body (OMP_BODY (stmt), data);
-  tsi_link_before (tsi, stmt, TSI_SAME_STMT);
-  tsi_link_before (tsi, OMP_BODY (stmt), TSI_SAME_STMT);
+  /* FIXME tuples
+  lower_sequence (OMP_BODY (stmt), data);
+  gsi_link_before (gsi, stmt, GSI_SAME_STMT);
+  gsi_link_before (gsi, OMP_BODY (stmt), GSI_SAME_STMT);
   OMP_BODY (stmt) = NULL_TREE;
-  tsi_delink (tsi);
+  */
+  gsi_delink (gsi);
 }
 
 
 /* Lower statement TSI.  DATA is passed through the recursion.  */
 
 static void
-lower_stmt (tree_stmt_iterator *tsi, struct lower_data *data)
+lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data)
 {
-  tree stmt = tsi_stmt (*tsi);
+  gimple stmt = gsi_stmt (gsi);
 
-  if (EXPR_HAS_LOCATION (stmt) && data)
-    TREE_BLOCK (stmt) = data->block;
+  set_gimple_block (stmt, data->block);
 
-  switch (TREE_CODE (stmt))
+  switch (gimple_code (stmt))
     {
-    case BIND_EXPR:
-      lower_bind_expr (tsi, data);
-      return;
-    case COND_EXPR:
-      lower_cond_expr (tsi, data);
+    case GIMPLE_BIND:
+      lower_gimple_bind (gsi, data);
       return;
-    case RETURN_EXPR:
-      lower_return_expr (tsi, data);
+    case GIMPLE_COND:
+      /* The high gimplifier has already lowered this into gotos.  */
+      break;
+    case GIMPLE_RETURN:
+      lower_gimple_return (gsi, data);
       return;
 
-    case TRY_FINALLY_EXPR:
-    case TRY_CATCH_EXPR:
-      lower_stmt_body (TREE_OPERAND (stmt, 0), data);
-      lower_stmt_body (TREE_OPERAND (stmt, 1), data);
+    case GIMPLE_TRY:
+      lower_sequence (gimple_try_eval (stmt), data);
+      lower_sequence (gimple_try_cleanup (stmt), data);
       break;
-    case CATCH_EXPR:
-      lower_stmt_body (CATCH_BODY (stmt), data);
-      break;
-    case EH_FILTER_EXPR:
-      lower_stmt_body (EH_FILTER_FAILURE (stmt), data);
+
+    case GIMPLE_CATCH:
+      lower_sequence (gimple_catch_handler (stmt), data);
       break;
-      
-    case NOP_EXPR:
-    case ASM_EXPR:
-    case GOTO_EXPR:
-    case LABEL_EXPR:
-    case SWITCH_EXPR:
-    case CHANGE_DYNAMIC_TYPE_EXPR:
-    case OMP_FOR:
-    case OMP_SECTIONS:
-    case OMP_SECTIONS_SWITCH:
-    case OMP_SECTION:
-    case OMP_SINGLE:
-    case OMP_MASTER:
-    case OMP_ORDERED:
-    case OMP_CRITICAL:
-    case OMP_RETURN:
-    case OMP_CONTINUE:
+
+    case GIMPLE_EH_FILTER:
+      lower_sequence (gimple_eh_filter_failure (stmt), data);
       break;
 
-    case GIMPLE_MODIFY_STMT:
-      if (TREE_CODE (GIMPLE_STMT_OPERAND (stmt, 1)) == CALL_EXPR)
-	stmt = GIMPLE_STMT_OPERAND (stmt, 1);
-      else
-	break;
-      /* FALLTHRU */
+    case GIMPLE_NOP:
+    case GIMPLE_ASM:
+    case GIMPLE_ASSIGN:
+    case GIMPLE_GOTO:
+    case GIMPLE_LABEL:
+    case GIMPLE_SWITCH:
+    /*FIXME tuples: case CHANGE_DYNAMIC_TYPE_EXPR:*/
+    case GIMPLE_OMP_FOR:
+    case GIMPLE_OMP_SECTIONS:
+    case GIMPLE_OMP_SECTION:
+    case GIMPLE_OMP_SINGLE:
+    case GIMPLE_OMP_MASTER:
+    case GIMPLE_OMP_ORDERED:
+    case GIMPLE_OMP_CRITICAL:
+    case GIMPLE_OMP_RETURN:
+    case GIMPLE_OMP_CONTINUE:
+      break;
 
-    case CALL_EXPR:
+    case GIMPLE_CALL:
       {
-	tree decl = get_callee_fndecl (stmt);
+	tree decl = gimple_call_fndecl (stmt);
+
 	if (decl
 	    && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
 	    && DECL_FUNCTION_CODE (decl) == BUILT_IN_SETJMP)
 	  {
 	    data->calls_builtin_setjmp = true;
-	    lower_builtin_setjmp (tsi);
+	    lower_builtin_setjmp (gsi);
 	    return;
 	  }
       }
       break;
 
-    case OMP_PARALLEL:
-      lower_omp_directive (tsi, data);
+    case GIMPLE_OMP_PARALLEL:
+      lower_omp_directive (gsi, data);
       return;
 
     default:
       gcc_unreachable ();
     }
 
-  tsi_next (tsi);
+  gsi_next (gsi);
 }
 
 /* Lower a bind_expr TSI.  DATA is passed through the recursion.  */
 
 static void
-lower_bind_expr (tree_stmt_iterator *tsi, struct lower_data *data)
+lower_gimple_bind (gimple_stmt_iterator *gsi, struct lower_data *data)
 {
   tree old_block = data->block;
-  tree stmt = tsi_stmt (*tsi);
-  tree new_block = BIND_EXPR_BLOCK (stmt);
+  gimple stmt = gsi_stmt (gsi);
+  tree new_block = gimple_bind_block (stmt);
 
   if (new_block)
     {
@@ -324,8 +356,8 @@ lower_bind_expr (tree_stmt_iterator *tsi
 	}
     }
 
-  record_vars (BIND_EXPR_VARS (stmt));
-  lower_stmt_body (BIND_EXPR_BODY (stmt), data);
+  record_vars (gimple_bind_vars (stmt));
+  lower_sequence (gimple_bind_body (stmt), data);
 
   if (new_block)
     {
@@ -336,9 +368,9 @@ lower_bind_expr (tree_stmt_iterator *tsi
       data->block = old_block;
     }
 
-  /* The BIND_EXPR no longer carries any useful information -- kill it.  */
-  tsi_link_before (tsi, BIND_EXPR_BODY (stmt), TSI_SAME_STMT);
-  tsi_delink (tsi);
+  /* The GIMPLE_BIND no longer carries any useful information -- kill it.  */
+  gsi_link_seq_before (gsi, gimple_bind_body (stmt), GSI_SAME_STMT);
+  gsi_delink (gsi);
 }
 
 /* Try to determine whether a TRY_CATCH expression can fall through.
@@ -389,6 +421,58 @@ try_catch_may_fallthru (tree stmt)
     }
 }
 
+
+/* Same as above, but for a gimple GIMPLE_TRY_FINALLY.  */
+
+static bool
+gimple_try_catch_may_fallthru (gimple stmt)
+{
+  gimple_stmt_iterator *i;
+
+  /* We don't handle GIMPLE_TRY_FINALLY.  */
+  gcc_assert (gimple_flags (stmt) == GIMPLE_TRY_CATCH);
+
+  /* If the TRY block can fall through, the whole TRY_CATCH can
+     fall through.  */
+  if (gimple_seq_may_fallthru (gimple_try_eval (stmt)))
+    return true;
+
+  i = gsi_start (gimple_try_cleanup (stmt));
+  switch (gimple_flags (gsi_stmt (i)))
+    {
+    case GIMPLE_CATCH:
+      /* We expect to see a sequence of GIMPLE_CATCH stmts, each with a
+	 catch expression and a body.  The whole try/catch may fall
+	 through iff any of the catch bodies falls through.  */
+      for (; !gsi_end_p (i); gsi_next (i))
+	{
+	  if (gimple_seq_may_fallthru (gimple_catch_handler (gsi_stmt (i))))
+	    return true;
+	}
+      return false;
+
+    case GIMPLE_EH_FILTER:
+      /* The exception filter expression only matters if there is an
+	 exception.  If the exception does not match EH_FILTER_TYPES,
+	 we will execute EH_FILTER_FAILURE, and we will fall through
+	 if that falls through.  If the exception does match
+	 EH_FILTER_TYPES, the stack unwinder will continue up the
+	 stack, so we will not fall through.  We don't know whether we
+	 will throw an exception which matches EH_FILTER_TYPES or not,
+	 so we just ignore EH_FILTER_TYPES and assume that we might
+	 throw an exception which doesn't match.  */
+      return gimple_seq_may_fallthru (gimple_eh_filter_failure (gsi_stmt (i)));
+
+    default:
+      /* This case represents statements to be executed when an
+	 exception occurs.  Those statements are implicitly followed
+	 by a GIMPLE_RESX to resume execution after the exception.  So
+	 in this case the try/catch never falls through.  */
+      return false;
+    }
+}
+
+
 /* Try to determine if we can fall out of the bottom of BLOCK.  This guess
    need not be 100% accurate; simply be conservative and return true if we
    don't know.  This is used only to avoid stupidly generating extra code.
@@ -456,138 +540,104 @@ block_may_fallthru (tree block)
     }
 }
 
-/* Lower a cond_expr TSI.  DATA is passed through the recursion.  */
 
-static void
-lower_cond_expr (tree_stmt_iterator *tsi, struct lower_data *data)
+/* The same as above, but for gimple sequences.  */
+
+bool
+gimple_seq_may_fallthru (gimple_seq seq)
 {
-  tree stmt = tsi_stmt (*tsi);
-  bool then_is_goto, else_is_goto;
-  tree then_branch, else_branch;
-  tree then_goto, else_goto;
-  
-  then_branch = COND_EXPR_THEN (stmt);
-  else_branch = COND_EXPR_ELSE (stmt);
+  gimple stmt = gimple_seq_last (seq);
 
-  lower_stmt_body (then_branch, data);
-  lower_stmt_body (else_branch, data);
+  if (!stmt)
+    return true;
 
-  then_goto = expr_only (then_branch);
-  then_is_goto = then_goto && simple_goto_p (then_goto);
+  switch (gimple_code (stmt))
+    {
+    case GIMPLE_GOTO:
+    case GIMPLE_RETURN:
+    case GIMPLE_RESX:
+      /* Easy cases.  If the last statement of the seq implies 
+	 control transfer, then we can't fall through.  */
+      return false;
 
-  else_goto = expr_only (else_branch);
-  else_is_goto = else_goto && simple_goto_p (else_goto);
+    case GIMPLE_SWITCH:
+      /* Switch has already been lowered and represents a
+	 branch to a selected label and hence can not fall through.  */
+      return true;
 
-  if (!then_is_goto || !else_is_goto)
-    {
-      tree then_label, else_label, end_label, t;
+    case GIMPLE_COND:
+      /* GIMPLE_COND's are already lowered into a two-way branch.  They
+	 can't fall through.  */
+      return false;
 
-      then_label = NULL_TREE;
-      else_label = NULL_TREE;
-      end_label = NULL_TREE;
- 
-      /* Replace the cond_expr with explicit gotos.  */
-      if (!then_is_goto)
-	{
-	  t = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
-	  if (TREE_SIDE_EFFECTS (then_branch))
-	    then_label = t;
-	  else
-	    end_label = t;
-	  then_goto = build_and_jump (&LABEL_EXPR_LABEL (t));
-	}
+    case GIMPLE_BIND:
+      return gimple_seq_may_fallthru (gimple_bind_body (stmt));
 
-      if (!else_is_goto)
-	{
-	  t = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
-	  if (TREE_SIDE_EFFECTS (else_branch))
-	    else_label = t;
-	  else
-	    {
-	      /* Both THEN and ELSE can be no-ops if one or both contained an
-	         empty BIND_EXPR that was associated with the toplevel block
-	         of an inlined function.  In that case remove_useless_stmts
-	         can't have cleaned things up for us; kill the whole 
-	         conditional now.  */
-	      if (end_label)
-		{
-		  tsi_delink (tsi);
-		  return;
-		}
-	      else
-		end_label = t;
-	    }
-	  else_goto = build_and_jump (&LABEL_EXPR_LABEL (t));
-	}
+    case GIMPLE_TRY:
+      if (gimple_flags (stmt) == GIMPLE_TRY_CATCH)
+        return gimple_try_catch_may_fallthru (stmt);
 
-      if (then_label)
-	{
-	  bool may_fallthru = block_may_fallthru (then_branch);
+      /* It must be a GIMPLE_TRY_FINALLY.  */
 
-	  tsi_link_after (tsi, then_label, TSI_CONTINUE_LINKING);
-	  tsi_link_after (tsi, then_branch, TSI_CONTINUE_LINKING);
-  
-	  if (else_label && may_fallthru)
-	    {
-	      end_label = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
-	      t = build_and_jump (&LABEL_EXPR_LABEL (end_label));
-	      tsi_link_after (tsi, t, TSI_CONTINUE_LINKING);
-	    }
-	}
-  
-      if (else_label)
-	{
-	  tsi_link_after (tsi, else_label, TSI_CONTINUE_LINKING);
-	  tsi_link_after (tsi, else_branch, TSI_CONTINUE_LINKING);
-	}
+      /* The finally clause is always executed after the try clause,
+	 so if it does not fall through, then the try-finally will not
+	 fall through.  Otherwise, if the try clause does not fall
+	 through, then when the finally clause falls through it will
+	 resume execution wherever the try clause was going.  So the
+	 whole try-finally will only fall through if both the try
+	 clause and the finally clause fall through.  */
+      return (gimple_seq_may_fallthru (gimple_try_eval (stmt))
+	      && gimple_seq_may_fallthru (gimple_try_cleanup (stmt)));
 
-      if (end_label)
-	tsi_link_after (tsi, end_label, TSI_CONTINUE_LINKING);
-    }
+    case GIMPLE_ASSIGN:
+      return true;
 
-  COND_EXPR_THEN (stmt) = then_goto;
-  COND_EXPR_ELSE (stmt) = else_goto;
+    case GIMPLE_CALL:
+      /* Functions that do not return do not fall through.  */
+      return (gimple_call_flags (stmt) & ECF_NORETURN) == 0;
+    
+    /* FIXME tuples
+    case CLEANUP_POINT_EXPR:
+      return block_may_fallthru (TREE_OPERAND (stmt, 0));
+      */
 
-  tsi_next (tsi);
+    default:
+      return true;
+    }
 }
 
-/* Lower a return_expr TSI.  DATA is passed through the recursion.  */
+
+/* Lower a GIMPLE_RETURN GSI.  DATA is passed through the recursion.  */
 
 static void
-lower_return_expr (tree_stmt_iterator *tsi, struct lower_data *data)
+lower_gimple_return (gimple_stmt_iterator *gsi, struct lower_data *data)
 {
-  tree stmt = tsi_stmt (*tsi);
-  tree value, t, label;
-
-  /* Extract the value being returned.  */
-  value = TREE_OPERAND (stmt, 0);
-  if (value && TREE_CODE (value) == GIMPLE_MODIFY_STMT)
-    value = GIMPLE_STMT_OPERAND (value, 1);
+  gimple stmt = gsi_stmt (gsi);
+  gimple t;
+  int i;
+  return_statements_t tmp_rs;
 
   /* Match this up with an existing return statement that's been created.  */
-  for (t = data->return_statements; t ; t = TREE_CHAIN (t))
+  for (i = VEC_length (return_statements_t, data->return_statements) - 1;
+       i >= 0; i--)
     {
-      tree tvalue = TREE_OPERAND (TREE_VALUE (t), 0);
-      if (tvalue && TREE_CODE (tvalue) == GIMPLE_MODIFY_STMT)
-	tvalue = GIMPLE_STMT_OPERAND (tvalue, 1);
+      tmp_rs = *VEC_index (return_statements_t, data->return_statements, i);
 
-      if (value == tvalue)
-	{
-	  label = TREE_PURPOSE (t);
-	  goto found;
-	}
+      if (gimple_return_retval (stmt) == gimple_return_retval (tmp_rs.stmt))
+	goto found;
     }
 
   /* Not found.  Create a new label and record the return statement.  */
-  label = create_artificial_label ();
-  data->return_statements = tree_cons (label, stmt, data->return_statements);
+  tmp_rs.label = create_artificial_label ();
+  tmp_rs.stmt = stmt;
+  VEC_safe_push (return_statements_t, heap, data->return_statements, &tmp_rs);
 
   /* Generate a goto statement and remove the return statement.  */
  found:
-  t = build1 (GOTO_EXPR, void_type_node, label);
-  SET_EXPR_LOCUS (t, EXPR_LOCUS (stmt));
-  tsi_link_before (tsi, t, TSI_SAME_STMT);
-  tsi_delink (tsi);
+  t = build_gimple_goto (tmp_rs.label);
+  set_gimple_locus (t, gimple_locus (stmt));
+  gsi_link_before (gsi, t, GSI_SAME_STMT);
+  gsi_delink (gsi);
 }
 
 /* Lower a __builtin_setjmp TSI.
@@ -644,71 +694,66 @@ lower_return_expr (tree_stmt_iterator *t
    to the receivers, thus keeping the complexity explosion localized.  */
 
 static void
-lower_builtin_setjmp (tree_stmt_iterator *tsi)
+lower_builtin_setjmp (gimple_stmt_iterator *gsi)
 {
-  tree stmt = tsi_stmt (*tsi);
+  gimple stmt = gsi_stmt (gsi);
   tree cont_label = create_artificial_label ();
   tree next_label = create_artificial_label ();
   tree dest, t, arg;
+  gimple g;
 
   /* NEXT_LABEL is the label __builtin_longjmp will jump to.  Its address is
      passed to both __builtin_setjmp_setup and __builtin_setjmp_receiver.  */
   FORCED_LABEL (next_label) = 1;
 
-  if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT)
-    {
-      dest = GIMPLE_STMT_OPERAND (stmt, 0);
-      stmt = GIMPLE_STMT_OPERAND (stmt, 1);
-    }
-  else
-    dest = NULL_TREE;
+  dest = gimple_call_lhs (stmt);
 
   /* Build '__builtin_setjmp_setup (BUF, NEXT_LABEL)' and insert.  */
   arg = build_addr (next_label, current_function_decl);
   t = implicit_built_in_decls[BUILT_IN_SETJMP_SETUP];
-  t = build_call_expr (t, 2, CALL_EXPR_ARG (stmt, 0), arg);
-  SET_EXPR_LOCUS (t, EXPR_LOCUS (stmt));
-  tsi_link_before (tsi, t, TSI_SAME_STMT);
+  g = build_gimple_call (t, 2, gimple_call_arg (stmt, 0));
+  set_gimple_locus (g, gimple_locus (stmt));
+  gsi_link_before (gsi, g, GSI_SAME_STMT);
 
   /* Build 'DEST = 0' and insert.  */
   if (dest)
     {
-      t = build_gimple_modify_stmt (dest, fold_convert (TREE_TYPE (dest),
-							integer_zero_node));
-      SET_EXPR_LOCUS (t, EXPR_LOCUS (stmt));
-      tsi_link_before (tsi, t, TSI_SAME_STMT);
+      g = build_gimple_assign (dest, fold_convert (TREE_TYPE (dest),
+						   integer_zero_node));
+      set_gimple_locus (g, gimple_locus (stmt));
+      gsi_link_before (gsi, g, GSI_SAME_STMT);
     }
 
   /* Build 'goto CONT_LABEL' and insert.  */
-  t = build1 (GOTO_EXPR, void_type_node, cont_label);
-  tsi_link_before (tsi, t, TSI_SAME_STMT);
+  g = build_gimple_goto (cont_label);
+  gsi_link_before (gsi, g, TSI_SAME_STMT);
 
   /* Build 'NEXT_LABEL:' and insert.  */
-  t = build1 (LABEL_EXPR, void_type_node, next_label);
-  tsi_link_before (tsi, t, TSI_SAME_STMT);
+  g = build_gimple_label (next_label);
+  gsi_link_before (gsi, g, GSI_SAME_STMT);
 
   /* Build '__builtin_setjmp_receiver (NEXT_LABEL)' and insert.  */
   arg = build_addr (next_label, current_function_decl);
   t = implicit_built_in_decls[BUILT_IN_SETJMP_RECEIVER];
-  t = build_call_expr (t, 1, arg);
-  SET_EXPR_LOCUS (t, EXPR_LOCUS (stmt));
-  tsi_link_before (tsi, t, TSI_SAME_STMT);
+  g = build_gimple_call (t, 1, arg);
+  set_gimple_locus (g, gimple_locus (stmt));
+  gsi_link_before (gsi, g, GSI_SAME_STMT);
 
   /* Build 'DEST = 1' and insert.  */
   if (dest)
     {
-      t = build_gimple_modify_stmt (dest, fold_convert (TREE_TYPE (dest),
-							integer_one_node));
-      SET_EXPR_LOCUS (t, EXPR_LOCUS (stmt));
-      tsi_link_before (tsi, t, TSI_SAME_STMT);
+      g = build_gimple_assign (dest, fold_convert (TREE_TYPE (dest),
+						   integer_one_node));
+      set_gimple_locus (g, gimple_locus (stmt));
+      gsi_link_before (gsi, g, GSI_SAME_STMT);
     }
 
   /* Build 'CONT_LABEL:' and insert.  */
-  t = build1 (LABEL_EXPR, void_type_node, cont_label);
-  tsi_link_before (tsi, t, TSI_SAME_STMT);
+  g = build_gimple_label (cont_label);
+  gsi_link_before (gsi, g, GSI_SAME_STMT);
 
   /* Remove the call to __builtin_setjmp.  */
-  tsi_delink (tsi);
+  gsi_delink (gsi);
 }
 \f
 
Index: gimple-iterator.c
===================================================================
--- gimple-iterator.c	(revision 0)
+++ gimple-iterator.c	(revision 0)
@@ -0,0 +1,204 @@
+/* Iterator routines for GIMPLE statements.
+   Copyright (C) 2007 Free Software Foundation, Inc.
+   Contributed by Aldy Hernandez  <aldy@quesejoda.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING.  If not, write to
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "gimple.h"
+
+/* Links a sequence of statements before the current statement.  */
+
+void
+gsi_link_seq_before (gimple_stmt_iterator *i,
+    		     gimple_seq seq,
+    		     enum gsi_iterator_update mode)
+{
+  gimple head, tail, cur;
+
+  /* Die on looping.  */
+  gcc_assert (seq != i->seq);
+
+  head = gimple_seq_first (seq);
+  tail = gimple_seq_last (seq);
+  gimple_seq_init (seq);
+
+  /* Empty sequences need no work.  */
+  if (!head || !tail)
+    {
+      gcc_assert (head == tail);
+      return;
+    }
+
+  cur = i->stmt;
+
+  /* Link it into the sequence.  */
+  if (cur)
+    {
+      set_gimple_prev (head, gimple_prev (cur));
+      if (gimple_prev (head))
+	set_gimple_next (gimple_prev (head), head);
+      else
+	gimple_seq_set_first (i->seq, head);
+      set_gimple_next (tail, cur);
+      set_gimple_prev (cur, tail);
+    }
+  else
+    {
+      set_gimple_prev (head, gimple_seq_last (i->seq));
+      if (gimple_prev (head))
+	set_gimple_next (gimple_prev (head), head);
+      else
+	gimple_seq_set_first (i->seq, head);
+      gimple_seq_set_last (i->seq, tail);
+    }
+
+  /* Update the iterator, if requested.  */
+  switch (mode)
+    {
+    case GSI_NEW_STMT:
+    case GSI_CONTINUE_LINKING:
+      i->stmt = head;
+      break;
+    case GSI_SAME_STMT:
+      break;
+    default:
+      gcc_unreachable ();
+    }
+}
+
+
+/* Links one gimple statement before the current statement.  */
+
+void
+gsi_link_before (gimple_stmt_iterator *i,
+    		 gimple g,
+		 enum gsi_iterator_update mode)
+{
+  struct gimple_sequence tseq;
+
+  gimple_seq_init (&tseq);
+  gimple_add (&tseq, g);
+  gsi_link_seq_before (i, &tseq, mode);
+}
+
+
+/* Links a sequence after the current statement.  */
+
+void
+gsi_link_seq_after (gimple_stmt_iterator *i, gimple_seq seq,
+		    enum gsi_iterator_update mode)
+{
+  gimple head, tail, cur;
+
+  /* Die on looping.  */
+  gcc_assert (seq != i->seq);
+
+  head = gimple_seq_first (seq);
+  tail = gimple_seq_last (seq);
+  gimple_seq_init (seq);
+
+  /* Empty sequences need no work.  */
+  if (!head || !tail)
+    {
+      gcc_assert (head == tail);
+      return;
+    }
+
+  cur = i->stmt;
+
+  /* Link it into the list.  */
+  if (cur)
+    {
+      set_gimple_next (tail, gimple_next (cur));
+      if (gimple_next (tail))
+	set_gimple_prev (gimple_next (tail), tail);
+      else
+	gimple_seq_set_last (i->seq, tail);
+      set_gimple_prev (head, cur);
+      set_gimple_next (cur, head);
+    }
+  else
+    {
+      gcc_assert (!gimple_seq_last (i->seq));
+      gimple_seq_set_first (i->seq, head);
+      gimple_seq_set_last (i->seq, tail);
+    }
+
+  /* Update the iterator, if requested.  */
+  switch (mode)
+    {
+    case GSI_NEW_STMT:
+      i->stmt = head;
+      break;
+    case GSI_CONTINUE_LINKING:
+      i->stmt = tail;
+      break;
+    case GSI_SAME_STMT:
+      gcc_assert (cur);
+      break;
+    default:
+      gcc_unreachable ();
+    }
+}
+
+
+/* Links one gimple statement after the current statement.  */
+
+void
+gsi_link_after (gimple_stmt_iterator *i,
+    		gimple g,
+		enum gsi_iterator_update mode)
+{
+  struct gimple_sequence tseq;
+
+  gimple_seq_init (&tseq);
+  gimple_add (&tseq, g);
+  gsi_link_seq_after (i, &tseq, mode);
+}
+
+
+/* Remove the current stmt from the sequence.  The iterator is updated to
+   point to the next statement.  */
+
+void
+gsi_delink (gimple_stmt_iterator *i)
+{
+  gimple cur = i->stmt;
+  gimple next = gimple_next (cur);
+  gimple prev = gimple_prev (cur);
+
+  if (prev)
+    set_gimple_next (prev, next);
+  else
+    gimple_seq_set_first (i->seq, next);
+  if (next)
+    set_gimple_prev (next, prev);
+  else
+    gimple_seq_set_last (i->seq, prev);
+
+  /* Clear any links this statement may have, just in case someone is
+     still using it.  */
+  set_gimple_next (i->stmt, NULL);
+  set_gimple_prev (i->stmt, NULL);
+
+  i->stmt = next;
+}
Index: gimple-iterator.h
===================================================================
--- gimple-iterator.h	(revision 127301)
+++ gimple-iterator.h	(working copy)
@@ -22,6 +22,8 @@ Boston, MA 02110-1301, USA.  */
 #ifndef GCC_SEQ_ITERATOR_H
 #define GCC_SEQ_ITERATOR_H
 #include "ggc.h"
+#include "gimple.h"
+
 /* Iterator object for GIMPLE statement sequences.  */
 
 typedef struct {
@@ -109,4 +111,24 @@ gsi_stmt (gimple_stmt_iterator *i)
   return i->stmt;
 }
 
+
+enum gsi_iterator_update
+{
+  GSI_NEW_STMT,		/* Only valid when single statement is added, move
+			   iterator to it.  */
+  GSI_SAME_STMT,	/* Leave the iterator at the same statement.  */
+  GSI_CONTINUE_LINKING	/* Move iterator to whatever position is suitable
+			   for linking other statements in the same
+			   direction.  */
+};
+
+void gsi_link_seq_before (gimple_stmt_iterator *, gimple_seq,
+			  enum gsi_iterator_update);
+void gsi_link_before (gimple_stmt_iterator *, gimple,
+    		      enum gsi_iterator_update);
+void gsi_link_seq_after (gimple_stmt_iterator *, gimple_seq,
+			 enum gsi_iterator_update);
+void gsi_link_after (gimple_stmt_iterator *, gimple, enum gsi_iterator_update);
+void gsi_delink (gimple_stmt_iterator *);
+
 #endif /* GCC_SEQ_ITERATOR_H */
Index: gimplify.c
===================================================================
--- gimplify.c	(revision 127301)
+++ gimplify.c	(working copy)
@@ -6661,10 +6661,13 @@ gimplify_body (tree *body_p, gimple_seq 
   pop_gimplify_context (outer_bind);
   gcc_assert (gimplify_ctxp == NULL);
 
+  /* FIXME tuples: We need a version of this for tuples.  */
+#if 0
 #ifdef ENABLE_TYPES_CHECKING
   if (!errorcount && !sorrycount)
     verify_gimple_1 (BIND_EXPR_BODY (*body_p));
 #endif
+#endif
 
   timevar_pop (TV_TREE_GIMPLIFY);
   input_location = saved_location;
Index: tree-flow.h
===================================================================
--- tree-flow.h	(revision 127301)
+++ tree-flow.h	(working copy)
@@ -823,6 +823,7 @@ extern tree phi_reverse (tree);
 extern void record_vars_into (tree, tree);
 extern void record_vars (tree);
 extern bool block_may_fallthru (tree);
+extern bool gimple_seq_may_fallthru (gimple_seq);
 
 /* In tree-ssa-alias.c  */
 extern void dump_may_aliases_for (FILE *, tree);
Index: Makefile.in
===================================================================
--- Makefile.in	(revision 127301)
+++ Makefile.in	(working copy)
@@ -1038,6 +1038,7 @@ OBJS-common = \
 	genrtl.o \
 	ggc-common.o \
 	gimple.o \
+	gimple-iterator.o \
 	gimple-low.o \
 	gimple-pretty-print.o \
 	gimplify.o \
@@ -2200,6 +2201,8 @@ gimplify.o : gimplify.c $(CONFIG_H) $(SY
    coretypes.h except.h $(FLAGS_H) $(RTL_H) $(FUNCTION_H) $(EXPR_H) output.h \
    $(GGC_H) gt-gimplify.h $(HASHTAB_H) $(TARGET_H) toplev.h $(OPTABS_H) \
    $(REAL_H) $(SPLAY_TREE_H) vec.h
+gimple-iterator.o : gimple-iterator.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
+   $(TREE_H) $(GIMPLE_H)
 gimple-low.o : gimple-low.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) \
    $(DIAGNOSTIC_H) $(TREE_GIMPLE_H) $(TREE_INLINE_H) $(VARRAY_H) langhooks.h \
    $(LANGHOOKS_DEF_H) $(TREE_FLOW_H) $(TIMEVAR_H) $(TM_H) coretypes.h \
@@ -2263,7 +2266,7 @@ gimple.o : gimple.c $(CONFIG_H) $(SYSTEM
    $(GGC_H) $(TREE_GIMPLE_H) $(GIMPLE_H) $(DIAGNOSTIC_H)
 gimple-pretty-print.o : gimple-pretty-print.c $(CONFIG_H) $(SYSTEM_H) \
    $(TREE_H) $(DIAGNOSTIC_H) $(REAL_H) $(HASHTAB_H) $(TREE_FLOW_H) \
-   $(TM_H) coretypes.h gimple-iterator.h tree-pass.h $(GIMPLE_H)
+   $(TM_H) coretypes.h tree-pass.h $(GIMPLE_H)
 tree-mudflap.o : $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(TREE_INLINE_H) \
    $(TREE_GIMPLE_H) $(DIAGNOSTIC_H) $(HASHTAB_H) langhooks.h tree-mudflap.h \
    $(TM_H) coretypes.h $(TREE_DUMP_H) tree-pass.h $(CGRAPH_H) $(GGC_H) \
Index: gimple.c
===================================================================
--- gimple.c	(revision 127301)
+++ gimple.c	(working copy)
@@ -55,24 +55,6 @@ set_gimple_code (gimple g, enum gimple_c
 }
 
 
-/* Set PREV to be the previous statement to G.  */
-
-static inline void
-set_gimple_prev (gimple g, gimple prev)
-{
-  g->base.prev = prev;
-}
-
-
-/* Set NEXT to be the next statement to G.  */
-
-static inline void
-set_gimple_next (gimple g, gimple next)
-{
-  g->base.next = next;
-}
-
-
 /* Return the GSS_* identifier for the given GIMPLE statement CODE.  */
 
 static enum gimple_statement_structure_enum
@@ -289,7 +271,7 @@ build_gimple_label (tree label)
   return p;
 }
 
-/* Construct a GIMPLE_GOTO statement to DEST.  */
+/* Construct a GIMPLE_GOTO statement to label DEST.  */
 
 gimple
 build_gimple_goto (tree dest)
@@ -1040,3 +1022,29 @@ gimple_body (tree fn)
   
   return NULL;
 }
+
+
+/* Detect flags from a GIMPLE_CALL.  This is just like
+   call_expr_flags, but for gimple tuples.  How sad that we have to
+   duplicate code.  */
+
+int
+gimple_call_flags (gimple stmt)
+{
+  int flags;
+  tree decl = gimple_call_fndecl (stmt);
+  tree t;
+
+  if (decl)
+    flags = flags_from_decl_or_type (decl);
+  else
+    {
+      t = TREE_TYPE (gimple_call_fn (stmt));
+      if (t && TREE_CODE (t) == POINTER_TYPE)
+	flags = flags_from_decl_or_type (TREE_TYPE (t));
+      else
+	flags = 0;
+    }
+
+  return flags;
+}
Index: gimple.h
===================================================================
--- gimple.h	(revision 127301)
+++ gimple.h	(working copy)
@@ -36,8 +36,9 @@ enum gimple_code {
     LAST_AND_UNUSED_GIMPLE_CODE
 };
 
+
 /* A sequence of gimple statements.  */
-struct gimple_sequence
+struct gimple_sequence GTY(())
 {
   gimple first;
   gimple last;
@@ -139,6 +140,12 @@ struct gimple_statement_bind GTY(())
 {
   struct gimple_statement_base base;
   tree vars;
+
+  /* This is different than the ``block'' in gimple_statement_base, which
+     is analogous to TREE_BLOCK.  This block is the equivalent of
+     BIND_EXPR_BLOCK in tree land.  See gimple-low.c.  */
+  tree block;
+
   struct gimple_sequence body;
 };
 
@@ -303,6 +310,24 @@ union gimple_statement_d GTY ((desc ("gi
 };
 
 
+/* Set PREV to be the previous statement to G.  */
+
+static inline void
+set_gimple_prev (gimple g, gimple prev)
+{
+  g->base.prev = prev;
+}
+
+
+/* Set NEXT to be the next statement to G.  */
+
+static inline void
+set_gimple_next (gimple g, gimple next)
+{
+  g->base.next = next;
+}
+
+
 /* Common accessors for all GIMPLE statements.  */
 
 static inline enum gimple_code
@@ -383,7 +408,7 @@ gimple_locus_empty_p (gimple g)
   return gimple_locus (g).file == NULL && gimple_locus (g).line == 0;
 }
 
-/* In gimple.c.  */
+/* Prototypes in gimple.c.  */
 extern gimple build_gimple_return (bool, tree);
 extern gimple build_gimple_assign (tree, tree);
 extern gimple build_gimple_call_vec (tree, VEC(tree, gc) *);
@@ -427,6 +452,7 @@ extern void walk_seq_ops (gimple_seq, wa
 extern void set_gimple_body (tree, gimple_seq);
 extern gimple_seq gimple_body (tree);
 extern void gimple_seq_append (gimple_seq, gimple_seq);
+extern int gimple_call_flags (gimple);
 
 extern const char *const gimple_code_name[];
 
@@ -573,6 +599,24 @@ gimple_call_fn (gimple gs)
   return gs->with_ops.op[1];
 }
 
+/* If a given GIMPLE_CALL's callee is a FUNCTION_DECL, return it.
+   Otherwise return NULL.  This function is analogous to
+   get_callee_fndecl in tree land.  */
+
+static inline tree
+gimple_call_fndecl (gimple gs)
+{
+  tree decl;
+
+  GIMPLE_CHECK (gs, GIMPLE_CALL);
+  gcc_assert (gs->with_ops.num_ops > 1);
+  decl = gs->with_ops.op[1];
+  if (TREE_CODE (decl) == FUNCTION_DECL)
+    return decl;
+  else
+    return NULL;
+}
+
 static inline tree
 gimple_call_return_type (gimple gs)
 {
@@ -766,6 +810,20 @@ gimple_bind_set_body (gimple gs, gimple_
   gimple_seq_copy (&(gs->gimple_bind.body), seq);
 }
 
+static inline tree
+gimple_bind_block (gimple gs)
+{
+  GIMPLE_CHECK (gs, GIMPLE_BIND);
+  return gs->gimple_bind.block;
+}
+
+static inline void
+gimple_bind_set_block (gimple gs, tree block)
+{
+  GIMPLE_CHECK (gs, GIMPLE_BIND);
+  gs->gimple_bind.block = block;
+}
+
 
 /* GIMPLE_ASM accessors. */
 

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [tuples] gimple-low and assorted machinery
  2007-08-08 18:12 [tuples] gimple-low and assorted machinery Aldy Hernandez
@ 2007-08-09 14:52 ` Diego Novillo
  0 siblings, 0 replies; 2+ messages in thread
From: Diego Novillo @ 2007-08-09 14:52 UTC (permalink / raw)
  To: Aldy Hernandez; +Cc: amacleod, gcc-patches

On 8/8/07 2:12 PM, Aldy Hernandez wrote:

> 3. We have a version of call_expr_flags for tuples: gimple_call_flags.
>    Yes, it sucks to have duplicate functionality, but we need a tuples
>    version *and* a tree version.

This one's easy.  Just factor out the code in call_expr_flags that deals
with the extracted fndecl and have both gimple_call_flags and
call_expr_flags call that routine.

>    Diego, could you please update the design document?

Nobody is tying your hands.  The code is Right There on the wiki ;)

OK, I'll do it.

>    In the GIMPLE_CALL tuple, we store the result from
>    get_callee_fndecl() as Diego had suggested, but we also need (after
>    gimplification) to do things depending on whether we have a
>    FUNCTION_DECL or not.

So we test for gimple_call_fn() being a FUNCTION_DECL.  I don't see
where we rely on the function value being NULL. We can just ask for
TREE_CODE (gimple_call_fn (gs)) == FUNCTION_DECL, or even better, code
this condition in a predicate is_gimple_indirect_call (gs).

Regarding the GC problem, the easiest solution I can think of is to have
the GIMPLE bodies inside a VEC and then have a pointer map as an index
into that VEC.  The pointer map is really only useful to avoid linear
scanning in set_gimple_body() and gimple_body().

This solves the problem because we now have GC roots pointing at all the
 sequence bodies.  The lowering is also ICEing here and there in
compile.exp.  I'll commit the changes after I fix all the regressions.

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2007-08-09 14:52 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-08-08 18:12 [tuples] gimple-low and assorted machinery Aldy Hernandez
2007-08-09 14:52 ` Diego Novillo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).