diff gcc/gimple.c @ 0:a06113de4d67

first commit
author kent <kent@cr.ie.u-ryukyu.ac.jp>
date Fri, 17 Jul 2009 14:47:48 +0900
parents
children a4c410aa4714 77e2b8dfacca
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gcc/gimple.c	Fri Jul 17 14:47:48 2009 +0900
@@ -0,0 +1,3194 @@
+/* Gimple IR support functions.
+
+   Copyright 2007, 2008 Free Software Foundation, Inc.
+   Contributed by Aldy Hernandez <aldyh@redhat.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 3, 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 COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "ggc.h"
+#include "errors.h"
+#include "hard-reg-set.h"
+#include "basic-block.h"
+#include "gimple.h"
+#include "diagnostic.h"
+#include "tree-flow.h"
+#include "value-prof.h"
+#include "flags.h"
+
+#define DEFGSCODE(SYM, NAME, STRUCT)	NAME,
+const char *const gimple_code_name[] = {
+#include "gimple.def"
+};
+#undef DEFGSCODE
+
+/* All the tuples have their operand vector at the very bottom
+   of the structure.  Therefore, the offset required to find the
+   operands vector the size of the structure minus the size of the 1
+   element tree array at the end (see gimple_ops).  */
+#define DEFGSCODE(SYM, NAME, STRUCT)	(sizeof (STRUCT) - sizeof (tree)),
+const size_t gimple_ops_offset_[] = {
+#include "gimple.def"
+};
+#undef DEFGSCODE
+
+#ifdef GATHER_STATISTICS
+/* Gimple stats.  */
+
+int gimple_alloc_counts[(int) gimple_alloc_kind_all];
+int gimple_alloc_sizes[(int) gimple_alloc_kind_all];
+
+/* Keep in sync with gimple.h:enum gimple_alloc_kind.  */
+static const char * const gimple_alloc_kind_names[] = {
+    "assignments",
+    "phi nodes",
+    "conditionals",
+    "sequences",
+    "everything else"
+};
+
+#endif /* GATHER_STATISTICS */
+
+/* A cache of gimple_seq objects.  Sequences are created and destroyed
+   fairly often during gimplification.  */
+static GTY ((deletable)) struct gimple_seq_d *gimple_seq_cache;
+
+/* Private API manipulation functions shared only with some
+   other files.  */
+extern void gimple_set_stored_syms (gimple, bitmap, bitmap_obstack *);
+extern void gimple_set_loaded_syms (gimple, bitmap, bitmap_obstack *);
+
+/* Gimple tuple constructors.
+   Note: Any constructor taking a ``gimple_seq'' as a parameter, can
+   be passed a NULL to start with an empty sequence.  */
+
+/* Set the code for statement G to CODE.  */
+
+static inline void
+gimple_set_code (gimple g, enum gimple_code code)
+{
+  g->gsbase.code = code;
+}
+
+
+/* Return the GSS_* identifier for the given GIMPLE statement CODE.  */
+
+static enum gimple_statement_structure_enum
+gss_for_code (enum gimple_code code)
+{
+  switch (code)
+    {
+    case GIMPLE_ASSIGN:
+    case GIMPLE_CALL:
+    case GIMPLE_RETURN:			return GSS_WITH_MEM_OPS;
+    case GIMPLE_COND:
+    case GIMPLE_GOTO:
+    case GIMPLE_LABEL:
+    case GIMPLE_CHANGE_DYNAMIC_TYPE:
+    case GIMPLE_SWITCH:			return GSS_WITH_OPS;
+    case GIMPLE_ASM:			return GSS_ASM;
+    case GIMPLE_BIND:			return GSS_BIND;
+    case GIMPLE_CATCH:			return GSS_CATCH;
+    case GIMPLE_EH_FILTER:		return GSS_EH_FILTER;
+    case GIMPLE_NOP:			return GSS_BASE;
+    case GIMPLE_PHI:			return GSS_PHI;
+    case GIMPLE_RESX:			return GSS_RESX;
+    case GIMPLE_TRY:			return GSS_TRY;
+    case GIMPLE_WITH_CLEANUP_EXPR:	return GSS_WCE;
+    case GIMPLE_OMP_CRITICAL:		return GSS_OMP_CRITICAL;
+    case GIMPLE_OMP_FOR:		return GSS_OMP_FOR;
+    case GIMPLE_OMP_MASTER:		
+    case GIMPLE_OMP_ORDERED:
+    case GIMPLE_OMP_SECTION:		return GSS_OMP;
+    case GIMPLE_OMP_RETURN:
+    case GIMPLE_OMP_SECTIONS_SWITCH:    return GSS_BASE;
+    case GIMPLE_OMP_CONTINUE:		return GSS_OMP_CONTINUE;
+    case GIMPLE_OMP_PARALLEL:		return GSS_OMP_PARALLEL;
+    case GIMPLE_OMP_TASK:		return GSS_OMP_TASK;
+    case GIMPLE_OMP_SECTIONS:		return GSS_OMP_SECTIONS;
+    case GIMPLE_OMP_SINGLE:		return GSS_OMP_SINGLE;
+    case GIMPLE_OMP_ATOMIC_LOAD:	return GSS_OMP_ATOMIC_LOAD;
+    case GIMPLE_OMP_ATOMIC_STORE:	return GSS_OMP_ATOMIC_STORE;
+    case GIMPLE_PREDICT:		return GSS_BASE;
+    default:				gcc_unreachable ();
+    }
+}
+
+
+/* Return the number of bytes needed to hold a GIMPLE statement with
+   code CODE.  */
+
+static size_t
+gimple_size (enum gimple_code code)
+{
+  enum gimple_statement_structure_enum gss = gss_for_code (code);
+
+  if (gss == GSS_WITH_OPS)
+    return sizeof (struct gimple_statement_with_ops);
+  else if (gss == GSS_WITH_MEM_OPS)
+    return sizeof (struct gimple_statement_with_memory_ops);
+
+  switch (code)
+    {
+    case GIMPLE_ASM:
+      return sizeof (struct gimple_statement_asm);
+    case GIMPLE_NOP:
+      return sizeof (struct gimple_statement_base);
+    case GIMPLE_BIND:
+      return sizeof (struct gimple_statement_bind);
+    case GIMPLE_CATCH:
+      return sizeof (struct gimple_statement_catch);
+    case GIMPLE_EH_FILTER:
+      return sizeof (struct gimple_statement_eh_filter);
+    case GIMPLE_TRY:
+      return sizeof (struct gimple_statement_try);
+    case GIMPLE_RESX:
+      return sizeof (struct gimple_statement_resx);
+    case GIMPLE_OMP_CRITICAL:
+      return sizeof (struct gimple_statement_omp_critical);
+    case GIMPLE_OMP_FOR:
+      return sizeof (struct gimple_statement_omp_for);
+    case GIMPLE_OMP_PARALLEL:
+      return sizeof (struct gimple_statement_omp_parallel);
+    case GIMPLE_OMP_TASK:
+      return sizeof (struct gimple_statement_omp_task);
+    case GIMPLE_OMP_SECTION:
+    case GIMPLE_OMP_MASTER:
+    case GIMPLE_OMP_ORDERED:
+      return sizeof (struct gimple_statement_omp);
+    case GIMPLE_OMP_RETURN:
+      return sizeof (struct gimple_statement_base);
+    case GIMPLE_OMP_CONTINUE:
+      return sizeof (struct gimple_statement_omp_continue);
+    case GIMPLE_OMP_SECTIONS:
+      return sizeof (struct gimple_statement_omp_sections);
+    case GIMPLE_OMP_SECTIONS_SWITCH:
+      return sizeof (struct gimple_statement_base);
+    case GIMPLE_OMP_SINGLE:
+      return sizeof (struct gimple_statement_omp_single);
+    case GIMPLE_OMP_ATOMIC_LOAD:
+      return sizeof (struct gimple_statement_omp_atomic_load);
+    case GIMPLE_OMP_ATOMIC_STORE:
+      return sizeof (struct gimple_statement_omp_atomic_store);
+    case GIMPLE_WITH_CLEANUP_EXPR:
+      return sizeof (struct gimple_statement_wce);
+    case GIMPLE_CHANGE_DYNAMIC_TYPE:
+      return sizeof (struct gimple_statement_with_ops);
+    case GIMPLE_PREDICT:
+      return sizeof (struct gimple_statement_base);
+    default:
+      break;
+    }
+
+  gcc_unreachable ();
+}
+
+
+/* Allocate memory for a GIMPLE statement with code CODE and NUM_OPS
+   operands.  */
+
+#define gimple_alloc(c, n) gimple_alloc_stat (c, n MEM_STAT_INFO)
+static gimple
+gimple_alloc_stat (enum gimple_code code, unsigned num_ops MEM_STAT_DECL)
+{
+  size_t size;
+  gimple stmt;
+
+  size = gimple_size (code);
+  if (num_ops > 0)
+    size += sizeof (tree) * (num_ops - 1);
+
+#ifdef GATHER_STATISTICS
+  {
+    enum gimple_alloc_kind kind = gimple_alloc_kind (code);
+    gimple_alloc_counts[(int) kind]++;
+    gimple_alloc_sizes[(int) kind] += size;
+  }
+#endif
+
+  stmt = (gimple) ggc_alloc_cleared_stat (size PASS_MEM_STAT);
+  gimple_set_code (stmt, code);
+  gimple_set_num_ops (stmt, num_ops);
+
+  /* Do not call gimple_set_modified here as it has other side
+     effects and this tuple is still not completely built.  */
+  stmt->gsbase.modified = 1;
+
+  return stmt;
+}
+
+/* Set SUBCODE to be the code of the expression computed by statement G.  */
+
+static inline void
+gimple_set_subcode (gimple g, unsigned subcode)
+{
+  /* We only have 16 bits for the RHS code.  Assert that we are not
+     overflowing it.  */
+  gcc_assert (subcode < (1 << 16));
+  g->gsbase.subcode = subcode;
+}
+
+
+
+/* Build a tuple with operands.  CODE is the statement to build (which
+   must be one of the GIMPLE_WITH_OPS tuples).  SUBCODE is the sub-code
+   for the new tuple.  NUM_OPS is the number of operands to allocate.  */ 
+
+#define gimple_build_with_ops(c, s, n) \
+  gimple_build_with_ops_stat (c, s, n MEM_STAT_INFO)
+
+static gimple
+gimple_build_with_ops_stat (enum gimple_code code, enum tree_code subcode,
+		            unsigned num_ops MEM_STAT_DECL)
+{
+  gimple s = gimple_alloc_stat (code, num_ops PASS_MEM_STAT);
+  gimple_set_subcode (s, subcode);
+
+  return s;
+}
+
+
+/* Build a GIMPLE_RETURN statement returning RETVAL.  */
+
+gimple
+gimple_build_return (tree retval)
+{
+  gimple s = gimple_build_with_ops (GIMPLE_RETURN, 0, 1);
+  if (retval)
+    gimple_return_set_retval (s, retval);
+  return s;
+}
+
+/* Helper for gimple_build_call, gimple_build_call_vec and
+   gimple_build_call_from_tree.  Build the basic components of a
+   GIMPLE_CALL statement to function FN with NARGS arguments.  */
+
+static inline gimple
+gimple_build_call_1 (tree fn, unsigned nargs)
+{
+  gimple s = gimple_build_with_ops (GIMPLE_CALL, 0, nargs + 3);
+  if (TREE_CODE (fn) == FUNCTION_DECL)
+    fn = build_fold_addr_expr (fn);
+  gimple_set_op (s, 1, fn);
+  return s;
+}
+
+
+/* Build a GIMPLE_CALL statement to function FN with the arguments
+   specified in vector ARGS.  */
+
+gimple
+gimple_build_call_vec (tree fn, VEC(tree, heap) *args)
+{
+  unsigned i;
+  unsigned nargs = VEC_length (tree, args);
+  gimple call = gimple_build_call_1 (fn, nargs);
+
+  for (i = 0; i < nargs; i++)
+    gimple_call_set_arg (call, i, VEC_index (tree, args, i));
+
+  return call;
+}
+
+
+/* Build a GIMPLE_CALL statement to function FN.  NARGS is the number of
+   arguments.  The ... are the arguments.  */
+
+gimple
+gimple_build_call (tree fn, unsigned nargs, ...)
+{
+  va_list ap;
+  gimple call;
+  unsigned i;
+
+  gcc_assert (TREE_CODE (fn) == FUNCTION_DECL || is_gimple_call_addr (fn));
+
+  call = gimple_build_call_1 (fn, nargs);
+
+  va_start (ap, nargs);
+  for (i = 0; i < nargs; i++)
+    gimple_call_set_arg (call, i, va_arg (ap, tree));
+  va_end (ap);
+
+  return call;
+}
+
+
+/* Build a GIMPLE_CALL statement from CALL_EXPR T.  Note that T is
+   assumed to be in GIMPLE form already.  Minimal checking is done of
+   this fact.  */
+
+gimple
+gimple_build_call_from_tree (tree t)
+{
+  unsigned i, nargs;
+  gimple call;
+  tree fndecl = get_callee_fndecl (t);
+
+  gcc_assert (TREE_CODE (t) == CALL_EXPR);
+
+  nargs = call_expr_nargs (t);
+  call = gimple_build_call_1 (fndecl ? fndecl : CALL_EXPR_FN (t), nargs);
+
+  for (i = 0; i < nargs; i++)
+    gimple_call_set_arg (call, i, CALL_EXPR_ARG (t, i));
+
+  gimple_set_block (call, TREE_BLOCK (t));
+
+  /* Carry all the CALL_EXPR flags to the new GIMPLE_CALL.  */
+  gimple_call_set_chain (call, CALL_EXPR_STATIC_CHAIN (t));
+  gimple_call_set_tail (call, CALL_EXPR_TAILCALL (t));
+  gimple_call_set_cannot_inline (call, CALL_CANNOT_INLINE_P (t));
+  gimple_call_set_return_slot_opt (call, CALL_EXPR_RETURN_SLOT_OPT (t));
+  gimple_call_set_from_thunk (call, CALL_FROM_THUNK_P (t));
+  gimple_call_set_va_arg_pack (call, CALL_EXPR_VA_ARG_PACK (t));
+
+  return call;
+}
+
+
+/* Extract the operands and code for expression EXPR into *SUBCODE_P,
+   *OP1_P and *OP2_P respectively.  */
+
+void
+extract_ops_from_tree (tree expr, enum tree_code *subcode_p, tree *op1_p,
+		       tree *op2_p)
+{
+  enum gimple_rhs_class grhs_class;
+
+  *subcode_p = TREE_CODE (expr);
+  grhs_class = get_gimple_rhs_class (*subcode_p);
+
+  if (grhs_class == GIMPLE_BINARY_RHS)
+    {
+      *op1_p = TREE_OPERAND (expr, 0);
+      *op2_p = TREE_OPERAND (expr, 1);
+    }
+  else if (grhs_class == GIMPLE_UNARY_RHS)
+    {
+      *op1_p = TREE_OPERAND (expr, 0);
+      *op2_p = NULL_TREE;
+    }
+  else if (grhs_class == GIMPLE_SINGLE_RHS)
+    {
+      *op1_p = expr;
+      *op2_p = NULL_TREE;
+    }
+  else
+    gcc_unreachable ();
+}
+
+
+/* Build a GIMPLE_ASSIGN statement.
+
+   LHS of the assignment.
+   RHS of the assignment which can be unary or binary.  */
+
+gimple
+gimple_build_assign_stat (tree lhs, tree rhs MEM_STAT_DECL)
+{
+  enum tree_code subcode;
+  tree op1, op2;
+
+  extract_ops_from_tree (rhs, &subcode, &op1, &op2);
+  return gimple_build_assign_with_ops_stat (subcode, lhs, op1, op2
+  					    PASS_MEM_STAT);
+}
+
+
+/* Build a GIMPLE_ASSIGN statement with sub-code SUBCODE and operands
+   OP1 and OP2.  If OP2 is NULL then SUBCODE must be of class
+   GIMPLE_UNARY_RHS or GIMPLE_SINGLE_RHS.  */
+
+gimple
+gimple_build_assign_with_ops_stat (enum tree_code subcode, tree lhs, tree op1,
+                                   tree op2 MEM_STAT_DECL)
+{
+  unsigned num_ops;
+  gimple p;
+
+  /* Need 1 operand for LHS and 1 or 2 for the RHS (depending on the
+     code).  */
+  num_ops = get_gimple_rhs_num_ops (subcode) + 1;
+  
+  p = gimple_build_with_ops_stat (GIMPLE_ASSIGN, subcode, num_ops
+  			          PASS_MEM_STAT);
+  gimple_assign_set_lhs (p, lhs);
+  gimple_assign_set_rhs1 (p, op1);
+  if (op2)
+    {
+      gcc_assert (num_ops > 2);
+      gimple_assign_set_rhs2 (p, op2);
+    }
+
+  return p;
+}
+
+
+/* Build a new GIMPLE_ASSIGN tuple and append it to the end of *SEQ_P.
+
+   DST/SRC are the destination and source respectively.  You can pass
+   ungimplified trees in DST or SRC, in which case they will be
+   converted to a gimple operand if necessary.
+
+   This function returns the newly created GIMPLE_ASSIGN tuple.  */
+
+inline gimple
+gimplify_assign (tree dst, tree src, gimple_seq *seq_p)
+{ 
+  tree t = build2 (MODIFY_EXPR, TREE_TYPE (dst), dst, src);
+  gimplify_and_add (t, seq_p);
+  ggc_free (t);
+  return gimple_seq_last_stmt (*seq_p);
+}
+
+
+/* Build a GIMPLE_COND statement.
+
+   PRED is the condition used to compare LHS and the RHS.
+   T_LABEL is the label to jump to if the condition is true.
+   F_LABEL is the label to jump to otherwise.  */
+
+gimple
+gimple_build_cond (enum tree_code pred_code, tree lhs, tree rhs,
+		   tree t_label, tree f_label)
+{
+  gimple p;
+
+  gcc_assert (TREE_CODE_CLASS (pred_code) == tcc_comparison);
+  p = gimple_build_with_ops (GIMPLE_COND, pred_code, 4);
+  gimple_cond_set_lhs (p, lhs);
+  gimple_cond_set_rhs (p, rhs);
+  gimple_cond_set_true_label (p, t_label);
+  gimple_cond_set_false_label (p, f_label);
+  return p;
+}
+
+
+/* Extract operands for a GIMPLE_COND statement out of COND_EXPR tree COND.  */
+
+void
+gimple_cond_get_ops_from_tree (tree cond, enum tree_code *code_p,
+                               tree *lhs_p, tree *rhs_p)
+{
+  gcc_assert (TREE_CODE_CLASS (TREE_CODE (cond)) == tcc_comparison
+	      || TREE_CODE (cond) == TRUTH_NOT_EXPR
+	      || is_gimple_min_invariant (cond)
+	      || SSA_VAR_P (cond));
+
+  extract_ops_from_tree (cond, code_p, lhs_p, rhs_p);
+
+  /* Canonicalize conditionals of the form 'if (!VAL)'.  */
+  if (*code_p == TRUTH_NOT_EXPR)
+    {
+      *code_p = EQ_EXPR;
+      gcc_assert (*lhs_p && *rhs_p == NULL_TREE);
+      *rhs_p = fold_convert (TREE_TYPE (*lhs_p), integer_zero_node);
+    }
+  /* Canonicalize conditionals of the form 'if (VAL)'  */
+  else if (TREE_CODE_CLASS (*code_p) != tcc_comparison)
+    {
+      *code_p = NE_EXPR;
+      gcc_assert (*lhs_p && *rhs_p == NULL_TREE);
+      *rhs_p = fold_convert (TREE_TYPE (*lhs_p), integer_zero_node);
+    }
+}
+
+
+/* Build a GIMPLE_COND statement from the conditional expression tree
+   COND.  T_LABEL and F_LABEL are as in gimple_build_cond.  */
+
+gimple
+gimple_build_cond_from_tree (tree cond, tree t_label, tree f_label)
+{
+  enum tree_code code;
+  tree lhs, rhs;
+
+  gimple_cond_get_ops_from_tree (cond, &code, &lhs, &rhs);
+  return gimple_build_cond (code, lhs, rhs, t_label, f_label);
+}
+
+/* Set code, lhs, and rhs of a GIMPLE_COND from a suitable
+   boolean expression tree COND.  */
+
+void
+gimple_cond_set_condition_from_tree (gimple stmt, tree cond)
+{
+  enum tree_code code;
+  tree lhs, rhs;
+
+  gimple_cond_get_ops_from_tree (cond, &code, &lhs, &rhs);
+  gimple_cond_set_condition (stmt, code, lhs, rhs);
+}
+
+/* Build a GIMPLE_LABEL statement for LABEL.  */
+
+gimple
+gimple_build_label (tree label)
+{
+  gimple p = gimple_build_with_ops (GIMPLE_LABEL, 0, 1);
+  gimple_label_set_label (p, label);
+  return p;
+}
+
+/* Build a GIMPLE_GOTO statement to label DEST.  */
+
+gimple
+gimple_build_goto (tree dest)
+{
+  gimple p = gimple_build_with_ops (GIMPLE_GOTO, 0, 1);
+  gimple_goto_set_dest (p, dest);
+  return p;
+}
+
+
+/* Build a GIMPLE_NOP statement.  */
+
+gimple 
+gimple_build_nop (void)
+{
+  return gimple_alloc (GIMPLE_NOP, 0);
+}
+
+
+/* Build a GIMPLE_BIND statement.
+   VARS are the variables in BODY.
+   BLOCK is the containing block.  */
+
+gimple
+gimple_build_bind (tree vars, gimple_seq body, tree block)
+{
+  gimple p = gimple_alloc (GIMPLE_BIND, 0);
+  gimple_bind_set_vars (p, vars);
+  if (body)
+    gimple_bind_set_body (p, body);
+  if (block)
+    gimple_bind_set_block (p, block);
+  return p;
+}
+
+/* Helper function to set the simple fields of a asm stmt.
+
+   STRING is a pointer to a string that is the asm blocks assembly code.
+   NINPUT is the number of register inputs.
+   NOUTPUT is the number of register outputs.
+   NCLOBBERS is the number of clobbered registers.
+   */
+
+static inline gimple
+gimple_build_asm_1 (const char *string, unsigned ninputs, unsigned noutputs, 
+                    unsigned nclobbers)
+{
+  gimple p;
+  int size = strlen (string);
+
+  p = gimple_build_with_ops (GIMPLE_ASM, 0, ninputs + noutputs + nclobbers);
+
+  p->gimple_asm.ni = ninputs;
+  p->gimple_asm.no = noutputs;
+  p->gimple_asm.nc = nclobbers;
+  p->gimple_asm.string = ggc_alloc_string (string, size);
+
+#ifdef GATHER_STATISTICS
+  gimple_alloc_sizes[(int) gimple_alloc_kind (GIMPLE_ASM)] += size;
+#endif
+  
+  return p;
+}
+
+/* Build a GIMPLE_ASM statement.
+
+   STRING is the assembly code.
+   NINPUT is the number of register inputs.
+   NOUTPUT is the number of register outputs.
+   NCLOBBERS is the number of clobbered registers.
+   INPUTS is a vector of the input register parameters.
+   OUTPUTS is a vector of the output register parameters.
+   CLOBBERS is a vector of the clobbered register parameters.  */
+
+gimple
+gimple_build_asm_vec (const char *string, VEC(tree,gc)* inputs, 
+                      VEC(tree,gc)* outputs, VEC(tree,gc)* clobbers)
+{
+  gimple p;
+  unsigned i;
+
+  p = gimple_build_asm_1 (string,
+                          VEC_length (tree, inputs),
+                          VEC_length (tree, outputs), 
+                          VEC_length (tree, clobbers));
+  
+  for (i = 0; i < VEC_length (tree, inputs); i++)
+    gimple_asm_set_input_op (p, i, VEC_index (tree, inputs, i));
+
+  for (i = 0; i < VEC_length (tree, outputs); i++)
+    gimple_asm_set_output_op (p, i, VEC_index (tree, outputs, i));
+
+  for (i = 0; i < VEC_length (tree, clobbers); i++)
+    gimple_asm_set_clobber_op (p, i, VEC_index (tree, clobbers, i));
+  
+  return p;
+}
+
+/* Build a GIMPLE_ASM statement.
+
+   STRING is the assembly code.
+   NINPUT is the number of register inputs.
+   NOUTPUT is the number of register outputs.
+   NCLOBBERS is the number of clobbered registers.
+   ... are trees for each input, output and clobbered register.  */
+
+gimple
+gimple_build_asm (const char *string, unsigned ninputs, unsigned noutputs, 
+		  unsigned nclobbers, ...)
+{
+  gimple p;
+  unsigned i;
+  va_list ap;
+  
+  p = gimple_build_asm_1 (string, ninputs, noutputs, nclobbers);
+  
+  va_start (ap, nclobbers);
+
+  for (i = 0; i < ninputs; i++)
+    gimple_asm_set_input_op (p, i, va_arg (ap, tree));
+
+  for (i = 0; i < noutputs; i++)
+    gimple_asm_set_output_op (p, i, va_arg (ap, tree));
+
+  for (i = 0; i < nclobbers; i++)
+    gimple_asm_set_clobber_op (p, i, va_arg (ap, tree));
+
+  va_end (ap);
+  
+  return p;
+}
+
+/* Build a GIMPLE_CATCH statement.
+
+  TYPES are the catch types.
+  HANDLER is the exception handler.  */
+
+gimple
+gimple_build_catch (tree types, gimple_seq handler)
+{
+  gimple p = gimple_alloc (GIMPLE_CATCH, 0);
+  gimple_catch_set_types (p, types);
+  if (handler)
+    gimple_catch_set_handler (p, handler);
+
+  return p;
+}
+
+/* Build a GIMPLE_EH_FILTER statement.
+
+   TYPES are the filter's types.
+   FAILURE is the filter's failure action.  */
+
+gimple
+gimple_build_eh_filter (tree types, gimple_seq failure)
+{
+  gimple p = gimple_alloc (GIMPLE_EH_FILTER, 0);
+  gimple_eh_filter_set_types (p, types);
+  if (failure)
+    gimple_eh_filter_set_failure (p, failure);
+
+  return p;
+}
+
+/* Build a GIMPLE_TRY statement.
+
+   EVAL is the expression to evaluate.
+   CLEANUP is the cleanup expression.
+   KIND is either GIMPLE_TRY_CATCH or GIMPLE_TRY_FINALLY depending on
+   whether this is a try/catch or a try/finally respectively.  */
+
+gimple
+gimple_build_try (gimple_seq eval, gimple_seq cleanup,
+    		  enum gimple_try_flags kind)
+{
+  gimple p;
+
+  gcc_assert (kind == GIMPLE_TRY_CATCH || kind == GIMPLE_TRY_FINALLY);
+  p = gimple_alloc (GIMPLE_TRY, 0);
+  gimple_set_subcode (p, kind);
+  if (eval)
+    gimple_try_set_eval (p, eval);
+  if (cleanup)
+    gimple_try_set_cleanup (p, cleanup);
+
+  return p;
+}
+
+/* Construct a GIMPLE_WITH_CLEANUP_EXPR statement.
+
+   CLEANUP is the cleanup expression.  */
+
+gimple
+gimple_build_wce (gimple_seq cleanup)
+{
+  gimple p = gimple_alloc (GIMPLE_WITH_CLEANUP_EXPR, 0);
+  if (cleanup)
+    gimple_wce_set_cleanup (p, cleanup);
+
+  return p;
+}
+
+
+/* Build a GIMPLE_RESX statement.
+
+   REGION is the region number from which this resx causes control flow to 
+   leave.  */
+
+gimple
+gimple_build_resx (int region)
+{
+  gimple p = gimple_alloc (GIMPLE_RESX, 0);
+  gimple_resx_set_region (p, region);
+  return p;
+}
+
+
+/* The helper for constructing a gimple switch statement.
+   INDEX is the switch's index.
+   NLABELS is the number of labels in the switch excluding the default.
+   DEFAULT_LABEL is the default label for the switch statement.  */
+
+static inline gimple 
+gimple_build_switch_1 (unsigned nlabels, tree index, tree default_label)
+{
+  /* nlabels + 1 default label + 1 index.  */
+  gimple p = gimple_build_with_ops (GIMPLE_SWITCH, 0, nlabels + 1 + 1);
+  gimple_switch_set_index (p, index);
+  gimple_switch_set_default_label (p, default_label);
+  return p;
+}
+
+
+/* Build a GIMPLE_SWITCH statement.
+
+   INDEX is the switch's index.
+   NLABELS is the number of labels in the switch excluding the DEFAULT_LABEL. 
+   ... are the labels excluding the default.  */
+
+gimple 
+gimple_build_switch (unsigned nlabels, tree index, tree default_label, ...)
+{
+  va_list al;
+  unsigned i;
+  gimple p;
+  
+  p = gimple_build_switch_1 (nlabels, index, default_label);
+
+  /* Store the rest of the labels.  */
+  va_start (al, default_label);
+  for (i = 1; i <= nlabels; i++)
+    gimple_switch_set_label (p, i, va_arg (al, tree));
+  va_end (al);
+
+  return p;
+}
+
+
+/* Build a GIMPLE_SWITCH statement.
+
+   INDEX is the switch's index.
+   DEFAULT_LABEL is the default label
+   ARGS is a vector of labels excluding the default.  */
+
+gimple
+gimple_build_switch_vec (tree index, tree default_label, VEC(tree, heap) *args)
+{
+  unsigned i;
+  unsigned nlabels = VEC_length (tree, args);
+  gimple p = gimple_build_switch_1 (nlabels, index, default_label);
+
+  /*  Put labels in labels[1 - (nlabels + 1)].
+     Default label is in labels[0].  */
+  for (i = 1; i <= nlabels; i++)
+    gimple_switch_set_label (p, i, VEC_index (tree, args, i - 1));
+
+  return p;
+}
+
+
+/* Build a GIMPLE_OMP_CRITICAL statement.
+
+   BODY is the sequence of statements for which only one thread can execute.
+   NAME is optional identifier for this critical block.  */
+
+gimple 
+gimple_build_omp_critical (gimple_seq body, tree name)
+{
+  gimple p = gimple_alloc (GIMPLE_OMP_CRITICAL, 0);
+  gimple_omp_critical_set_name (p, name);
+  if (body)
+    gimple_omp_set_body (p, body);
+
+  return p;
+}
+
+/* Build a GIMPLE_OMP_FOR statement.
+
+   BODY is sequence of statements inside the for loop.
+   CLAUSES, are any of the OMP loop construct's clauses: private, firstprivate, 
+   lastprivate, reductions, ordered, schedule, and nowait.
+   COLLAPSE is the collapse count.
+   PRE_BODY is the sequence of statements that are loop invariant.  */
+
+gimple
+gimple_build_omp_for (gimple_seq body, tree clauses, size_t collapse,
+		      gimple_seq pre_body)
+{
+  gimple p = gimple_alloc (GIMPLE_OMP_FOR, 0);
+  if (body)
+    gimple_omp_set_body (p, body);
+  gimple_omp_for_set_clauses (p, clauses);
+  p->gimple_omp_for.collapse = collapse;
+  p->gimple_omp_for.iter = GGC_CNEWVEC (struct gimple_omp_for_iter, collapse);
+  if (pre_body)
+    gimple_omp_for_set_pre_body (p, pre_body);
+
+  return p;
+}
+
+
+/* Build a GIMPLE_OMP_PARALLEL statement.
+
+   BODY is sequence of statements which are executed in parallel.
+   CLAUSES, are the OMP parallel construct's clauses.
+   CHILD_FN is the function created for the parallel threads to execute.
+   DATA_ARG are the shared data argument(s).  */
+
+gimple 
+gimple_build_omp_parallel (gimple_seq body, tree clauses, tree child_fn, 
+			   tree data_arg)
+{
+  gimple p = gimple_alloc (GIMPLE_OMP_PARALLEL, 0);
+  if (body)
+    gimple_omp_set_body (p, body);
+  gimple_omp_parallel_set_clauses (p, clauses);
+  gimple_omp_parallel_set_child_fn (p, child_fn);
+  gimple_omp_parallel_set_data_arg (p, data_arg);
+
+  return p;
+}
+
+
+/* Build a GIMPLE_OMP_TASK statement.
+
+   BODY is sequence of statements which are executed by the explicit task.
+   CLAUSES, are the OMP parallel construct's clauses.
+   CHILD_FN is the function created for the parallel threads to execute.
+   DATA_ARG are the shared data argument(s).
+   COPY_FN is the optional function for firstprivate initialization.
+   ARG_SIZE and ARG_ALIGN are size and alignment of the data block.  */
+
+gimple 
+gimple_build_omp_task (gimple_seq body, tree clauses, tree child_fn,
+		       tree data_arg, tree copy_fn, tree arg_size,
+		       tree arg_align)
+{
+  gimple p = gimple_alloc (GIMPLE_OMP_TASK, 0);
+  if (body)
+    gimple_omp_set_body (p, body);
+  gimple_omp_task_set_clauses (p, clauses);
+  gimple_omp_task_set_child_fn (p, child_fn);
+  gimple_omp_task_set_data_arg (p, data_arg);
+  gimple_omp_task_set_copy_fn (p, copy_fn);
+  gimple_omp_task_set_arg_size (p, arg_size);
+  gimple_omp_task_set_arg_align (p, arg_align);
+
+  return p;
+}
+
+
+/* Build a GIMPLE_OMP_SECTION statement for a sections statement.
+
+   BODY is the sequence of statements in the section.  */
+
+gimple
+gimple_build_omp_section (gimple_seq body)
+{
+  gimple p = gimple_alloc (GIMPLE_OMP_SECTION, 0);
+  if (body)
+    gimple_omp_set_body (p, body);
+
+  return p;
+}
+
+
+/* Build a GIMPLE_OMP_MASTER statement.
+
+   BODY is the sequence of statements to be executed by just the master.  */
+
+gimple 
+gimple_build_omp_master (gimple_seq body)
+{
+  gimple p = gimple_alloc (GIMPLE_OMP_MASTER, 0);
+  if (body)
+    gimple_omp_set_body (p, body);
+
+  return p;
+}
+
+
+/* Build a GIMPLE_OMP_CONTINUE statement.
+
+   CONTROL_DEF is the definition of the control variable.
+   CONTROL_USE is the use of the control variable.  */
+
+gimple 
+gimple_build_omp_continue (tree control_def, tree control_use)
+{
+  gimple p = gimple_alloc (GIMPLE_OMP_CONTINUE, 0);
+  gimple_omp_continue_set_control_def (p, control_def);
+  gimple_omp_continue_set_control_use (p, control_use);
+  return p;
+}
+
+/* Build a GIMPLE_OMP_ORDERED statement.
+
+   BODY is the sequence of statements inside a loop that will executed in
+   sequence.  */
+
+gimple 
+gimple_build_omp_ordered (gimple_seq body)
+{
+  gimple p = gimple_alloc (GIMPLE_OMP_ORDERED, 0);
+  if (body)
+    gimple_omp_set_body (p, body);
+
+  return p;
+}
+
+
+/* Build a GIMPLE_OMP_RETURN statement.
+   WAIT_P is true if this is a non-waiting return.  */
+
+gimple 
+gimple_build_omp_return (bool wait_p)
+{
+  gimple p = gimple_alloc (GIMPLE_OMP_RETURN, 0);
+  if (wait_p)
+    gimple_omp_return_set_nowait (p);
+
+  return p;
+}
+
+
+/* Build a GIMPLE_OMP_SECTIONS statement.
+
+   BODY is a sequence of section statements.
+   CLAUSES are any of the OMP sections contsruct's clauses: private,
+   firstprivate, lastprivate, reduction, and nowait.  */
+
+gimple 
+gimple_build_omp_sections (gimple_seq body, tree clauses)
+{
+  gimple p = gimple_alloc (GIMPLE_OMP_SECTIONS, 0);
+  if (body)
+    gimple_omp_set_body (p, body);
+  gimple_omp_sections_set_clauses (p, clauses);
+
+  return p;
+}
+
+
+/* Build a GIMPLE_OMP_SECTIONS_SWITCH.  */
+
+gimple
+gimple_build_omp_sections_switch (void)
+{
+  return gimple_alloc (GIMPLE_OMP_SECTIONS_SWITCH, 0);
+}
+
+
+/* Build a GIMPLE_OMP_SINGLE statement.
+
+   BODY is the sequence of statements that will be executed once.
+   CLAUSES are any of the OMP single construct's clauses: private, firstprivate,
+   copyprivate, nowait.  */
+
+gimple 
+gimple_build_omp_single (gimple_seq body, tree clauses)
+{
+  gimple p = gimple_alloc (GIMPLE_OMP_SINGLE, 0);
+  if (body)
+    gimple_omp_set_body (p, body);
+  gimple_omp_single_set_clauses (p, clauses);
+
+  return p;
+}
+
+
+/* Build a GIMPLE_CHANGE_DYNAMIC_TYPE statement.  TYPE is the new type
+   for the location PTR.  */
+
+gimple
+gimple_build_cdt (tree type, tree ptr)
+{
+  gimple p = gimple_build_with_ops (GIMPLE_CHANGE_DYNAMIC_TYPE, 0, 2);
+  gimple_cdt_set_new_type (p, type);
+  gimple_cdt_set_location (p, ptr);
+
+  return p;
+}
+
+
+/* Build a GIMPLE_OMP_ATOMIC_LOAD statement.  */
+
+gimple
+gimple_build_omp_atomic_load (tree lhs, tree rhs)
+{
+  gimple p = gimple_alloc (GIMPLE_OMP_ATOMIC_LOAD, 0);
+  gimple_omp_atomic_load_set_lhs (p, lhs);
+  gimple_omp_atomic_load_set_rhs (p, rhs);
+  return p;
+}
+
+/* Build a GIMPLE_OMP_ATOMIC_STORE statement.
+
+   VAL is the value we are storing.  */
+
+gimple
+gimple_build_omp_atomic_store (tree val)
+{
+  gimple p = gimple_alloc (GIMPLE_OMP_ATOMIC_STORE, 0);
+  gimple_omp_atomic_store_set_val (p, val);
+  return p;
+}
+
+/* Build a GIMPLE_PREDICT statement.  PREDICT is one of the predictors from
+   predict.def, OUTCOME is NOT_TAKEN or TAKEN.  */
+
+gimple
+gimple_build_predict (enum br_predictor predictor, enum prediction outcome)
+{
+  gimple p = gimple_alloc (GIMPLE_PREDICT, 0);
+  /* Ensure all the predictors fit into the lower bits of the subcode.  */
+  gcc_assert ((int) END_PREDICTORS <= GF_PREDICT_TAKEN);
+  gimple_predict_set_predictor (p, predictor);
+  gimple_predict_set_outcome (p, outcome);
+  return p;
+}
+
+/* Return which gimple structure is used by T.  The enums here are defined
+   in gsstruct.def.  */
+
+enum gimple_statement_structure_enum
+gimple_statement_structure (gimple gs)
+{
+  return gss_for_code (gimple_code (gs));
+}
+
+#if defined ENABLE_GIMPLE_CHECKING
+/* Complain of a gimple type mismatch and die.  */
+
+void
+gimple_check_failed (const_gimple gs, const char *file, int line,
+		     const char *function, enum gimple_code code,
+		     enum tree_code subcode)
+{
+  internal_error ("gimple check: expected %s(%s), have %s(%s) in %s, at %s:%d",
+      		  gimple_code_name[code],
+		  tree_code_name[subcode],
+		  gimple_code_name[gimple_code (gs)],
+		  gs->gsbase.subcode > 0
+		    ? tree_code_name[gs->gsbase.subcode]
+		    : "",
+		  function, trim_filename (file), line);
+}
+#endif /* ENABLE_GIMPLE_CHECKING */
+
+
+/* Allocate a new GIMPLE sequence in GC memory and return it.  If
+   there are free sequences in GIMPLE_SEQ_CACHE return one of those
+   instead.  */
+
+gimple_seq
+gimple_seq_alloc (void)
+{
+  gimple_seq seq = gimple_seq_cache;
+  if (seq)
+    {
+      gimple_seq_cache = gimple_seq_cache->next_free;
+      gcc_assert (gimple_seq_cache != seq);
+      memset (seq, 0, sizeof (*seq));
+    }
+  else
+    {
+      seq = (gimple_seq) ggc_alloc_cleared (sizeof (*seq));
+#ifdef GATHER_STATISTICS
+      gimple_alloc_counts[(int) gimple_alloc_kind_seq]++;
+      gimple_alloc_sizes[(int) gimple_alloc_kind_seq] += sizeof (*seq);
+#endif
+    }
+
+  return seq;
+}
+
+/* Return SEQ to the free pool of GIMPLE sequences.  */
+
+void
+gimple_seq_free (gimple_seq seq)
+{
+  if (seq == NULL)
+    return;
+
+  gcc_assert (gimple_seq_first (seq) == NULL);
+  gcc_assert (gimple_seq_last (seq) == NULL);
+
+  /* If this triggers, it's a sign that the same list is being freed
+     twice.  */
+  gcc_assert (seq != gimple_seq_cache || gimple_seq_cache == NULL);
+  
+  /* Add SEQ to the pool of free sequences.  */
+  seq->next_free = gimple_seq_cache;
+  gimple_seq_cache = seq;
+}
+
+
+/* Link gimple statement GS to the end of the sequence *SEQ_P.  If
+   *SEQ_P is NULL, a new sequence is allocated.  */
+
+void
+gimple_seq_add_stmt (gimple_seq *seq_p, gimple gs)
+{
+  gimple_stmt_iterator si;
+
+  if (gs == NULL)
+    return;
+
+  if (*seq_p == NULL)
+    *seq_p = gimple_seq_alloc ();
+
+  si = gsi_last (*seq_p);
+  gsi_insert_after (&si, gs, GSI_NEW_STMT);
+}
+
+
+/* Append sequence SRC to the end of sequence *DST_P.  If *DST_P is
+   NULL, a new sequence is allocated.  */
+
+void
+gimple_seq_add_seq (gimple_seq *dst_p, gimple_seq src)
+{
+  gimple_stmt_iterator si;
+
+  if (src == NULL)
+    return;
+
+  if (*dst_p == NULL)
+    *dst_p = gimple_seq_alloc ();
+
+  si = gsi_last (*dst_p);
+  gsi_insert_seq_after (&si, src, GSI_NEW_STMT);
+}
+
+
+/* Helper function of empty_body_p.  Return true if STMT is an empty
+   statement.  */
+
+static bool
+empty_stmt_p (gimple stmt)
+{
+  if (gimple_code (stmt) == GIMPLE_NOP)
+    return true;
+  if (gimple_code (stmt) == GIMPLE_BIND)
+    return empty_body_p (gimple_bind_body (stmt));
+  return false;
+}
+
+
+/* Return true if BODY contains nothing but empty statements.  */
+
+bool
+empty_body_p (gimple_seq body)
+{
+  gimple_stmt_iterator i;
+
+
+  if (gimple_seq_empty_p (body))
+    return true;
+  for (i = gsi_start (body); !gsi_end_p (i); gsi_next (&i))
+    if (!empty_stmt_p (gsi_stmt (i)))
+      return false;
+
+  return true;
+}
+
+
+/* Perform a deep copy of sequence SRC and return the result.  */
+
+gimple_seq
+gimple_seq_copy (gimple_seq src)
+{
+  gimple_stmt_iterator gsi;
+  gimple_seq new_seq = gimple_seq_alloc ();
+  gimple stmt;
+
+  for (gsi = gsi_start (src); !gsi_end_p (gsi); gsi_next (&gsi))
+    {
+      stmt = gimple_copy (gsi_stmt (gsi));
+      gimple_seq_add_stmt (&new_seq, stmt);
+    }
+
+  return new_seq;
+}
+
+
+/* Walk all the statements in the sequence SEQ calling walk_gimple_stmt
+   on each one.  WI is as in walk_gimple_stmt.
+   
+   If walk_gimple_stmt returns non-NULL, the walk is stopped, the
+   value is stored in WI->CALLBACK_RESULT and the statement that
+   produced the value is returned.
+
+   Otherwise, all the statements are walked and NULL returned.  */
+
+gimple
+walk_gimple_seq (gimple_seq seq, walk_stmt_fn callback_stmt,
+		 walk_tree_fn callback_op, struct walk_stmt_info *wi)
+{
+  gimple_stmt_iterator gsi;
+
+  for (gsi = gsi_start (seq); !gsi_end_p (gsi); gsi_next (&gsi))
+    {
+      tree ret = walk_gimple_stmt (&gsi, callback_stmt, callback_op, wi);
+      if (ret)
+	{
+	  /* If CALLBACK_STMT or CALLBACK_OP return a value, WI must exist
+	     to hold it.  */
+	  gcc_assert (wi);
+	  wi->callback_result = ret;
+	  return gsi_stmt (gsi);
+	}
+    }
+
+  if (wi)
+    wi->callback_result = NULL_TREE;
+
+  return NULL;
+}
+
+
+/* Helper function for walk_gimple_stmt.  Walk operands of a GIMPLE_ASM.  */
+
+static tree
+walk_gimple_asm (gimple stmt, walk_tree_fn callback_op,
+		 struct walk_stmt_info *wi)
+{
+  tree ret;
+  unsigned noutputs;
+  const char **oconstraints;
+  unsigned i;
+  const char *constraint;
+  bool allows_mem, allows_reg, is_inout;
+
+  noutputs = gimple_asm_noutputs (stmt);
+  oconstraints = (const char **) alloca ((noutputs) * sizeof (const char *));
+
+  if (wi)
+    wi->is_lhs = true;
+
+  for (i = 0; i < noutputs; i++)
+    {
+      tree op = gimple_asm_output_op (stmt, i);
+      constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (op)));
+      oconstraints[i] = constraint;
+      parse_output_constraint (&constraint, i, 0, 0, &allows_mem, &allows_reg,
+	                       &is_inout);
+      if (wi)
+	wi->val_only = (allows_reg || !allows_mem);
+      ret = walk_tree (&TREE_VALUE (op), callback_op, wi, NULL);
+      if (ret)
+	return ret;
+    }
+
+  for (i = 0; i < gimple_asm_ninputs (stmt); i++)
+    {
+      tree op = gimple_asm_input_op (stmt, i);
+      constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (op)));
+      parse_input_constraint (&constraint, 0, 0, noutputs, 0,
+			      oconstraints, &allows_mem, &allows_reg);
+      if (wi)
+	wi->val_only = (allows_reg || !allows_mem);
+
+      /* Although input "m" is not really a LHS, we need a lvalue.  */
+      if (wi)
+	wi->is_lhs = !wi->val_only;
+      ret = walk_tree (&TREE_VALUE (op), callback_op, wi, NULL);
+      if (ret)
+	return ret;
+    }
+
+  if (wi)
+    {
+      wi->is_lhs = false;
+      wi->val_only = true;
+    }
+
+  return NULL_TREE;
+}
+
+
+/* Helper function of WALK_GIMPLE_STMT.  Walk every tree operand in
+   STMT.  CALLBACK_OP and WI are as in WALK_GIMPLE_STMT.
+
+   CALLBACK_OP is called on each operand of STMT via walk_tree.
+   Additional parameters to walk_tree must be stored in WI.  For each operand
+   OP, walk_tree is called as:
+
+	walk_tree (&OP, CALLBACK_OP, WI, WI->PSET)
+
+   If CALLBACK_OP returns non-NULL for an operand, the remaining
+   operands are not scanned.
+
+   The return value is that returned by the last call to walk_tree, or
+   NULL_TREE if no CALLBACK_OP is specified.  */
+
+inline tree
+walk_gimple_op (gimple stmt, walk_tree_fn callback_op,
+		struct walk_stmt_info *wi)
+{
+  struct pointer_set_t *pset = (wi) ? wi->pset : NULL;
+  unsigned i;
+  tree ret = NULL_TREE;
+
+  switch (gimple_code (stmt))
+    {
+    case GIMPLE_ASSIGN:
+      /* Walk the RHS operands.  A formal temporary LHS may use a
+	 COMPONENT_REF RHS.  */
+      if (wi)
+	wi->val_only = !is_gimple_formal_tmp_var (gimple_assign_lhs (stmt));
+
+      for (i = 1; i < gimple_num_ops (stmt); i++)
+	{
+	  ret = walk_tree (gimple_op_ptr (stmt, i), callback_op, wi,
+			   pset);
+	  if (ret)
+	    return ret;
+	}
+
+      /* Walk the LHS.  If the RHS is appropriate for a memory, we
+	 may use a COMPONENT_REF on the LHS.  */
+      if (wi)
+	{
+          /* If the RHS has more than 1 operand, it is not appropriate
+             for the memory.  */
+	  wi->val_only = !is_gimple_mem_rhs (gimple_assign_rhs1 (stmt))
+                         || !gimple_assign_single_p (stmt);
+	  wi->is_lhs = true;
+	}
+
+      ret = walk_tree (gimple_op_ptr (stmt, 0), callback_op, wi, pset);
+      if (ret)
+	return ret;
+
+      if (wi)
+	{
+	  wi->val_only = true;
+	  wi->is_lhs = false;
+	}
+      break;
+
+    case GIMPLE_CALL:
+      if (wi)
+	wi->is_lhs = false;
+
+      ret = walk_tree (gimple_call_chain_ptr (stmt), callback_op, wi, pset);
+      if (ret)
+        return ret;
+
+      ret = walk_tree (gimple_call_fn_ptr (stmt), callback_op, wi, pset);
+      if (ret)
+        return ret;
+
+      for (i = 0; i < gimple_call_num_args (stmt); i++)
+	{
+	  ret = walk_tree (gimple_call_arg_ptr (stmt, i), callback_op, wi,
+			   pset);
+	  if (ret)
+	    return ret;
+	}
+
+      if (wi)
+	wi->is_lhs = true;
+
+      ret = walk_tree (gimple_call_lhs_ptr (stmt), callback_op, wi, pset);
+      if (ret)
+	return ret;
+
+      if (wi)
+	wi->is_lhs = false;
+      break;
+
+    case GIMPLE_CATCH:
+      ret = walk_tree (gimple_catch_types_ptr (stmt), callback_op, wi,
+		       pset);
+      if (ret)
+	return ret;
+      break;
+
+    case GIMPLE_EH_FILTER:
+      ret = walk_tree (gimple_eh_filter_types_ptr (stmt), callback_op, wi,
+		       pset);
+      if (ret)
+	return ret;
+      break;
+
+    case GIMPLE_CHANGE_DYNAMIC_TYPE:
+      ret = walk_tree (gimple_cdt_location_ptr (stmt), callback_op, wi, pset);
+      if (ret)
+	return ret;
+
+      ret = walk_tree (gimple_cdt_new_type_ptr (stmt), callback_op, wi, pset);
+      if (ret)
+	return ret;
+      break;
+
+    case GIMPLE_ASM:
+      ret = walk_gimple_asm (stmt, callback_op, wi);
+      if (ret)
+	return ret;
+      break;
+
+    case GIMPLE_OMP_CONTINUE:
+      ret = walk_tree (gimple_omp_continue_control_def_ptr (stmt),
+	  	       callback_op, wi, pset);
+      if (ret)
+	return ret;
+
+      ret = walk_tree (gimple_omp_continue_control_use_ptr (stmt),
+	  	       callback_op, wi, pset);
+      if (ret)
+	return ret;
+      break;
+
+    case GIMPLE_OMP_CRITICAL:
+      ret = walk_tree (gimple_omp_critical_name_ptr (stmt), callback_op, wi,
+		       pset);
+      if (ret)
+	return ret;
+      break;
+
+    case GIMPLE_OMP_FOR:
+      ret = walk_tree (gimple_omp_for_clauses_ptr (stmt), callback_op, wi,
+		       pset);
+      if (ret)
+	return ret;
+      for (i = 0; i < gimple_omp_for_collapse (stmt); i++)
+	{
+	  ret = walk_tree (gimple_omp_for_index_ptr (stmt, i), callback_op,
+			   wi, pset);
+	  if (ret)
+	    return ret;
+	  ret = walk_tree (gimple_omp_for_initial_ptr (stmt, i), callback_op,
+			   wi, pset);
+	  if (ret)
+	    return ret;
+	  ret = walk_tree (gimple_omp_for_final_ptr (stmt, i), callback_op,
+			   wi, pset);
+	  if (ret)
+	    return ret;
+	  ret = walk_tree (gimple_omp_for_incr_ptr (stmt, i), callback_op,
+			   wi, pset);
+	}
+      if (ret)
+	return ret;
+      break;
+
+    case GIMPLE_OMP_PARALLEL:
+      ret = walk_tree (gimple_omp_parallel_clauses_ptr (stmt), callback_op,
+		       wi, pset);
+      if (ret)
+	return ret;
+      ret = walk_tree (gimple_omp_parallel_child_fn_ptr (stmt), callback_op,
+		       wi, pset);
+      if (ret)
+	return ret;
+      ret = walk_tree (gimple_omp_parallel_data_arg_ptr (stmt), callback_op,
+		       wi, pset);
+      if (ret)
+	return ret;
+      break;
+
+    case GIMPLE_OMP_TASK:
+      ret = walk_tree (gimple_omp_task_clauses_ptr (stmt), callback_op,
+		       wi, pset);
+      if (ret)
+	return ret;
+      ret = walk_tree (gimple_omp_task_child_fn_ptr (stmt), callback_op,
+		       wi, pset);
+      if (ret)
+	return ret;
+      ret = walk_tree (gimple_omp_task_data_arg_ptr (stmt), callback_op,
+		       wi, pset);
+      if (ret)
+	return ret;
+      ret = walk_tree (gimple_omp_task_copy_fn_ptr (stmt), callback_op,
+		       wi, pset);
+      if (ret)
+	return ret;
+      ret = walk_tree (gimple_omp_task_arg_size_ptr (stmt), callback_op,
+		       wi, pset);
+      if (ret)
+	return ret;
+      ret = walk_tree (gimple_omp_task_arg_align_ptr (stmt), callback_op,
+		       wi, pset);
+      if (ret)
+	return ret;
+      break;
+
+    case GIMPLE_OMP_SECTIONS:
+      ret = walk_tree (gimple_omp_sections_clauses_ptr (stmt), callback_op,
+		       wi, pset);
+      if (ret)
+	return ret;
+
+      ret = walk_tree (gimple_omp_sections_control_ptr (stmt), callback_op,
+		       wi, pset);
+      if (ret)
+	return ret;
+
+      break;
+
+    case GIMPLE_OMP_SINGLE:
+      ret = walk_tree (gimple_omp_single_clauses_ptr (stmt), callback_op, wi,
+		       pset);
+      if (ret)
+	return ret;
+      break;
+
+    case GIMPLE_OMP_ATOMIC_LOAD:
+      ret = walk_tree (gimple_omp_atomic_load_lhs_ptr (stmt), callback_op, wi,
+		       pset);
+      if (ret)
+	return ret;
+
+      ret = walk_tree (gimple_omp_atomic_load_rhs_ptr (stmt), callback_op, wi,
+		       pset);
+      if (ret)
+	return ret;
+      break;
+
+    case GIMPLE_OMP_ATOMIC_STORE:
+      ret = walk_tree (gimple_omp_atomic_store_val_ptr (stmt), callback_op,
+		       wi, pset);
+      if (ret)
+	return ret;
+      break;
+
+      /* Tuples that do not have operands.  */
+    case GIMPLE_NOP:
+    case GIMPLE_RESX:
+    case GIMPLE_OMP_RETURN:
+    case GIMPLE_PREDICT:
+      break;
+
+    default:
+      {
+	enum gimple_statement_structure_enum gss;
+	gss = gimple_statement_structure (stmt);
+	if (gss == GSS_WITH_OPS || gss == GSS_WITH_MEM_OPS)
+	  for (i = 0; i < gimple_num_ops (stmt); i++)
+	    {
+	      ret = walk_tree (gimple_op_ptr (stmt, i), callback_op, wi, pset);
+	      if (ret)
+		return ret;
+	    }
+      }
+      break;
+    }
+
+  return NULL_TREE;
+}
+
+
+/* Walk the current statement in GSI (optionally using traversal state
+   stored in WI).  If WI is NULL, no state is kept during traversal.
+   The callback CALLBACK_STMT is called.  If CALLBACK_STMT indicates
+   that it has handled all the operands of the statement, its return
+   value is returned.  Otherwise, the return value from CALLBACK_STMT
+   is discarded and its operands are scanned.
+
+   If CALLBACK_STMT is NULL or it didn't handle the operands,
+   CALLBACK_OP is called on each operand of the statement via
+   walk_gimple_op.  If walk_gimple_op returns non-NULL for any
+   operand, the remaining operands are not scanned.  In this case, the
+   return value from CALLBACK_OP is returned.
+
+   In any other case, NULL_TREE is returned.  */
+
+tree
+walk_gimple_stmt (gimple_stmt_iterator *gsi, walk_stmt_fn callback_stmt,
+		  walk_tree_fn callback_op, struct walk_stmt_info *wi)
+{
+  gimple ret;
+  tree tree_ret;
+  gimple stmt = gsi_stmt (*gsi);
+
+  if (wi)
+    wi->gsi = *gsi;
+
+  if (wi && wi->want_locations && gimple_has_location (stmt))
+    input_location = gimple_location (stmt);
+
+  ret = NULL;
+
+  /* Invoke the statement callback.  Return if the callback handled
+     all of STMT operands by itself.  */
+  if (callback_stmt)
+    {
+      bool handled_ops = false;
+      tree_ret = callback_stmt (gsi, &handled_ops, wi);
+      if (handled_ops)
+	return tree_ret;
+
+      /* If CALLBACK_STMT did not handle operands, it should not have
+	 a value to return.  */
+      gcc_assert (tree_ret == NULL);
+
+      /* Re-read stmt in case the callback changed it.  */
+      stmt = gsi_stmt (*gsi);
+    }
+
+  /* If CALLBACK_OP is defined, invoke it on every operand of STMT.  */
+  if (callback_op)
+    {
+      tree_ret = walk_gimple_op (stmt, callback_op, wi);
+      if (tree_ret)
+	return tree_ret;
+    }
+
+  /* If STMT can have statements inside (e.g. GIMPLE_BIND), walk them.  */
+  switch (gimple_code (stmt))
+    {
+    case GIMPLE_BIND:
+      ret = walk_gimple_seq (gimple_bind_body (stmt), callback_stmt,
+	                     callback_op, wi);
+      if (ret)
+	return wi->callback_result;
+      break;
+
+    case GIMPLE_CATCH:
+      ret = walk_gimple_seq (gimple_catch_handler (stmt), callback_stmt,
+	                     callback_op, wi);
+      if (ret)
+	return wi->callback_result;
+      break;
+
+    case GIMPLE_EH_FILTER:
+      ret = walk_gimple_seq (gimple_eh_filter_failure (stmt), callback_stmt,
+		             callback_op, wi);
+      if (ret)
+	return wi->callback_result;
+      break;
+
+    case GIMPLE_TRY:
+      ret = walk_gimple_seq (gimple_try_eval (stmt), callback_stmt, callback_op,
+	                     wi);
+      if (ret)
+	return wi->callback_result;
+
+      ret = walk_gimple_seq (gimple_try_cleanup (stmt), callback_stmt,
+	                     callback_op, wi);
+      if (ret)
+	return wi->callback_result;
+      break;
+
+    case GIMPLE_OMP_FOR:
+      ret = walk_gimple_seq (gimple_omp_for_pre_body (stmt), callback_stmt,
+		             callback_op, wi);
+      if (ret)
+	return wi->callback_result;
+
+      /* FALL THROUGH.  */
+    case GIMPLE_OMP_CRITICAL:
+    case GIMPLE_OMP_MASTER:
+    case GIMPLE_OMP_ORDERED:
+    case GIMPLE_OMP_SECTION:
+    case GIMPLE_OMP_PARALLEL:
+    case GIMPLE_OMP_TASK:
+    case GIMPLE_OMP_SECTIONS:
+    case GIMPLE_OMP_SINGLE:
+      ret = walk_gimple_seq (gimple_omp_body (stmt), callback_stmt, callback_op,
+	                     wi);
+      if (ret)
+	return wi->callback_result;
+      break;
+
+    case GIMPLE_WITH_CLEANUP_EXPR:
+      ret = walk_gimple_seq (gimple_wce_cleanup (stmt), callback_stmt,
+			     callback_op, wi);
+      if (ret)
+	return wi->callback_result;
+      break;
+
+    default:
+      gcc_assert (!gimple_has_substatements (stmt));
+      break;
+    }
+
+  return NULL;
+}
+
+
+/* Set sequence SEQ to be the GIMPLE body for function FN.  */
+
+void
+gimple_set_body (tree fndecl, gimple_seq seq)
+{
+  struct function *fn = DECL_STRUCT_FUNCTION (fndecl);
+  if (fn == NULL)
+    {
+      /* If FNDECL still does not have a function structure associated
+	 with it, then it does not make sense for it to receive a
+	 GIMPLE body.  */
+      gcc_assert (seq == NULL);
+    }
+  else
+    fn->gimple_body = seq;
+}
+
+
+/* Return the body of GIMPLE statements for function FN.  */
+
+gimple_seq
+gimple_body (tree fndecl)
+{
+  struct function *fn = DECL_STRUCT_FUNCTION (fndecl);
+  return fn ? fn->gimple_body : NULL;
+}
+
+/* Return true when FNDECL has Gimple body either in unlowered
+   or CFG form.  */
+bool
+gimple_has_body_p (tree fndecl)
+{
+  struct function *fn = DECL_STRUCT_FUNCTION (fndecl);
+  return (gimple_body (fndecl) || (fn && fn->cfg));
+}
+
+/* Detect flags from a GIMPLE_CALL.  This is just like
+   call_expr_flags, but for gimple tuples.  */
+
+int
+gimple_call_flags (const_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;
+}
+
+
+/* Return true if GS is a copy assignment.  */
+
+bool
+gimple_assign_copy_p (gimple gs)
+{
+  return gimple_code (gs) == GIMPLE_ASSIGN
+         && get_gimple_rhs_class (gimple_assign_rhs_code (gs))
+	    == GIMPLE_SINGLE_RHS
+	 && is_gimple_val (gimple_op (gs, 1));
+}
+
+
+/* Return true if GS is a SSA_NAME copy assignment.  */
+
+bool
+gimple_assign_ssa_name_copy_p (gimple gs)
+{
+  return (gimple_code (gs) == GIMPLE_ASSIGN
+	  && (get_gimple_rhs_class (gimple_assign_rhs_code (gs))
+	      == GIMPLE_SINGLE_RHS)
+	  && TREE_CODE (gimple_assign_lhs (gs)) == SSA_NAME
+	  && TREE_CODE (gimple_assign_rhs1 (gs)) == SSA_NAME);
+}
+
+
+/* Return true if GS is an assignment with a singleton RHS, i.e.,
+   there is no operator associated with the assignment itself.
+   Unlike gimple_assign_copy_p, this predicate returns true for
+   any RHS operand, including those that perform an operation
+   and do not have the semantics of a copy, such as COND_EXPR.  */
+
+bool
+gimple_assign_single_p (gimple gs)
+{
+  return (gimple_code (gs) == GIMPLE_ASSIGN
+          && get_gimple_rhs_class (gimple_assign_rhs_code (gs))
+	     == GIMPLE_SINGLE_RHS);
+}
+
+/* Return true if GS is an assignment with a unary RHS, but the
+   operator has no effect on the assigned value.  The logic is adapted
+   from STRIP_NOPS.  This predicate is intended to be used in tuplifying
+   instances in which STRIP_NOPS was previously applied to the RHS of
+   an assignment.
+
+   NOTE: In the use cases that led to the creation of this function
+   and of gimple_assign_single_p, it is typical to test for either
+   condition and to proceed in the same manner.  In each case, the
+   assigned value is represented by the single RHS operand of the
+   assignment.  I suspect there may be cases where gimple_assign_copy_p,
+   gimple_assign_single_p, or equivalent logic is used where a similar
+   treatment of unary NOPs is appropriate.  */
+   
+bool
+gimple_assign_unary_nop_p (gimple gs)
+{
+  return (gimple_code (gs) == GIMPLE_ASSIGN
+          && (CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (gs))
+              || gimple_assign_rhs_code (gs) == NON_LVALUE_EXPR)
+          && gimple_assign_rhs1 (gs) != error_mark_node
+          && (TYPE_MODE (TREE_TYPE (gimple_assign_lhs (gs)))
+              == TYPE_MODE (TREE_TYPE (gimple_assign_rhs1 (gs)))));
+}
+
+/* Set BB to be the basic block holding G.  */
+
+void
+gimple_set_bb (gimple stmt, basic_block bb)
+{
+  stmt->gsbase.bb = bb;
+
+  /* If the statement is a label, add the label to block-to-labels map
+     so that we can speed up edge creation for GIMPLE_GOTOs.  */
+  if (cfun->cfg && gimple_code (stmt) == GIMPLE_LABEL)
+    {
+      tree t;
+      int uid;
+
+      t = gimple_label_label (stmt);
+      uid = LABEL_DECL_UID (t);
+      if (uid == -1)
+	{
+	  unsigned old_len = VEC_length (basic_block, label_to_block_map);
+	  LABEL_DECL_UID (t) = uid = cfun->cfg->last_label_uid++;
+	  if (old_len <= (unsigned) uid)
+	    {
+	      unsigned new_len = 3 * uid / 2;
+
+	      VEC_safe_grow_cleared (basic_block, gc, label_to_block_map,
+				     new_len);
+	    }
+	}
+
+      VEC_replace (basic_block, label_to_block_map, uid, bb);
+    }
+}
+
+
+/* Fold the expression computed by STMT.  If the expression can be
+   folded, return the folded result, otherwise return NULL.  STMT is
+   not modified.  */
+
+tree
+gimple_fold (const_gimple stmt)
+{
+  switch (gimple_code (stmt))
+    {
+    case GIMPLE_COND:
+      return fold_binary (gimple_cond_code (stmt),
+			  boolean_type_node,
+			  gimple_cond_lhs (stmt),
+			  gimple_cond_rhs (stmt));
+
+    case GIMPLE_ASSIGN:
+      switch (get_gimple_rhs_class (gimple_assign_rhs_code (stmt)))
+	{
+	case GIMPLE_UNARY_RHS:
+	  return fold_unary (gimple_assign_rhs_code (stmt),
+			     TREE_TYPE (gimple_assign_lhs (stmt)),
+			     gimple_assign_rhs1 (stmt));
+	case GIMPLE_BINARY_RHS:
+	  return fold_binary (gimple_assign_rhs_code (stmt),
+			      TREE_TYPE (gimple_assign_lhs (stmt)),
+			      gimple_assign_rhs1 (stmt),
+			      gimple_assign_rhs2 (stmt));
+	case GIMPLE_SINGLE_RHS:
+	  return fold (gimple_assign_rhs1 (stmt));
+	default:;
+	}
+      break;
+
+    case GIMPLE_SWITCH:
+      return gimple_switch_index (stmt);
+
+    case GIMPLE_CALL:
+      return NULL_TREE;
+
+    default:
+      break;
+    }
+
+  gcc_unreachable ();
+}
+
+
+/* Modify the RHS of the assignment pointed-to by GSI using the
+   operands in the expression tree EXPR.
+
+   NOTE: The statement pointed-to by GSI may be reallocated if it
+   did not have enough operand slots.
+
+   This function is useful to convert an existing tree expression into
+   the flat representation used for the RHS of a GIMPLE assignment.
+   It will reallocate memory as needed to expand or shrink the number
+   of operand slots needed to represent EXPR.
+
+   NOTE: If you find yourself building a tree and then calling this
+   function, you are most certainly doing it the slow way.  It is much
+   better to build a new assignment or to use the function
+   gimple_assign_set_rhs_with_ops, which does not require an
+   expression tree to be built.  */
+
+void
+gimple_assign_set_rhs_from_tree (gimple_stmt_iterator *gsi, tree expr)
+{
+  enum tree_code subcode;
+  tree op1, op2;
+
+  extract_ops_from_tree (expr, &subcode, &op1, &op2);
+  gimple_assign_set_rhs_with_ops (gsi, subcode, op1, op2);
+}
+
+
+/* Set the RHS of assignment statement pointed-to by GSI to CODE with
+   operands OP1 and OP2.
+
+   NOTE: The statement pointed-to by GSI may be reallocated if it
+   did not have enough operand slots.  */
+
+void
+gimple_assign_set_rhs_with_ops (gimple_stmt_iterator *gsi, enum tree_code code,
+				tree op1, tree op2)
+{
+  unsigned new_rhs_ops = get_gimple_rhs_num_ops (code);
+  gimple stmt = gsi_stmt (*gsi);
+
+  /* If the new CODE needs more operands, allocate a new statement.  */
+  if (gimple_num_ops (stmt) < new_rhs_ops + 1)
+    {
+      tree lhs = gimple_assign_lhs (stmt);
+      gimple new_stmt = gimple_alloc (gimple_code (stmt), new_rhs_ops + 1);
+      memcpy (new_stmt, stmt, gimple_size (gimple_code (stmt)));
+      gsi_replace (gsi, new_stmt, true);
+      stmt = new_stmt;
+
+      /* The LHS needs to be reset as this also changes the SSA name
+	 on the LHS.  */
+      gimple_assign_set_lhs (stmt, lhs);
+    }
+
+  gimple_set_num_ops (stmt, new_rhs_ops + 1);
+  gimple_set_subcode (stmt, code);
+  gimple_assign_set_rhs1 (stmt, op1);
+  if (new_rhs_ops > 1)
+    gimple_assign_set_rhs2 (stmt, op2);
+}
+
+
+/* Return the LHS of a statement that performs an assignment,
+   either a GIMPLE_ASSIGN or a GIMPLE_CALL.  Returns NULL_TREE
+   for a call to a function that returns no value, or for a
+   statement other than an assignment or a call.  */
+
+tree
+gimple_get_lhs (const_gimple stmt)
+{
+  enum gimple_code code = gimple_code (stmt);
+
+  if (code == GIMPLE_ASSIGN)
+    return gimple_assign_lhs (stmt);
+  else if (code == GIMPLE_CALL)
+    return gimple_call_lhs (stmt);
+  else
+    return NULL_TREE;
+}
+
+
+/* Set the LHS of a statement that performs an assignment,
+   either a GIMPLE_ASSIGN or a GIMPLE_CALL.  */
+
+void
+gimple_set_lhs (gimple stmt, tree lhs)
+{
+  enum gimple_code code = gimple_code (stmt);
+
+  if (code == GIMPLE_ASSIGN)
+    gimple_assign_set_lhs (stmt, lhs);
+  else if (code == GIMPLE_CALL)
+    gimple_call_set_lhs (stmt, lhs);
+  else
+    gcc_unreachable();
+}
+
+
+/* Return a deep copy of statement STMT.  All the operands from STMT
+   are reallocated and copied using unshare_expr.  The DEF, USE, VDEF
+   and VUSE operand arrays are set to empty in the new copy.  */
+
+gimple
+gimple_copy (gimple stmt)
+{
+  enum gimple_code code = gimple_code (stmt);
+  unsigned num_ops = gimple_num_ops (stmt);
+  gimple copy = gimple_alloc (code, num_ops);
+  unsigned i;
+
+  /* Shallow copy all the fields from STMT.  */
+  memcpy (copy, stmt, gimple_size (code));
+
+  /* If STMT has sub-statements, deep-copy them as well.  */
+  if (gimple_has_substatements (stmt))
+    {
+      gimple_seq new_seq;
+      tree t;
+
+      switch (gimple_code (stmt))
+	{
+	case GIMPLE_BIND:
+	  new_seq = gimple_seq_copy (gimple_bind_body (stmt));
+	  gimple_bind_set_body (copy, new_seq);
+	  gimple_bind_set_vars (copy, unshare_expr (gimple_bind_vars (stmt)));
+	  gimple_bind_set_block (copy, gimple_bind_block (stmt));
+	  break;
+
+	case GIMPLE_CATCH:
+	  new_seq = gimple_seq_copy (gimple_catch_handler (stmt));
+	  gimple_catch_set_handler (copy, new_seq);
+	  t = unshare_expr (gimple_catch_types (stmt));
+	  gimple_catch_set_types (copy, t);
+	  break;
+
+	case GIMPLE_EH_FILTER:
+	  new_seq = gimple_seq_copy (gimple_eh_filter_failure (stmt));
+	  gimple_eh_filter_set_failure (copy, new_seq);
+	  t = unshare_expr (gimple_eh_filter_types (stmt));
+	  gimple_eh_filter_set_types (copy, t);
+	  break;
+
+	case GIMPLE_TRY:
+	  new_seq = gimple_seq_copy (gimple_try_eval (stmt));
+	  gimple_try_set_eval (copy, new_seq);
+	  new_seq = gimple_seq_copy (gimple_try_cleanup (stmt));
+	  gimple_try_set_cleanup (copy, new_seq);
+	  break;
+
+	case GIMPLE_OMP_FOR:
+	  new_seq = gimple_seq_copy (gimple_omp_for_pre_body (stmt));
+	  gimple_omp_for_set_pre_body (copy, new_seq);
+	  t = unshare_expr (gimple_omp_for_clauses (stmt));
+	  gimple_omp_for_set_clauses (copy, t);
+	  copy->gimple_omp_for.iter
+	    = GGC_NEWVEC (struct gimple_omp_for_iter,
+			  gimple_omp_for_collapse (stmt));
+	  for (i = 0; i < gimple_omp_for_collapse (stmt); i++)
+	    {
+	      gimple_omp_for_set_cond (copy, i,
+				       gimple_omp_for_cond (stmt, i));
+	      gimple_omp_for_set_index (copy, i,
+					gimple_omp_for_index (stmt, i));
+	      t = unshare_expr (gimple_omp_for_initial (stmt, i));
+	      gimple_omp_for_set_initial (copy, i, t);
+	      t = unshare_expr (gimple_omp_for_final (stmt, i));
+	      gimple_omp_for_set_final (copy, i, t);
+	      t = unshare_expr (gimple_omp_for_incr (stmt, i));
+	      gimple_omp_for_set_incr (copy, i, t);
+	    }
+	  goto copy_omp_body;
+
+	case GIMPLE_OMP_PARALLEL:
+	  t = unshare_expr (gimple_omp_parallel_clauses (stmt));
+	  gimple_omp_parallel_set_clauses (copy, t);
+	  t = unshare_expr (gimple_omp_parallel_child_fn (stmt));
+	  gimple_omp_parallel_set_child_fn (copy, t);
+	  t = unshare_expr (gimple_omp_parallel_data_arg (stmt));
+	  gimple_omp_parallel_set_data_arg (copy, t);
+	  goto copy_omp_body;
+
+	case GIMPLE_OMP_TASK:
+	  t = unshare_expr (gimple_omp_task_clauses (stmt));
+	  gimple_omp_task_set_clauses (copy, t);
+	  t = unshare_expr (gimple_omp_task_child_fn (stmt));
+	  gimple_omp_task_set_child_fn (copy, t);
+	  t = unshare_expr (gimple_omp_task_data_arg (stmt));
+	  gimple_omp_task_set_data_arg (copy, t);
+	  t = unshare_expr (gimple_omp_task_copy_fn (stmt));
+	  gimple_omp_task_set_copy_fn (copy, t);
+	  t = unshare_expr (gimple_omp_task_arg_size (stmt));
+	  gimple_omp_task_set_arg_size (copy, t);
+	  t = unshare_expr (gimple_omp_task_arg_align (stmt));
+	  gimple_omp_task_set_arg_align (copy, t);
+	  goto copy_omp_body;
+
+	case GIMPLE_OMP_CRITICAL:
+	  t = unshare_expr (gimple_omp_critical_name (stmt));
+	  gimple_omp_critical_set_name (copy, t);
+	  goto copy_omp_body;
+
+	case GIMPLE_OMP_SECTIONS:
+	  t = unshare_expr (gimple_omp_sections_clauses (stmt));
+	  gimple_omp_sections_set_clauses (copy, t);
+	  t = unshare_expr (gimple_omp_sections_control (stmt));
+	  gimple_omp_sections_set_control (copy, t);
+	  /* FALLTHRU  */
+
+	case GIMPLE_OMP_SINGLE:
+	case GIMPLE_OMP_SECTION:
+	case GIMPLE_OMP_MASTER:
+	case GIMPLE_OMP_ORDERED:
+	copy_omp_body:
+	  new_seq = gimple_seq_copy (gimple_omp_body (stmt));
+	  gimple_omp_set_body (copy, new_seq);
+	  break;
+
+	case GIMPLE_WITH_CLEANUP_EXPR:
+	  new_seq = gimple_seq_copy (gimple_wce_cleanup (stmt));
+	  gimple_wce_set_cleanup (copy, new_seq);
+	  break;
+
+	default:
+	  gcc_unreachable ();
+	}
+    }
+
+  /* Make copy of operands.  */
+  if (num_ops > 0)
+    {
+      for (i = 0; i < num_ops; i++)
+	gimple_set_op (copy, i, unshare_expr (gimple_op (stmt, i)));
+
+      /* Clear out SSA operand vectors on COPY.  Note that we cannot
+	 call the API functions for setting addresses_taken, stores
+	 and loads.  These functions free the previous values, and we
+	 cannot do that on COPY as it will affect the original
+	 statement.  */
+      if (gimple_has_ops (stmt))
+	{
+	  gimple_set_def_ops (copy, NULL);
+	  gimple_set_use_ops (copy, NULL);
+	  copy->gsops.opbase.addresses_taken = NULL;
+	}
+
+      if (gimple_has_mem_ops (stmt))
+	{
+	  gimple_set_vdef_ops (copy, NULL);
+	  gimple_set_vuse_ops (copy, NULL);
+	  copy->gsmem.membase.stores = NULL;
+	  copy->gsmem.membase.loads = NULL;
+	}
+
+      update_stmt (copy);
+    }
+
+  return copy;
+}
+
+
+/* Set the MODIFIED flag to MODIFIEDP, iff the gimple statement G has
+   a MODIFIED field.  */
+
+void
+gimple_set_modified (gimple s, bool modifiedp)
+{
+  if (gimple_has_ops (s))
+    {
+      s->gsbase.modified = (unsigned) modifiedp;
+
+      if (modifiedp
+	  && cfun->gimple_df
+	  && is_gimple_call (s)
+	  && gimple_call_noreturn_p (s))
+	VEC_safe_push (gimple, gc, MODIFIED_NORETURN_CALLS (cfun), s);
+    }
+}
+
+
+/* Return true if statement S has side-effects.  We consider a
+   statement to have side effects if:
+
+   - It is a GIMPLE_CALL not marked with ECF_PURE or ECF_CONST.
+   - Any of its operands are marked TREE_THIS_VOLATILE or TREE_SIDE_EFFECTS.  */
+
+bool
+gimple_has_side_effects (const_gimple s)
+{
+  unsigned i;
+
+  /* We don't have to scan the arguments to check for
+     volatile arguments, though, at present, we still
+     do a scan to check for TREE_SIDE_EFFECTS.  */
+  if (gimple_has_volatile_ops (s))
+    return true;
+
+  if (is_gimple_call (s))
+    {
+      unsigned nargs = gimple_call_num_args (s);
+
+      if (!(gimple_call_flags (s) & (ECF_CONST | ECF_PURE)))
+        return true;
+      else if (gimple_call_flags (s) & ECF_LOOPING_CONST_OR_PURE)
+	/* An infinite loop is considered a side effect.  */
+	return true;
+
+      if (gimple_call_lhs (s)
+          && TREE_SIDE_EFFECTS (gimple_call_lhs (s)))
+	{
+	  gcc_assert (gimple_has_volatile_ops (s));
+	  return true;
+	}
+
+      if (TREE_SIDE_EFFECTS (gimple_call_fn (s)))
+        return true;
+
+      for (i = 0; i < nargs; i++)
+        if (TREE_SIDE_EFFECTS (gimple_call_arg (s, i)))
+	  {
+	    gcc_assert (gimple_has_volatile_ops (s));
+	    return true;
+	  }
+
+      return false;
+    }
+  else
+    {
+      for (i = 0; i < gimple_num_ops (s); i++)
+	if (TREE_SIDE_EFFECTS (gimple_op (s, i)))
+	  {
+	    gcc_assert (gimple_has_volatile_ops (s));
+	    return true;
+	  }
+    }
+
+  return false;
+}
+
+/* Return true if the RHS of statement S has side effects.
+   We may use it to determine if it is admissable to replace
+   an assignment or call with a copy of a previously-computed
+   value.  In such cases, side-effects due the the LHS are
+   preserved.  */
+
+bool
+gimple_rhs_has_side_effects (const_gimple s)
+{
+  unsigned i;
+
+  if (is_gimple_call (s))
+    {
+      unsigned nargs = gimple_call_num_args (s);
+
+      if (!(gimple_call_flags (s) & (ECF_CONST | ECF_PURE)))
+        return true;
+
+      /* We cannot use gimple_has_volatile_ops here,
+         because we must ignore a volatile LHS.  */
+      if (TREE_SIDE_EFFECTS (gimple_call_fn (s))
+          || TREE_THIS_VOLATILE (gimple_call_fn (s)))
+	{
+	  gcc_assert (gimple_has_volatile_ops (s));
+	  return true;
+	}
+
+      for (i = 0; i < nargs; i++)
+        if (TREE_SIDE_EFFECTS (gimple_call_arg (s, i))
+            || TREE_THIS_VOLATILE (gimple_call_arg (s, i)))
+          return true;
+
+      return false;
+    }
+  else if (is_gimple_assign (s))
+    {
+      /* Skip the first operand, the LHS. */
+      for (i = 1; i < gimple_num_ops (s); i++)
+	if (TREE_SIDE_EFFECTS (gimple_op (s, i))
+            || TREE_THIS_VOLATILE (gimple_op (s, i)))
+	  {
+	    gcc_assert (gimple_has_volatile_ops (s));
+	    return true;
+	  }
+    }
+  else
+    {
+      /* For statements without an LHS, examine all arguments.  */
+      for (i = 0; i < gimple_num_ops (s); i++)
+	if (TREE_SIDE_EFFECTS (gimple_op (s, i))
+            || TREE_THIS_VOLATILE (gimple_op (s, i)))
+	  {
+	    gcc_assert (gimple_has_volatile_ops (s));
+	    return true;
+	  }
+    }
+
+  return false;
+}
+
+
+/* Helper for gimple_could_trap_p and gimple_assign_rhs_could_trap_p.
+   Return true if S can trap.  If INCLUDE_LHS is true and S is a
+   GIMPLE_ASSIGN, the LHS of the assignment is also checked.
+   Otherwise, only the RHS of the assignment is checked.  */
+
+static bool
+gimple_could_trap_p_1 (gimple s, bool include_lhs)
+{
+  unsigned i, start;
+  tree t, div = NULL_TREE;
+  enum tree_code op;
+
+  start = (is_gimple_assign (s) && !include_lhs) ? 1 : 0;
+
+  for (i = start; i < gimple_num_ops (s); i++)
+    if (tree_could_trap_p (gimple_op (s, i)))
+      return true;
+
+  switch (gimple_code (s))
+    {
+    case GIMPLE_ASM:
+      return gimple_asm_volatile_p (s);
+
+    case GIMPLE_CALL:
+      t = gimple_call_fndecl (s);
+      /* Assume that calls to weak functions may trap.  */
+      if (!t || !DECL_P (t) || DECL_WEAK (t))
+	return true;
+      return false;
+
+    case GIMPLE_ASSIGN:
+      t = gimple_expr_type (s);
+      op = gimple_assign_rhs_code (s);
+      if (get_gimple_rhs_class (op) == GIMPLE_BINARY_RHS)
+	div = gimple_assign_rhs2 (s);
+      return (operation_could_trap_p (op, FLOAT_TYPE_P (t),
+				      (INTEGRAL_TYPE_P (t)
+				       && TYPE_OVERFLOW_TRAPS (t)),
+				      div));
+
+    default:
+      break;
+    }
+
+  return false;
+
+}
+
+
+/* Return true if statement S can trap.  */
+
+bool
+gimple_could_trap_p (gimple s)
+{
+  return gimple_could_trap_p_1 (s, true);
+}
+
+
+/* Return true if RHS of a GIMPLE_ASSIGN S can trap.  */
+
+bool
+gimple_assign_rhs_could_trap_p (gimple s)
+{
+  gcc_assert (is_gimple_assign (s));
+  return gimple_could_trap_p_1 (s, false);
+}
+
+
+/* Print debugging information for gimple stmts generated.  */
+
+void
+dump_gimple_statistics (void)
+{
+#ifdef GATHER_STATISTICS
+  int i, total_tuples = 0, total_bytes = 0;
+
+  fprintf (stderr, "\nGIMPLE statements\n");
+  fprintf (stderr, "Kind                   Stmts      Bytes\n");
+  fprintf (stderr, "---------------------------------------\n");
+  for (i = 0; i < (int) gimple_alloc_kind_all; ++i)
+    {
+      fprintf (stderr, "%-20s %7d %10d\n", gimple_alloc_kind_names[i],
+	  gimple_alloc_counts[i], gimple_alloc_sizes[i]);
+      total_tuples += gimple_alloc_counts[i];
+      total_bytes += gimple_alloc_sizes[i];
+    }
+  fprintf (stderr, "---------------------------------------\n");
+  fprintf (stderr, "%-20s %7d %10d\n", "Total", total_tuples, total_bytes);
+  fprintf (stderr, "---------------------------------------\n");
+#else
+  fprintf (stderr, "No gimple statistics\n");
+#endif
+}
+
+
+/* Deep copy SYMS into the set of symbols stored by STMT.  If SYMS is
+   NULL or empty, the storage used is freed up.  */
+
+void
+gimple_set_stored_syms (gimple stmt, bitmap syms, bitmap_obstack *obs)
+{
+  gcc_assert (gimple_has_mem_ops (stmt));
+
+  if (syms == NULL || bitmap_empty_p (syms))
+    BITMAP_FREE (stmt->gsmem.membase.stores);
+  else
+    {
+      if (stmt->gsmem.membase.stores == NULL)
+	stmt->gsmem.membase.stores = BITMAP_ALLOC (obs);
+
+      bitmap_copy (stmt->gsmem.membase.stores, syms);
+    }
+}
+
+
+/* Deep copy SYMS into the set of symbols loaded by STMT.  If SYMS is
+   NULL or empty, the storage used is freed up.  */
+
+void
+gimple_set_loaded_syms (gimple stmt, bitmap syms, bitmap_obstack *obs)
+{
+  gcc_assert (gimple_has_mem_ops (stmt));
+
+  if (syms == NULL || bitmap_empty_p (syms))
+    BITMAP_FREE (stmt->gsmem.membase.loads);
+  else
+    {
+      if (stmt->gsmem.membase.loads == NULL)
+	stmt->gsmem.membase.loads = BITMAP_ALLOC (obs);
+
+      bitmap_copy (stmt->gsmem.membase.loads, syms);
+    }
+}
+
+
+/* Return the number of operands needed on the RHS of a GIMPLE
+   assignment for an expression with tree code CODE.  */
+
+unsigned
+get_gimple_rhs_num_ops (enum tree_code code)
+{
+  enum gimple_rhs_class rhs_class = get_gimple_rhs_class (code);
+
+  if (rhs_class == GIMPLE_UNARY_RHS || rhs_class == GIMPLE_SINGLE_RHS)
+    return 1;
+  else if (rhs_class == GIMPLE_BINARY_RHS)
+    return 2;
+  else
+    gcc_unreachable ();
+}
+
+#define DEFTREECODE(SYM, STRING, TYPE, NARGS)   			    \
+  (unsigned char)							    \
+  ((TYPE) == tcc_unary ? GIMPLE_UNARY_RHS				    \
+   : ((TYPE) == tcc_binary						    \
+      || (TYPE) == tcc_comparison) ? GIMPLE_BINARY_RHS   		    \
+   : ((TYPE) == tcc_constant						    \
+      || (TYPE) == tcc_declaration					    \
+      || (TYPE) == tcc_reference) ? GIMPLE_SINGLE_RHS			    \
+   : ((SYM) == TRUTH_AND_EXPR						    \
+      || (SYM) == TRUTH_OR_EXPR						    \
+      || (SYM) == TRUTH_XOR_EXPR) ? GIMPLE_BINARY_RHS			    \
+   : (SYM) == TRUTH_NOT_EXPR ? GIMPLE_UNARY_RHS				    \
+   : ((SYM) == COND_EXPR						    \
+      || (SYM) == CONSTRUCTOR						    \
+      || (SYM) == OBJ_TYPE_REF						    \
+      || (SYM) == ASSERT_EXPR						    \
+      || (SYM) == ADDR_EXPR						    \
+      || (SYM) == WITH_SIZE_EXPR					    \
+      || (SYM) == EXC_PTR_EXPR						    \
+      || (SYM) == SSA_NAME						    \
+      || (SYM) == FILTER_EXPR						    \
+      || (SYM) == POLYNOMIAL_CHREC					    \
+      || (SYM) == DOT_PROD_EXPR						    \
+      || (SYM) == VEC_COND_EXPR						    \
+      || (SYM) == REALIGN_LOAD_EXPR) ? GIMPLE_SINGLE_RHS		    \
+   : GIMPLE_INVALID_RHS),
+#define END_OF_BASE_TREE_CODES (unsigned char) GIMPLE_INVALID_RHS,
+
+const unsigned char gimple_rhs_class_table[] = {
+#include "all-tree.def"
+};
+
+#undef DEFTREECODE
+#undef END_OF_BASE_TREE_CODES
+
+/* For the definitive definition of GIMPLE, see doc/tree-ssa.texi.  */
+
+/* Validation of GIMPLE expressions.  */
+
+/* Return true if OP is an acceptable tree node to be used as a GIMPLE
+   operand.  */
+
+bool
+is_gimple_operand (const_tree op)
+{
+  return op && get_gimple_rhs_class (TREE_CODE (op)) == GIMPLE_SINGLE_RHS;
+}
+
+
+/* Return true if T is a GIMPLE RHS for an assignment to a temporary.  */
+
+bool
+is_gimple_formal_tmp_rhs (tree t)
+{
+  if (is_gimple_lvalue (t) || is_gimple_val (t))
+    return true;
+
+  return get_gimple_rhs_class (TREE_CODE (t)) != GIMPLE_INVALID_RHS;
+}
+
+/* Returns true iff T is a valid RHS for an assignment to a renamed
+   user -- or front-end generated artificial -- variable.  */
+
+bool
+is_gimple_reg_rhs (tree t)
+{
+  /* If the RHS of the MODIFY_EXPR may throw or make a nonlocal goto
+     and the LHS is a user variable, then we need to introduce a formal
+     temporary.  This way the optimizers can determine that the user
+     variable is only modified if evaluation of the RHS does not throw.
+
+     Don't force a temp of a non-renamable type; the copy could be
+     arbitrarily expensive.  Instead we will generate a VDEF for
+     the assignment.  */
+
+  if (is_gimple_reg_type (TREE_TYPE (t)) && tree_could_throw_p (t))
+    return false;
+
+  return is_gimple_formal_tmp_rhs (t);
+}
+
+/* Returns true iff T is a valid RHS for an assignment to an un-renamed
+   LHS, or for a call argument.  */
+
+bool
+is_gimple_mem_rhs (tree t)
+{
+  /* If we're dealing with a renamable type, either source or dest must be
+     a renamed variable.  */
+  if (is_gimple_reg_type (TREE_TYPE (t)))
+    return is_gimple_val (t);
+  else
+    return is_gimple_formal_tmp_rhs (t);
+}
+
+/*  Return true if T is a valid LHS for a GIMPLE assignment expression.  */
+
+bool
+is_gimple_lvalue (tree t)
+{
+  return (is_gimple_addressable (t)
+	  || TREE_CODE (t) == WITH_SIZE_EXPR
+	  /* These are complex lvalues, but don't have addresses, so they
+	     go here.  */
+	  || TREE_CODE (t) == BIT_FIELD_REF);
+}
+
+/*  Return true if T is a GIMPLE condition.  */
+
+bool
+is_gimple_condexpr (tree t)
+{
+  return (is_gimple_val (t) || (COMPARISON_CLASS_P (t)
+				&& !tree_could_trap_p (t)
+				&& is_gimple_val (TREE_OPERAND (t, 0))
+				&& is_gimple_val (TREE_OPERAND (t, 1))));
+}
+
+/*  Return true if T is something whose address can be taken.  */
+
+bool
+is_gimple_addressable (tree t)
+{
+  return (is_gimple_id (t) || handled_component_p (t) || INDIRECT_REF_P (t));
+}
+
+/* Return true if T is a valid gimple constant.  */
+
+bool
+is_gimple_constant (const_tree t)
+{
+  switch (TREE_CODE (t))
+    {
+    case INTEGER_CST:
+    case REAL_CST:
+    case FIXED_CST:
+    case STRING_CST:
+    case COMPLEX_CST:
+    case VECTOR_CST:
+      return true;
+
+    /* Vector constant constructors are gimple invariant.  */
+    case CONSTRUCTOR:
+      if (TREE_TYPE (t) && TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE)
+	return TREE_CONSTANT (t);
+      else
+	return false;
+
+    default:
+      return false;
+    }
+}
+
+/* Return true if T is a gimple address.  */
+
+bool
+is_gimple_address (const_tree t)
+{
+  tree op;
+
+  if (TREE_CODE (t) != ADDR_EXPR)
+    return false;
+
+  op = TREE_OPERAND (t, 0);
+  while (handled_component_p (op))
+    {
+      if ((TREE_CODE (op) == ARRAY_REF
+	   || TREE_CODE (op) == ARRAY_RANGE_REF)
+	  && !is_gimple_val (TREE_OPERAND (op, 1)))
+	    return false;
+
+      op = TREE_OPERAND (op, 0);
+    }
+
+  if (CONSTANT_CLASS_P (op) || INDIRECT_REF_P (op))
+    return true;
+
+  switch (TREE_CODE (op))
+    {
+    case PARM_DECL:
+    case RESULT_DECL:
+    case LABEL_DECL:
+    case FUNCTION_DECL:
+    case VAR_DECL:
+    case CONST_DECL:
+      return true;
+
+    default:
+      return false;
+    }
+}
+
+/* Strip out all handled components that produce invariant
+   offsets.  */
+
+static const_tree
+strip_invariant_refs (const_tree op)
+{
+  while (handled_component_p (op))
+    {
+      switch (TREE_CODE (op))
+	{
+	case ARRAY_REF:
+	case ARRAY_RANGE_REF:
+	  if (!is_gimple_constant (TREE_OPERAND (op, 1))
+	      || TREE_OPERAND (op, 2) != NULL_TREE
+	      || TREE_OPERAND (op, 3) != NULL_TREE)
+	    return NULL;
+	  break;
+
+	case COMPONENT_REF:
+	  if (TREE_OPERAND (op, 2) != NULL_TREE)
+	    return NULL;
+	  break;
+
+	default:;
+	}
+      op = TREE_OPERAND (op, 0);
+    }
+
+  return op;
+}
+
+/* Return true if T is a gimple invariant address.  */
+
+bool
+is_gimple_invariant_address (const_tree t)
+{
+  const_tree op;
+
+  if (TREE_CODE (t) != ADDR_EXPR)
+    return false;
+
+  op = strip_invariant_refs (TREE_OPERAND (t, 0));
+
+  return op && (CONSTANT_CLASS_P (op) || decl_address_invariant_p (op));
+}
+
+/* Return true if T is a gimple invariant address at IPA level
+   (so addresses of variables on stack are not allowed).  */
+
+bool
+is_gimple_ip_invariant_address (const_tree t)
+{
+  const_tree op;
+
+  if (TREE_CODE (t) != ADDR_EXPR)
+    return false;
+
+  op = strip_invariant_refs (TREE_OPERAND (t, 0));
+
+  return op && (CONSTANT_CLASS_P (op) || decl_address_ip_invariant_p (op));
+}
+
+/* Return true if T is a GIMPLE minimal invariant.  It's a restricted
+   form of function invariant.  */
+
+bool
+is_gimple_min_invariant (const_tree t)
+{
+  if (TREE_CODE (t) == ADDR_EXPR)
+    return is_gimple_invariant_address (t);
+
+  return is_gimple_constant (t);
+}
+
+/* Return true if T is a GIMPLE interprocedural invariant.  It's a restricted
+   form of gimple minimal invariant.  */
+
+bool
+is_gimple_ip_invariant (const_tree t)
+{
+  if (TREE_CODE (t) == ADDR_EXPR)
+    return is_gimple_ip_invariant_address (t);
+
+  return is_gimple_constant (t);
+}
+
+/* Return true if T looks like a valid GIMPLE statement.  */
+
+bool
+is_gimple_stmt (tree t)
+{
+  const enum tree_code code = TREE_CODE (t);
+
+  switch (code)
+    {
+    case NOP_EXPR:
+      /* The only valid NOP_EXPR is the empty statement.  */
+      return IS_EMPTY_STMT (t);
+
+    case BIND_EXPR:
+    case COND_EXPR:
+      /* These are only valid if they're void.  */
+      return TREE_TYPE (t) == NULL || VOID_TYPE_P (TREE_TYPE (t));
+
+    case SWITCH_EXPR:
+    case GOTO_EXPR:
+    case RETURN_EXPR:
+    case LABEL_EXPR:
+    case CASE_LABEL_EXPR:
+    case TRY_CATCH_EXPR:
+    case TRY_FINALLY_EXPR:
+    case EH_FILTER_EXPR:
+    case CATCH_EXPR:
+    case CHANGE_DYNAMIC_TYPE_EXPR:
+    case ASM_EXPR:
+    case RESX_EXPR:
+    case STATEMENT_LIST:
+    case OMP_PARALLEL:
+    case OMP_FOR:
+    case OMP_SECTIONS:
+    case OMP_SECTION:
+    case OMP_SINGLE:
+    case OMP_MASTER:
+    case OMP_ORDERED:
+    case OMP_CRITICAL:
+    case OMP_TASK:
+      /* These are always void.  */
+      return true;
+
+    case CALL_EXPR:
+    case MODIFY_EXPR:
+    case PREDICT_EXPR:
+      /* These are valid regardless of their type.  */
+      return true;
+
+    default:
+      return false;
+    }
+}
+
+/* Return true if T is a variable.  */
+
+bool
+is_gimple_variable (tree t)
+{
+  return (TREE_CODE (t) == VAR_DECL
+	  || TREE_CODE (t) == PARM_DECL
+	  || TREE_CODE (t) == RESULT_DECL
+	  || TREE_CODE (t) == SSA_NAME);
+}
+
+/*  Return true if T is a GIMPLE identifier (something with an address).  */
+
+bool
+is_gimple_id (tree t)
+{
+  return (is_gimple_variable (t)
+	  || TREE_CODE (t) == FUNCTION_DECL
+	  || TREE_CODE (t) == LABEL_DECL
+	  || TREE_CODE (t) == CONST_DECL
+	  /* Allow string constants, since they are addressable.  */
+	  || TREE_CODE (t) == STRING_CST);
+}
+
+/* Return true if TYPE is a suitable type for a scalar register variable.  */
+
+bool
+is_gimple_reg_type (tree type)
+{
+  /* In addition to aggregate types, we also exclude complex types if not
+     optimizing because they can be subject to partial stores in GNU C by
+     means of the __real__ and __imag__ operators and we cannot promote
+     them to total stores (see gimplify_modify_expr_complex_part).  */
+  return !(AGGREGATE_TYPE_P (type)
+	   || (TREE_CODE (type) == COMPLEX_TYPE && !optimize));
+
+}
+
+/* Return true if T is a non-aggregate register variable.  */
+
+bool
+is_gimple_reg (tree t)
+{
+  if (TREE_CODE (t) == SSA_NAME)
+    t = SSA_NAME_VAR (t);
+
+  if (MTAG_P (t))
+    return false;
+
+  if (!is_gimple_variable (t))
+    return false;
+
+  if (!is_gimple_reg_type (TREE_TYPE (t)))
+    return false;
+
+  /* A volatile decl is not acceptable because we can't reuse it as
+     needed.  We need to copy it into a temp first.  */
+  if (TREE_THIS_VOLATILE (t))
+    return false;
+
+  /* We define "registers" as things that can be renamed as needed,
+     which with our infrastructure does not apply to memory.  */
+  if (needs_to_live_in_memory (t))
+    return false;
+
+  /* Hard register variables are an interesting case.  For those that
+     are call-clobbered, we don't know where all the calls are, since
+     we don't (want to) take into account which operations will turn
+     into libcalls at the rtl level.  For those that are call-saved,
+     we don't currently model the fact that calls may in fact change
+     global hard registers, nor do we examine ASM_CLOBBERS at the tree
+     level, and so miss variable changes that might imply.  All around,
+     it seems safest to not do too much optimization with these at the
+     tree level at all.  We'll have to rely on the rtl optimizers to
+     clean this up, as there we've got all the appropriate bits exposed.  */
+  if (TREE_CODE (t) == VAR_DECL && DECL_HARD_REGISTER (t))
+    return false;
+
+  /* Complex and vector values must have been put into SSA-like form.
+     That is, no assignments to the individual components.  */
+  if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE
+      || TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE)
+    return DECL_GIMPLE_REG_P (t);
+
+  return true;
+}
+
+
+/* Returns true if T is a GIMPLE formal temporary variable.  */
+
+bool
+is_gimple_formal_tmp_var (tree t)
+{
+  if (TREE_CODE (t) == SSA_NAME)
+    return true;
+
+  return TREE_CODE (t) == VAR_DECL && DECL_GIMPLE_FORMAL_TEMP_P (t);
+}
+
+/* Returns true if T is a GIMPLE formal temporary register variable.  */
+
+bool
+is_gimple_formal_tmp_reg (tree t)
+{
+  /* The intent of this is to get hold of a value that won't change.
+     An SSA_NAME qualifies no matter if its of a user variable or not.  */
+  if (TREE_CODE (t) == SSA_NAME)
+    return true;
+
+  /* We don't know the lifetime characteristics of user variables.  */
+  if (!is_gimple_formal_tmp_var (t))
+    return false;
+
+  /* Finally, it must be capable of being placed in a register.  */
+  return is_gimple_reg (t);
+}
+
+/* Return true if T is a GIMPLE variable whose address is not needed.  */
+
+bool
+is_gimple_non_addressable (tree t)
+{
+  if (TREE_CODE (t) == SSA_NAME)
+    t = SSA_NAME_VAR (t);
+
+  return (is_gimple_variable (t) && ! needs_to_live_in_memory (t));
+}
+
+/* Return true if T is a GIMPLE rvalue, i.e. an identifier or a constant.  */
+
+bool
+is_gimple_val (tree t)
+{
+  /* Make loads from volatiles and memory vars explicit.  */
+  if (is_gimple_variable (t)
+      && is_gimple_reg_type (TREE_TYPE (t))
+      && !is_gimple_reg (t))
+    return false;
+
+  /* FIXME make these decls.  That can happen only when we expose the
+     entire landing-pad construct at the tree level.  */
+  if (TREE_CODE (t) == EXC_PTR_EXPR || TREE_CODE (t) == FILTER_EXPR)
+    return true;
+
+  return (is_gimple_variable (t) || is_gimple_min_invariant (t));
+}
+
+/* Similarly, but accept hard registers as inputs to asm statements.  */
+
+bool
+is_gimple_asm_val (tree t)
+{
+  if (TREE_CODE (t) == VAR_DECL && DECL_HARD_REGISTER (t))
+    return true;
+
+  return is_gimple_val (t);
+}
+
+/* Return true if T is a GIMPLE minimal lvalue.  */
+
+bool
+is_gimple_min_lval (tree t)
+{
+  return (is_gimple_id (t) || TREE_CODE (t) == INDIRECT_REF);
+}
+
+/* Return true if T is a typecast operation.  */
+
+bool
+is_gimple_cast (tree t)
+{
+  return (CONVERT_EXPR_P (t)
+          || TREE_CODE (t) == FIX_TRUNC_EXPR);
+}
+
+/* Return true if T is a valid function operand of a CALL_EXPR.  */
+
+bool
+is_gimple_call_addr (tree t)
+{
+  return (TREE_CODE (t) == OBJ_TYPE_REF || is_gimple_val (t));
+}
+
+/* If T makes a function call, return the corresponding CALL_EXPR operand.
+   Otherwise, return NULL_TREE.  */
+
+tree
+get_call_expr_in (tree t)
+{
+  if (TREE_CODE (t) == MODIFY_EXPR)
+    t = TREE_OPERAND (t, 1);
+  if (TREE_CODE (t) == WITH_SIZE_EXPR)
+    t = TREE_OPERAND (t, 0);
+  if (TREE_CODE (t) == CALL_EXPR)
+    return t;
+  return NULL_TREE;
+}
+
+
+/* Given a memory reference expression T, return its base address.
+   The base address of a memory reference expression is the main
+   object being referenced.  For instance, the base address for
+   'array[i].fld[j]' is 'array'.  You can think of this as stripping
+   away the offset part from a memory address.
+
+   This function calls handled_component_p to strip away all the inner
+   parts of the memory reference until it reaches the base object.  */
+
+tree
+get_base_address (tree t)
+{
+  while (handled_component_p (t))
+    t = TREE_OPERAND (t, 0);
+  
+  if (SSA_VAR_P (t)
+      || TREE_CODE (t) == STRING_CST
+      || TREE_CODE (t) == CONSTRUCTOR
+      || INDIRECT_REF_P (t))
+    return t;
+  else
+    return NULL_TREE;
+}
+
+void
+recalculate_side_effects (tree t)
+{
+  enum tree_code code = TREE_CODE (t);
+  int len = TREE_OPERAND_LENGTH (t);
+  int i;
+
+  switch (TREE_CODE_CLASS (code))
+    {
+    case tcc_expression:
+      switch (code)
+	{
+	case INIT_EXPR:
+	case MODIFY_EXPR:
+	case VA_ARG_EXPR:
+	case PREDECREMENT_EXPR:
+	case PREINCREMENT_EXPR:
+	case POSTDECREMENT_EXPR:
+	case POSTINCREMENT_EXPR:
+	  /* All of these have side-effects, no matter what their
+	     operands are.  */
+	  return;
+
+	default:
+	  break;
+	}
+      /* Fall through.  */
+
+    case tcc_comparison:  /* a comparison expression */
+    case tcc_unary:       /* a unary arithmetic expression */
+    case tcc_binary:      /* a binary arithmetic expression */
+    case tcc_reference:   /* a reference */
+    case tcc_vl_exp:        /* a function call */
+      TREE_SIDE_EFFECTS (t) = TREE_THIS_VOLATILE (t);
+      for (i = 0; i < len; ++i)
+	{
+	  tree op = TREE_OPERAND (t, i);
+	  if (op && TREE_SIDE_EFFECTS (op))
+	    TREE_SIDE_EFFECTS (t) = 1;
+	}
+      break;
+
+    case tcc_constant:
+      /* No side-effects.  */
+      return;
+
+    default:
+      gcc_unreachable ();
+   }
+}
+
+/* Canonicalize a tree T for use in a COND_EXPR as conditional.  Returns
+   a canonicalized tree that is valid for a COND_EXPR or NULL_TREE, if
+   we failed to create one.  */
+
+tree
+canonicalize_cond_expr_cond (tree t)
+{
+  /* For (bool)x use x != 0.  */
+  if (TREE_CODE (t) == NOP_EXPR
+      && TREE_TYPE (t) == boolean_type_node)
+    {
+      tree top0 = TREE_OPERAND (t, 0);
+      t = build2 (NE_EXPR, TREE_TYPE (t),
+		  top0, build_int_cst (TREE_TYPE (top0), 0));
+    }
+  /* For !x use x == 0.  */
+  else if (TREE_CODE (t) == TRUTH_NOT_EXPR)
+    {
+      tree top0 = TREE_OPERAND (t, 0);
+      t = build2 (EQ_EXPR, TREE_TYPE (t),
+		  top0, build_int_cst (TREE_TYPE (top0), 0));
+    }
+  /* For cmp ? 1 : 0 use cmp.  */
+  else if (TREE_CODE (t) == COND_EXPR
+	   && COMPARISON_CLASS_P (TREE_OPERAND (t, 0))
+	   && integer_onep (TREE_OPERAND (t, 1))
+	   && integer_zerop (TREE_OPERAND (t, 2)))
+    {
+      tree top0 = TREE_OPERAND (t, 0);
+      t = build2 (TREE_CODE (top0), TREE_TYPE (t),
+		  TREE_OPERAND (top0, 0), TREE_OPERAND (top0, 1));
+    }
+
+  if (is_gimple_condexpr (t))
+    return t;
+
+  return NULL_TREE;
+}
+
+/* Build a GIMPLE_CALL identical to STMT but skipping the arguments in
+   the positions marked by the set ARGS_TO_SKIP.  */
+
+gimple
+gimple_call_copy_skip_args (gimple stmt, bitmap args_to_skip)
+{
+  int i;
+  tree fn = gimple_call_fn (stmt);
+  int nargs = gimple_call_num_args (stmt);
+  VEC(tree, heap) *vargs = VEC_alloc (tree, heap, nargs);
+  gimple new_stmt;
+
+  for (i = 0; i < nargs; i++)
+    if (!bitmap_bit_p (args_to_skip, i))
+      VEC_quick_push (tree, vargs, gimple_call_arg (stmt, i));
+
+  new_stmt = gimple_build_call_vec (fn, vargs);
+  VEC_free (tree, heap, vargs);
+  if (gimple_call_lhs (stmt))
+    gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt));
+
+  gimple_set_block (new_stmt, gimple_block (stmt));
+  if (gimple_has_location (stmt))
+    gimple_set_location (new_stmt, gimple_location (stmt));
+
+  /* Carry all the flags to the new GIMPLE_CALL.  */
+  gimple_call_set_chain (new_stmt, gimple_call_chain (stmt));
+  gimple_call_set_tail (new_stmt, gimple_call_tail_p (stmt));
+  gimple_call_set_cannot_inline (new_stmt, gimple_call_cannot_inline_p (stmt));
+  gimple_call_set_return_slot_opt (new_stmt, gimple_call_return_slot_opt_p (stmt));
+  gimple_call_set_from_thunk (new_stmt, gimple_call_from_thunk_p (stmt));
+  gimple_call_set_va_arg_pack (new_stmt, gimple_call_va_arg_pack_p (stmt));
+  return new_stmt;
+}
+
+#include "gt-gimple.h"