This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[tuples] Fix bootstrap C/Fortran and more C++ regressions



This patch fixes a memory corruption bug that was causing intermittent bootstrap problems. When a FUNCTION_DECL node is garbage collected, its entry in gimple_bodies_map is not removed because pointer_sets are not in GC memory. In some cases, a new FUNCTION_DECL would be later re-allocated at the same address, causing confusion when gimple_body() returned the same body for a different FUNCTION_DECL.


I will rework gimple_body() to use GC-friendly structures, but for now I have made make_node_stat clear gimple_body() for newly created FUNCTION_DECLs.

The patch also fixes gimplification of CALL_EXPRs to play nicely with return slot optimizations. The election of the LHS for the new GIMPLE_CALL is left to gimplify_modify_expr.

The Fortran front end can now be bootstrapped as well. I will update the wiki to include it in the patch test requirements.

Bootstrapped C and Fortran on x86.


Diego.
2008-04-21  Diego Novillo  <dnovillo@google.com>

	* tree.c (make_node_stat): Clear gimple_body() for newly
	created FUNCTION_DECLs.
	* tree-gimple.c (rhs_predicate_for): Move to gimplify.c.
	* tree-gimple.h (rhs_predicate_for): Remove declaration.
	* gimple-pretty-print.c (dump_gimple_assign): Add support
	for showing volatile operands.
	(dump_gimple_call): Likewise.
	Add support for showing __builtin_va_arg_pack, static
	chains, return slot optimized and tail calls.
	(dump_gimple_phi): Remove code to print memory symbols.
	* gimplify.c (is_gimple_formal_tmp_or_call_rhs): New.
	(is_gimple_mem_or_call_rhs): New.
	(rhs_predicate_for): Call them.
	(internal_get_tmp_var): Use is_gimple_formal_tmp_or_call_rhs as
	the gimplification predicate.
	Use the last statement in *PRE_P to get the temporary to
	be updated when in SSA form.
	(gimplify_bind_expr): Clear out *EXPR_P before returning.
	(gimplify_call_expr): Do not build a GIMPLE_CALL if
	WANT_VALUE is true.
	Call gimple_build_call_from_tree if WANT_VALUE is false.
	Remove local variable ARGS.
	(gimplify_modify_expr): If after gimplification *FROM_P
	is a CALL_EXPR, create a GIMPLE_CALL instead of a
	GIMPLE_ASSIGN.
	Document why the gimplification of the RHS should accept
	CALL_EXPRs.
	(gimplify_expr): Document where the generated statement
	is stored.
	Accept is_gimple_formal_tmp_or_call_rhs and
	is_gimple_mem_or_call_rhs as gimplification predicates.
	When gimplifying statements, clear out *EXPR_P before
	returning.
	When generating an rvalue, call is_gimple_formal_tmp_or_call_rhs
	to test *EXPR_P.
	* tree-dfa.c (mark_symbols_for_renaming): Remove
	ATTRIBUTE_UNUSED.
	* tree-flow.h (stmt_references_memory_p): Remove.
	* gimple.c (gimple_build_call_from_tree): New.
	* gimple.h (struct gimple_statement_with_memory_ops): Add
	bitfield references_memory_p.
	(gimple_build_call_from_tree): Declare.
	(gimple_references_memory_p): Rename from
	stmt_references_memory_p.  Move here.  Update all users.
	(gimple_set_references_memory): New.
	(gimple_assign_set_rhs1): When the assignment has more
	than one operand on the RHS, assert that the operands are
	gimple values.
	(gimple_assign_set_rhs2): Assert that the operand is a
	gimple value.
	(gimple_call_set_return_slot_opt): Fix mask clearing.
	(gimple_call_set_from_thunk): Likewise.
	(gimple_call_set_va_arg_pack): Likewise.
	* tree-cfg.c (dump_function_to_file): Do not indent when
	doing a GIMPLE dump.
	* tree-ssa-operands.c (add_virtual_operand): Call
	gimple_set_references_memory.
	(get_addr_dereference_operands): Likewise.
	(get_tmr_operands): Likewise.
	(maybe_add_call_clobbered_vops): Likewise.
	(get_asm_expr_operands): Likewise.
	(parse_ssa_operands): Likewise.
	(build_ssa_operands): Likewise.
	(stmt_references_memory_p): Remove.

Index: tree-ssa-loop-im.c
===================================================================
--- tree-ssa-loop-im.c	(revision 134468)
+++ tree-ssa-loop-im.c	(working copy)
@@ -515,7 +515,7 @@ stmt_cost (gimple stmt)
     return LIM_EXPENSIVE;
 
   /* Hoisting memory references out should almost surely be a win.  */
-  if (stmt_references_memory_p (stmt))
+  if (gimple_references_memory_p (stmt))
     cost += 20;
 
   if (gimple_code (stmt) == GIMPLE_CALL)
Index: tree-ssa-loop-niter.c
===================================================================
--- tree-ssa-loop-niter.c	(revision 134468)
+++ tree-ssa-loop-niter.c	(working copy)
@@ -1971,10 +1971,10 @@ chain_of_csts_start (struct loop *loop, 
     return NULL;
 
   code = gimple_assign_rhs_code (stmt);
-  if (stmt_references_memory_p (stmt)
+  if (gimple_references_memory_p (stmt)
       /* Before alias information is computed, operand scanning marks
 	 statements that write memory volatile.  However, the statements
-	 that only read memory are not marked, thus stmt_references_memory_p
+	 that only read memory are not marked, thus gimple_references_memory_p
 	 returns false for them.  */
       || TREE_CODE_CLASS (code) == tcc_reference
       || TREE_CODE_CLASS (code) == tcc_declaration
Index: tree-tailcall.c
===================================================================
--- tree-tailcall.c	(revision 134468)
+++ tree-tailcall.c	(working copy)
@@ -410,7 +410,7 @@ find_tail_calls (basic_block bb, struct 
       if (!ZERO_SSA_OPERANDS (stmt, (SSA_OP_VUSE | SSA_OP_VIRTUAL_DEFS))
 	  || gimple_has_volatile_ops (stmt)
 	  || (!gimple_aliases_computed_p (cfun)
-	      && stmt_references_memory_p (stmt)))
+	      && gimple_references_memory_p (stmt)))
 	return;
     }
 
Index: tree.c
===================================================================
--- tree.c	(revision 134468)
+++ tree.c	(working copy)
@@ -582,6 +582,7 @@ make_node_stat (enum tree_code code MEM_
 	    {
 	      DECL_ALIGN (t) = FUNCTION_BOUNDARY;
 	      DECL_MODE (t) = FUNCTION_MODE;
+	      gimple_set_body (t, NULL);
 	    }
 	  else
 	    DECL_ALIGN (t) = 1;
Index: tree-gimple.c
===================================================================
--- tree-gimple.c	(revision 134468)
+++ tree-gimple.c	(working copy)
@@ -187,19 +187,6 @@ is_gimple_mem_rhs (tree t)
     return is_gimple_formal_tmp_rhs (t);
 }
 
-/* Returns the appropriate RHS predicate for this LHS.  */
-
-gimple_predicate
-rhs_predicate_for (tree lhs)
-{
-  if (is_gimple_formal_tmp_var (lhs))
-    return is_gimple_formal_tmp_rhs;
-  else if (is_gimple_reg (lhs))
-    return is_gimple_reg_rhs;
-  else
-    return is_gimple_mem_rhs;
-}
-
 /*  Return true if T is a valid LHS for a GIMPLE assignment expression.  */
 
 bool
Index: tree-gimple.h
===================================================================
--- tree-gimple.h	(revision 134468)
+++ tree-gimple.h	(working copy)
@@ -49,7 +49,6 @@ extern void annotate_all_with_location (
 /* Validation of GIMPLE expressions.  Note that these predicates only check
    the basic form of the expression, they don't recurse to make sure that
    underlying nodes are also of the right form.  */
-
 typedef bool (*gimple_predicate)(tree);
 
 /* In tree-gimple.c  */
@@ -92,9 +91,6 @@ extern bool is_gimple_asm_val (tree);
 extern bool is_gimple_formal_tmp_rhs (tree);
 extern bool is_gimple_reg_rhs (tree);
 extern bool is_gimple_mem_rhs (tree);
-/* Returns the appropriate one of the above three predicates for the LHS
-   T.  */
-extern gimple_predicate rhs_predicate_for (tree);
 
 /* Returns true iff T is a valid if-statement condition.  */
 extern bool is_gimple_condexpr (tree);
Index: tree-ssa-dom.c
===================================================================
--- tree-ssa-dom.c	(revision 134468)
+++ tree-ssa-dom.c	(working copy)
@@ -1997,7 +1997,7 @@ record_equivalences_from_stmt (gimple st
      vops and recording the result in the available expression table,
      we may be able to expose more redundant loads.  */
   if (!gimple_has_volatile_ops (stmt)
-      && stmt_references_memory_p (stmt)
+      && gimple_references_memory_p (stmt)
       && gimple_assign_single_p (stmt)
       && (TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME
 	  || is_gimple_min_invariant (gimple_assign_rhs1 (stmt)))
Index: tree-ssa-alias.c
===================================================================
--- tree-ssa-alias.c	(revision 134468)
+++ tree-ssa-alias.c	(working copy)
@@ -768,7 +768,7 @@ count_mem_refs (long *num_vuses_p, long 
       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
 	{
 	  gimple stmt = gsi_stmt (gsi);
-	  if (stmt_references_memory_p (stmt))
+	  if (gimple_references_memory_p (stmt))
 	    {
 	      num_vuses += NUM_SSA_OPERANDS (stmt, SSA_OP_VUSE);
 	      num_vdefs += NUM_SSA_OPERANDS (stmt, SSA_OP_VDEF);
Index: gimple-pretty-print.c
===================================================================
--- gimple-pretty-print.c	(revision 134468)
+++ gimple-pretty-print.c	(working copy)
@@ -329,8 +329,13 @@ dump_gimple_assign (pretty_printer *buff
       dump_generic_node (buffer, gimple_assign_lhs (gs), spc, flags, false);
       pp_space (buffer);
       pp_character (buffer, '=');
+
       if (gimple_assign_nontemporal_move_p (gs))
 	pp_string (buffer, "{nt}");
+
+      if (gimple_has_volatile_ops (gs))
+	pp_string (buffer, "{v}");
+
       pp_space (buffer);
 
       if (gimple_num_ops (gs) == 2)
@@ -370,12 +375,24 @@ static void
 dump_gimple_call_args (pretty_printer *buffer, gimple gs, int flags)
 {
   size_t i;
+
   for (i = 0; i < gimple_call_num_args (gs); i++)
     {
       dump_generic_node (buffer, gimple_call_arg (gs, i), 0, flags, false);
       if (i < gimple_call_num_args (gs) - 1)
 	pp_string (buffer, ", ");
     }
+
+  if (gimple_call_va_arg_pack_p (gs))
+    {
+      if (gimple_call_num_args (gs) > 0)
+        {
+          pp_character (buffer, ',');
+          pp_space (buffer);
+        }
+
+      pp_string (buffer, "__builtin_va_arg_pack ()");
+    }
 }
 
 
@@ -403,13 +420,31 @@ dump_gimple_call (pretty_printer *buffer
       if (lhs)
         {
           dump_generic_node (buffer, lhs, spc, flags, false);
-          pp_string (buffer, " = ");
+          pp_string (buffer, " =");
+
+	  if (gimple_has_volatile_ops (gs))
+	    pp_string (buffer, "{v}");
+
+	  pp_space (buffer);
         }
       dump_generic_node (buffer, gimple_call_fn (gs), spc, flags, false);
       pp_string (buffer, " (");
       dump_gimple_call_args (buffer, gs, flags);
       pp_string (buffer, ")");
     }
+
+  if (gimple_call_chain (gs))
+    {
+      pp_string (buffer, " [static-chain: ");
+      dump_generic_node (buffer, gimple_call_chain (gs), spc, flags, false);
+      pp_character (buffer, ']');
+    }
+
+  if (gimple_call_return_slot_opt_p (gs))
+    pp_string (buffer, " [return slot optimization]");
+
+  if (gimple_call_tail_p (gs))
+    pp_string (buffer, " [tail call]");
 }
 
 
@@ -431,6 +466,7 @@ dump_gimple_switch (pretty_printer *buff
       dump_generic_node (buffer, gimple_switch_index (gs), spc, flags, true);
       pp_string (buffer, ") <");
     }
+
   for (i = 0; i < gimple_switch_num_labels (gs); i++)
     {
       tree case_label = gimple_switch_label (gs, i);
@@ -884,9 +920,6 @@ dump_gimple_phi (pretty_printer *buffer,
 	pp_string (buffer, ", ");
     }
   pp_string (buffer, ">");
-
-  if (stmt_references_memory_p (phi) && (flags & TDF_MEMSYMS))
-    dump_symbols (buffer, gimple_stored_syms (phi), flags);
 }
 
 
@@ -1000,7 +1033,7 @@ dump_gimple_mem_ops (pretty_printer *buf
   struct voptype_d *vuses;
   int i, n;
 
-  if (!ssa_operands_active () || !stmt_references_memory_p (gs))
+  if (!ssa_operands_active () || !gimple_references_memory_p (gs))
     return;
 
   /* Even if the statement doesn't have virtual operators yet, it may
Index: gimplify.c
===================================================================
--- gimplify.c	(revision 134468)
+++ gimplify.c	(working copy)
@@ -605,6 +605,40 @@ lookup_tmp_var (tree val, bool is_formal
   return ret;
 }
 
+
+/* Return true if T is a CALL_EXPR or an expression that can be
+   assignmed to a temporary.  Note that this predicate should only be
+   used during gimplification.  See the rationale for this in
+   gimplify_modify_expr.  */
+
+static bool
+is_gimple_formal_tmp_or_call_rhs (tree t)
+{
+  return TREE_CODE (t) == CALL_EXPR || is_gimple_formal_tmp_rhs (t);
+}
+
+
+/* Return true if T is a valid memory RHS or a CALL_EXPR.  Note that
+   this predicate should only be used during gimplification.  See the
+   rationale for this in gimplify_modify_expr.  */
+
+static bool
+is_gimple_mem_or_call_rhs (tree t)
+{
+  /* If we're dealing with a renamable type, either source or dest must be
+     a renamed variable.  Also force a temporary if the type doesn't need
+     to be stored in memory, since it's cheap and prevents erroneous
+     tailcalls (PR 17526).  */
+  if (is_gimple_reg_type (TREE_TYPE (t))
+      || (TYPE_MODE (TREE_TYPE (t)) != BLKmode
+	  && (TREE_CODE (t) != CALL_EXPR
+              || ! aggregate_value_p (t, t))))
+    return is_gimple_val (t);
+  else
+    return is_gimple_formal_tmp_or_call_rhs (t);
+}
+
+
 /* Returns a formal temporary variable initialized with VAL.  PRE_P is as
    in gimplify_expr.  Only use this function if:
 
@@ -623,7 +657,10 @@ internal_get_tmp_var (tree val, gimple_s
 {
   tree t, mod;
 
-  gimplify_expr (&val, pre_p, post_p, is_gimple_formal_tmp_rhs, fb_rvalue);
+  /* Notice that we explicitly allow VAL to be a CALL_EXPR so that we
+     can create an INIT_EXPR and convert it into a GIMPLE_CALL below.  */
+  gimplify_expr (&val, pre_p, post_p, is_gimple_formal_tmp_or_call_rhs,
+		 fb_rvalue);
 
   t = lookup_tmp_var (val, is_formal);
 
@@ -660,9 +697,12 @@ internal_get_tmp_var (tree val, gimple_s
   gimplify_and_add (mod, pre_p);
 
   /* If we're gimplifying into ssa, gimplify_modify_expr will have
-     given our temporary an ssa name.  Find and return it.  */
+     given our temporary an SSA name.  Find and return it.  */
   if (gimplify_ctxp->into_ssa)
-    t = TREE_OPERAND (mod, 0);
+    {
+      gimple last = gimple_seq_last_stmt (*pre_p);
+      t = gimple_get_lhs (last);
+    }
 
   return t;
 }
@@ -1189,8 +1229,9 @@ gimplify_bind_expr (tree *expr_p, gimple
       *expr_p = temp;
       return GS_OK;
     }
-  else
-    return GS_ALL_DONE;
+
+  *expr_p = NULL_TREE;
+  return GS_ALL_DONE;
 }
 
 /* Gimplify a RETURN_EXPR.  If the expression to be returned is not a
@@ -2161,7 +2202,6 @@ gimplify_call_expr (tree *expr_p, gimple
   tree fndecl, parms, p;
   enum gimplify_status ret;
   int i, nargs;
-  VEC(tree, heap) *args = NULL;
   gimple call;
   bool builtin_va_start_p = FALSE;
 
@@ -2304,6 +2344,7 @@ gimplify_call_expr (tree *expr_p, gimple
 	  --nargs;
 	  *expr_p = build_call_array (TREE_TYPE (call), CALL_EXPR_FN (call),
 				      nargs, CALL_EXPR_ARGP (call));
+
 	  /* Copy all CALL_EXPR flags, location and block, except
 	     CALL_EXPR_VA_ARG_PACK flag.  */
 	  CALL_EXPR_STATIC_CHAIN (*expr_p) = CALL_EXPR_STATIC_CHAIN (call);
@@ -2314,6 +2355,7 @@ gimplify_call_expr (tree *expr_p, gimple
 	  CALL_CANNOT_INLINE_P (*expr_p) = CALL_CANNOT_INLINE_P (call);
 	  SET_EXPR_LOCUS (*expr_p, EXPR_LOCUS (call));
 	  TREE_BLOCK (*expr_p) = TREE_BLOCK (call);
+
 	  /* Set CALL_EXPR_VA_ARG_PACK.  */
 	  CALL_EXPR_VA_ARG_PACK (*expr_p) = 1;
 	}
@@ -2322,27 +2364,22 @@ gimplify_call_expr (tree *expr_p, gimple
   /* Finally, gimplify the function arguments.  */
   if (nargs > 0)
     {
-      args = VEC_alloc (tree, heap, nargs);
-      VEC_safe_grow (tree, heap, args, nargs);
-
-    for (i = (PUSH_ARGS_REVERSED ? nargs - 1 : 0);
-	 PUSH_ARGS_REVERSED ? i >= 0 : i < nargs;
-	 PUSH_ARGS_REVERSED ? i-- : i++)
-      {
-	enum gimplify_status t;
-
-	/* Avoid gimplifying the second argument to va_start, which needs
-           to be the plain PARM_DECL.  */
-        if ((i != 1) || !builtin_va_start_p)
-	  {
-	    t = gimplify_arg (&CALL_EXPR_ARG (*expr_p, i), pre_p);
+      for (i = (PUSH_ARGS_REVERSED ? nargs - 1 : 0);
+           PUSH_ARGS_REVERSED ? i >= 0 : i < nargs;
+           PUSH_ARGS_REVERSED ? i-- : i++)
+        {
+          enum gimplify_status t;
 
-	    if (t == GS_ERROR)
-	      ret = GS_ERROR;
-	  }
+          /* Avoid gimplifying the second argument to va_start, which needs to
+             be the plain PARM_DECL.  */
+          if ((i != 1) || !builtin_va_start_p)
+            {
+              t = gimplify_arg (&CALL_EXPR_ARG (*expr_p, i), pre_p);
 
-	VEC_replace (tree, args, i, CALL_EXPR_ARG (*expr_p, i));
-      }
+              if (t == GS_ERROR)
+                ret = GS_ERROR;
+            }
+        }
     }
 
   /* Try this again in case gimplification exposed something.  */
@@ -2365,40 +2402,22 @@ gimplify_call_expr (tree *expr_p, gimple
       return GS_ERROR;
     }
 
-  /* Now add the GIMPLE call to PRE_P.  If WANT_VALUE is set, we need
-     to create the appropriate temporary for the call's LHS.  */
-  call = gimple_build_call_vec (fndecl ? fndecl : CALL_EXPR_FN (*expr_p), args);
-  gimple_set_block (call, TREE_BLOCK (*expr_p));
-  VEC_free (tree, heap, args);
-
-  /* Carry all the CALL_EXPR flags to the new GIMPLE_CALL.  */
-  gimple_call_set_chain (call, CALL_EXPR_STATIC_CHAIN (*expr_p));
-  gimple_call_set_tail (call, CALL_EXPR_TAILCALL (*expr_p));
-  gimple_call_set_cannot_inline (call, CALL_CANNOT_INLINE_P (*expr_p));
-  gimple_call_set_return_slot_opt (call, CALL_EXPR_RETURN_SLOT_OPT (*expr_p));
-  gimple_call_set_from_thunk (call, CALL_FROM_THUNK_P (*expr_p));
-  gimple_call_set_va_arg_pack (call, CALL_EXPR_VA_ARG_PACK (*expr_p));
-
-  gimplify_seq_add_stmt (pre_p, call);
-  if (want_value)
+  /* If the value is not needed by the caller, emit a new GIMPLE_CALL
+     and clear *EXPR_P.  Otherwise, leave *EXPR_P in its gimplified
+     form and delegate the creation of a GIMPLE_CALL to
+     gimplify_modify_expr.  This is always possible because when
+     WANT_VALUE is true, the caller wants the result of this call into
+     a temporary, which means that we will emit an INIT_EXPR in
+     internal_get_tmp_var which will then be handled by
+     gimplify_modify_expr.  */
+  if (!want_value)
     {
-      /* FIXME tuples: we want to use internal_get_tmp_var here,
-         but can't because it wants a value that it gimplifies and the new
-         call is not a tree expression.  internal_get_tmp_var needs to be
-         rewritten to support this and still use the formal temporary table.
-         */
-      tree lhs = create_tmp_var (gimple_call_return_type (call),
-                                 get_name (gimple_call_fn (call)));
-      gimple_call_set_lhs (call, lhs);
-
-      if (TREE_CODE (gimple_call_return_type (call)) == COMPLEX_TYPE
-          || TREE_CODE (gimple_call_return_type (call)) == VECTOR_TYPE)
-        DECL_GIMPLE_REG_P (lhs) = 1;
-
-      *expr_p = lhs;
+      /* The CALL_EXPR in *EXPR_P is already in GIMPLE form, so all we
+	 have to do is replicate it as a GIMPLE_CALL tuple.  */
+      call = gimple_build_call_from_tree (*expr_p);
+      gimplify_seq_add_stmt (pre_p, call);
+      *expr_p = NULL_TREE;
     }
-  else
-    *expr_p = NULL_TREE;
 
   return ret;
 }
@@ -3060,7 +3079,7 @@ gimplify_init_ctor_preeval (tree *expr_p
   maybe_with_size_expr (expr_p);
 
   /* Gimplify the constructor element to something appropriate for the rhs
-     of a MODIFY_EXPR.  Given that we know the lhs is an aggregate, we know
+     of a MODIFY_EXPR.  Given that we know the LHS is an aggregate, we know
      the gimplifier will consider this a store to memory.  Doing this
      gimplification now means that we won't have to deal with complicated
      language-specific trees, nor trees like SAVE_EXPR that can induce
@@ -3272,6 +3291,21 @@ gimplify_init_ctor_eval (tree object, VE
     }
 }
 
+
+/* Returns the appropriate RHS predicate for this LHS.  */
+
+static gimple_predicate
+rhs_predicate_for (tree lhs)
+{
+  if (is_gimple_formal_tmp_var (lhs))
+    return is_gimple_formal_tmp_or_call_rhs;
+  else if (is_gimple_reg (lhs))
+    return is_gimple_reg_rhs;
+  else
+    return is_gimple_mem_or_call_rhs;
+}
+
+
 /* A subroutine of gimplify_modify_expr.  Break out elements of a
    CONSTRUCTOR used as an initializer into separate MODIFY_EXPRs.
 
@@ -3956,6 +3990,7 @@ gimplify_modify_expr_complex_part (tree 
   return GS_ALL_DONE;
 }
 
+
 /* Gimplify the MODIFY_EXPR node pointed to by EXPR_P.
 
       modify_expr
@@ -4018,13 +4053,25 @@ gimplify_modify_expr (tree *expr_p, gimp
      before gimplifying any of the operands so that we can resolve any
      PLACEHOLDER_EXPRs in the size.  Also note that the RTL expander uses
      the size of the expression to be copied, not of the destination, so
-     that is what we must here.  */
+     that is what we must do here.  */
   maybe_with_size_expr (from_p);
 
   ret = gimplify_expr (to_p, pre_p, post_p, is_gimple_lvalue, fb_lvalue);
   if (ret == GS_ERROR)
     return ret;
 
+  /* As a special case, we have to temporarily allow for assignments
+     with a CALL_EXPR on the RHS.  Since in GIMPLE a function call is
+     a toplevel statement, when gimplifying the GENERIC expression
+     MODIFY_EXPR <a, CALL_EXPR <foo>>, we cannot create the tuple
+     GIMPLE_ASSIGN <a, GIMPLE_CALL <foo>>.
+
+     Instead, we need to create the tuple GIMPLE_CALL <a, foo>.  To
+     prevent gimplify_expr from trying to create a new temporary for
+     foo's LHS, we tell it that it should only gimplify until it
+     reaches the CALL_EXPR.  On return from gimplify_expr, the newly
+     created GIMPLE_CALL <foo> will be the last statement in *PRE_P
+     and all we need to do here is set 'a' to be its LHS.  */
   ret = gimplify_expr (from_p, pre_p, post_p, rhs_predicate_for (*to_p),
 		       fb_rvalue);
   if (ret == GS_ERROR)
@@ -4046,6 +4093,7 @@ gimplify_modify_expr (tree *expr_p, gimp
 
       if (TREE_CODE (from) == CONSTRUCTOR)
 	return gimplify_modify_expr_to_memset (expr_p, size, want_value, pre_p);
+
       if (is_gimple_addressable (from))
 	{
 	  *from_p = from;
@@ -4075,18 +4123,29 @@ gimplify_modify_expr (tree *expr_p, gimp
 	  = create_tmp_var_name (IDENTIFIER_POINTER (DECL_NAME (*to_p)));
       DECL_DEBUG_EXPR_IS_FROM (*from_p) = 1;
       SET_DECL_DEBUG_EXPR (*from_p, *to_p);
+   }
+
+  /* FIXME tuples.  Are the calls to unshare_expr really necessary
+     here? */
+  if (TREE_CODE (*from_p) == CALL_EXPR)
+    {
+      /* Since the RHS is a CALL_EXPR, we need to create a GIMPLE_CALL
+	 instead of a GIMPLE_ASSIGN.  */
+      assign = gimple_build_call_from_tree (*from_p);
+      gimple_call_set_lhs (assign, unshare_expr (*to_p));
     }
+  else
+    assign = gimple_build_assign (unshare_expr (*to_p), unshare_expr (*from_p));
 
-  assign = gimple_build_assign (unshare_expr (*to_p), unshare_expr (*from_p));
   gimplify_seq_add_stmt (pre_p, assign);
 
   if (gimplify_ctxp->into_ssa && is_gimple_reg (*to_p))
     {
       /* If we've somehow already got an SSA_NAME on the LHS, then
-	 we're probably modified it twice.  Not good.  */
+	 we've probably modified it twice.  Not good.  */
       gcc_assert (TREE_CODE (*to_p) != SSA_NAME);
       *to_p = make_ssa_name (*to_p, assign);
-      gimple_assign_set_lhs (assign, *to_p);
+      gimple_set_lhs (assign, *to_p);
     }
 
   if (want_value)
@@ -5727,7 +5786,11 @@ gimplify_omp_atomic (tree *expr_p, gimpl
 
    PRE_P will contain the sequence of GIMPLE statements corresponding
        to the evaluation of EXPR and all the side-effects that must
-       be executed before the main expression.
+       be executed before the main expression.  On exit, the last
+       statement of PRE_P is the core statement being gimplified.  For
+       instance, when gimplifying 'if (++a)' the last statement in
+       PRE_P will be 'if (t.1)' where t.1 is the result of
+       pre-incrementing 'a'.
 
    POST_P will contain the sequence of GIMPLE statements corresponding
        to the evaluation of all the side-effects that must be executed
@@ -5809,11 +5872,13 @@ gimplify_expr (tree *expr_p, gimple_seq 
   if (gimple_test_f == is_gimple_val
       || gimple_test_f == is_gimple_reg
       || gimple_test_f == is_gimple_formal_tmp_rhs
+      || gimple_test_f == is_gimple_formal_tmp_or_call_rhs
       || gimple_test_f == is_gimple_formal_tmp_reg
       || gimple_test_f == is_gimple_formal_tmp_var
       || gimple_test_f == is_gimple_call_addr
       || gimple_test_f == is_gimple_condexpr
       || gimple_test_f == is_gimple_mem_rhs
+      || gimple_test_f == is_gimple_mem_or_call_rhs
       || gimple_test_f == is_gimple_reg_rhs
       || gimple_test_f == is_gimple_asm_val)
     gcc_assert (fallback & fb_rvalue);
@@ -6520,6 +6585,10 @@ gimplify_expr (tree *expr_p, gimple_seq 
      everything together and return.  */
   if (fallback == fb_none || is_statement)
     {
+      /* Since *EXPR_P has been converted into a GIMPLE tuple, clear
+         it out for GC to reclaim it.  */
+      *expr_p = NULL_TREE;
+
       if (!gimple_seq_empty_p (internal_pre)
 	  || !gimple_seq_empty_p (internal_post))
 	{
@@ -6562,12 +6631,11 @@ gimplify_expr (tree *expr_p, gimple_seq 
     }
 #endif
 
-  /* Otherwise we're gimplifying a subexpression, so the resulting value is
-     interesting.  */
-
-  /* If it's sufficiently simple already, we're done.  Unless we are
-     handling some post-effects internally; if that's the case, we need to
-     copy into a temp before adding the post-effects to the tree.  */
+  /* Otherwise we're gimplifying a subexpression, so the resulting
+     value is interesting.  If it's a valid operand that matches
+     GIMPLE_TEST_F, we're done. Unless we are handling some
+     post-effects internally; if that's the case, we need to copy into
+     a temporary before adding the post-effects to POST_P.  */
   if (gimple_seq_empty_p (internal_post) && (*gimple_test_f) (*expr_p))
     goto out;
 
@@ -6589,7 +6657,7 @@ gimplify_expr (tree *expr_p, gimple_seq 
       gimplify_expr (&tmp, pre_p, post_p, is_gimple_reg, fb_rvalue);
       *expr_p = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (tmp)), tmp);
     }
-  else if ((fallback & fb_rvalue) && is_gimple_formal_tmp_rhs (*expr_p))
+  else if ((fallback & fb_rvalue) && is_gimple_formal_tmp_or_call_rhs (*expr_p))
     {
       /* An rvalue will do.  Assign the gimplified expression into a
 	 new temporary TMP and replace the original expression with
Index: tree-dfa.c
===================================================================
--- tree-dfa.c	(revision 134468)
+++ tree-dfa.c	(working copy)
@@ -763,7 +763,7 @@ get_virtual_var (tree var)
    combination push_stmt_changes/pop_stmt_changes.  */
 
 void
-mark_symbols_for_renaming (gimple stmt ATTRIBUTE_UNUSED)
+mark_symbols_for_renaming (gimple stmt)
 {
   tree op;
   ssa_op_iter iter;
Index: tree-flow.h
===================================================================
--- tree-flow.h	(revision 134468)
+++ tree-flow.h	(working copy)
@@ -872,7 +872,6 @@ extern bool types_compatible_p (tree, tr
 extern void verify_ssa (bool);
 extern void delete_tree_ssa (void);
 extern void walk_use_def_chains (tree, walk_use_def_chains_fn, void *, bool);
-extern bool stmt_references_memory_p (gimple);
 extern bool ssa_undefined_value_p (tree);
 
 
Index: gimple.c
===================================================================
--- gimple.c	(revision 134468)
+++ gimple.c	(working copy)
@@ -253,9 +253,9 @@ gimple_build_return (tree retval)
   return s;
 }
 
-/* Helper for gimple_build_call and gimple_build_call_vec.  Build the basic
-   components of a GIMPLE_CALL statement to function FN with NARGS
-   arguments.  */
+/* 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, size_t nargs)
@@ -306,6 +306,39 @@ gimple_build_call (tree fn, size_t nargs
 }
 
 
+/* 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)
+{
+  size_t 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.  */
 
@@ -392,7 +425,7 @@ gimple_build_assign_with_ops (enum tree_
 
    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 teh label to jump to otherwise.  */
+   F_LABEL is the label to jump to otherwise.  */
 
 gimple
 gimple_build_cond (enum tree_code pred_code, tree lhs, tree rhs,
Index: tree-ssa-structalias.c
===================================================================
--- tree-ssa-structalias.c	(revision 134468)
+++ tree-ssa-structalias.c	(working copy)
@@ -3405,7 +3405,7 @@ update_alias_info (gimple stmt, struct a
 
   /* Mark stored variables in STMT as being written to and update the
      memory reference stats for all memory symbols referenced by STMT.  */
-  if (stmt_references_memory_p (stmt))
+  if (gimple_references_memory_p (stmt))
     {
       unsigned i;
       bitmap_iterator bi;
Index: gimple.h
===================================================================
--- gimple.h	(revision 134468)
+++ gimple.h	(working copy)
@@ -301,6 +301,7 @@ struct gimple_statement_with_memory_ops 
 {
   struct gimple_statement_with_ops with_ops;
   unsigned has_volatile_ops : 1;
+  unsigned references_memory_p : 1;
   struct voptype_d GTY((skip (""))) *vdef_ops;
   struct voptype_d GTY((skip (""))) *vuse_ops;
   bitmap GTY((skip (""))) stores;
@@ -591,6 +592,7 @@ void extract_ops_from_tree (tree, enum t
 gimple gimple_build_assign_with_ops (enum tree_code, tree, tree, tree);
 gimple gimple_build_call_vec (tree, VEC(tree, heap) *);
 gimple gimple_build_call (tree, size_t, ...);
+gimple gimple_build_call_from_tree (tree);
 gimple gimple_build_cond (enum tree_code, tree, tree, tree, tree);
 gimple gimple_build_label (tree label);
 gimple gimple_build_goto (tree dest);
@@ -1055,6 +1057,25 @@ gimple_set_has_volatile_ops (gimple stmt
 }
 
 
+/* Return true if statement STMT may access memory.  */
+
+static inline bool
+gimple_references_memory_p (gimple stmt)
+{
+  return gimple_has_mem_ops (stmt) && stmt->with_mem_ops.references_memory_p;
+}
+
+
+/* Set the REFERENCES_MEMORY_P flag for STMT to MEM_P.  */
+
+static inline void
+gimple_set_references_memory (gimple stmt, bool mem_p)
+{
+  if (gimple_has_mem_ops (stmt))
+    stmt->with_mem_ops.references_memory_p = (unsigned) mem_p;
+}
+
+
 /* Set the nowait flag on OMP_RETURN statement S.  */
 
 static inline void
@@ -1255,7 +1276,14 @@ static inline void
 gimple_assign_set_rhs1 (gimple gs, tree rhs)
 {
   GIMPLE_CHECK (gs, GIMPLE_ASSIGN);
-  gcc_assert (is_gimple_operand (rhs));
+
+  /* If there are 3 or more operands, the 2 operands on the RHS must be
+     GIMPLE values.  */
+  if (gimple_num_ops (gs) >= 3)
+    gcc_assert (is_gimple_val (rhs));
+  else
+    gcc_assert (is_gimple_operand (rhs));
+
   gimple_set_op (gs, 1, rhs);
 }
 
@@ -1292,7 +1320,10 @@ static inline void
 gimple_assign_set_rhs2 (gimple gs, tree rhs)
 {
   GIMPLE_CHECK (gs, GIMPLE_ASSIGN);
-  gcc_assert (is_gimple_operand (rhs));
+
+  /* The 2 operands on the RHS must be GIMPLE values.  */
+  gcc_assert (is_gimple_val (rhs));
+
   gimple_set_op (gs, 2, rhs);
 }
 
@@ -1565,7 +1596,7 @@ gimple_call_set_return_slot_opt (gimple 
   if (return_slot_opt_p)
     s->gsbase.subcode |= GF_CALL_RETURN_SLOT_OPT;
   else
-    s->gsbase.subcode &= GF_CALL_RETURN_SLOT_OPT;
+    s->gsbase.subcode &= ~GF_CALL_RETURN_SLOT_OPT;
 }
 
 
@@ -1589,7 +1620,7 @@ gimple_call_set_from_thunk (gimple s, bo
   if (from_thunk_p)
     s->gsbase.subcode |= GF_CALL_FROM_THUNK;
   else
-    s->gsbase.subcode &= GF_CALL_FROM_THUNK;
+    s->gsbase.subcode &= ~GF_CALL_FROM_THUNK;
 }
 
 
@@ -1613,7 +1644,7 @@ gimple_call_set_va_arg_pack (gimple s, b
   if (pass_arg_pack_p)
     s->gsbase.subcode |= GF_CALL_VA_ARG_PACK;
   else
-    s->gsbase.subcode &= GF_CALL_VA_ARG_PACK;
+    s->gsbase.subcode &= ~GF_CALL_VA_ARG_PACK;
 }
 
 
Index: tree-cfg.c
===================================================================
--- tree-cfg.c	(revision 134468)
+++ tree-cfg.c	(working copy)
@@ -5896,7 +5896,7 @@ dump_function_to_file (tree fn, FILE *fi
       /* The function is now in GIMPLE form but the CFG has not been
 	 built yet.  Emit the single sequence of GIMPLE statements
 	 that make up its body.  */
-      print_gimple_seq (file, gimple_body (fn), 2, flags);
+      print_gimple_seq (file, gimple_body (fn), 0, flags);
     }
   else
     {
Index: tree-ssa-operands.c
===================================================================
--- tree-ssa-operands.c	(revision 134468)
+++ tree-ssa-operands.c	(working copy)
@@ -1457,6 +1457,9 @@ add_virtual_operand (tree var, gimple st
   sym = (TREE_CODE (var) == SSA_NAME ? SSA_NAME_VAR (var) : var);
   v_ann = var_ann (sym);
   
+  /* Mark the statement as having memory operands.  */
+  gimple_set_references_memory (stmt, true);
+
   /* If the variable cannot be modified and this is a VDEF change
      it into a VUSE.  This happens when read-only variables are marked
      call-clobbered and/or aliased to writable variables.  So we only
@@ -1630,6 +1633,9 @@ get_addr_dereference_operands (gimple st
 {
   tree ptr = *addr;
 
+  /* Mark the statement as having memory operands.  */
+  gimple_set_references_memory (stmt, true);
+
   if (SSA_VAR_P (ptr))
     {
       struct ptr_info_def *pi = NULL;
@@ -1754,6 +1760,9 @@ get_tmr_operands (gimple stmt, tree expr
 {
   tree tag;
 
+  /* Mark the statement as having memory operands.  */
+  gimple_set_references_memory (stmt, true);
+
   /* First record the real operands.  */
   get_expr_operands (stmt, &TMR_BASE (expr), opf_use);
   get_expr_operands (stmt, &TMR_INDEX (expr), opf_use);
@@ -1931,6 +1940,9 @@ maybe_add_call_clobbered_vops (gimple st
 {
   int call_flags = gimple_call_flags (stmt);
 
+  /* Mark the statement as having memory operands.  */
+  gimple_set_references_memory (stmt, true);
+
   /* If aliases have been computed already, add VDEF or VUSE
      operands for all the symbols that have been found to be
      call-clobbered.  */
@@ -2013,6 +2025,9 @@ get_asm_expr_operands (gimple stmt)
 	  unsigned i;
 	  bitmap_iterator bi;
 
+	  /* Mark the statement as having memory operands.  */
+	  gimple_set_references_memory (stmt, true);
+
 	  EXECUTE_IF_SET_IN_BITMAP (gimple_call_clobbered_vars (cfun), 0, i, bi)
 	    {
 	      tree var = referenced_var (i);
@@ -2406,8 +2421,10 @@ parse_ssa_operands (gimple stmt)
 static void
 build_ssa_operands (gimple stmt)
 {
-  /* Initially assume that the statement has no volatile operands.  */
+  /* Initially assume that the statement has no volatile operands and
+     makes no memory references.  */
   gimple_set_has_volatile_ops (stmt, false);
+  gimple_set_references_memory (stmt, false);
 
   /* Just clear the bitmap so we don't end up reallocating it over and over.  */
   if (gimple_addresses_taken (stmt))
@@ -2418,6 +2435,11 @@ build_ssa_operands (gimple stmt)
   operand_build_sort_virtual (build_vuses);
   operand_build_sort_virtual (build_vdefs);
   finalize_ssa_stmt_operands (stmt);
+
+  /* For added safety, assume that statements with volatile operands
+     also reference memory.  */
+  if (gimple_has_volatile_ops (stmt))
+    gimple_set_references_memory (stmt, true);
 }
 
 
@@ -2879,7 +2901,7 @@ push_stmt_changes (gimple *stmt_p)
 
   buf->stmt_p = stmt_p;
 
-  if (stmt_references_memory_p (stmt))
+  if (gimple_references_memory_p (stmt))
     {
       tree op;
       ssa_op_iter i;
@@ -2968,7 +2990,7 @@ pop_stmt_changes (gimple *stmt_p)
      memory anymore, but we still need to act on the differences in
      the sets of symbols.  */
   loads = stores = NULL;
-  if (stmt_references_memory_p (stmt))
+  if (gimple_references_memory_p (stmt))
     {
       tree op;
       ssa_op_iter i;
@@ -3050,21 +3072,3 @@ discard_stmt_changes (gimple *stmt_p)
   buf->stmt_p = NULL;
   free (buf);
 }
-
-
-/* Returns true if statement STMT may access memory.  */
-
-bool
-stmt_references_memory_p (gimple stmt)
-{
-  if (!gimple_ssa_operands (cfun)->ops_active
-      || gimple_code (stmt) == GIMPLE_PHI)
-    return false;
-
-  /* Statements with volatile operands are assumed to access memory
-     as well.  */
-  return gimple_has_mem_ops (stmt)
-	 && (stmt->with_mem_ops.vdef_ops
-	     || stmt->with_mem_ops.vuse_ops
-	     || stmt->with_mem_ops.has_volatile_ops);
-}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]