Skip to content
Snippets Groups Projects
gimplify.c 125 KiB
Newer Older

  /* The 'else' branch also needs a label if it contains interesting code.  */
    false_label_p = &false_label;
  else
    false_label_p = NULL;

  /* If there was nothing else in our arms, just forward the label(s).  */
    return shortcut_cond_r (pred, true_label_p, false_label_p);

  /* If our last subexpression already has a terminal label, reuse it.  */
    expr = expr_last (else_);
    expr = expr_last (then_);
  else
    expr = NULL;
  if (expr && TREE_CODE (expr) == LABEL_EXPR)
    end_label = LABEL_EXPR_LABEL (expr);

  /* If we don't care about jumping to the 'else' branch, jump to the end
     if the condition is false.  */
  if (!false_label_p)
    false_label_p = &end_label;

  /* We only want to emit these labels if we aren't hijacking them.  */
  emit_end = (end_label == NULL_TREE);
  emit_false = (false_label == NULL_TREE);

  pred = shortcut_cond_r (pred, true_label_p, false_label_p);

  expr = NULL;
  append_to_statement_list (pred, &expr);

  append_to_statement_list (then_, &expr);
    {
      t = build_and_jump (&end_label);
      append_to_statement_list (t, &expr);
      if (emit_false)
	{
	  t = build1 (LABEL_EXPR, void_type_node, false_label);
	  append_to_statement_list (t, &expr);
	}
      append_to_statement_list (else_, &expr);
    }
  if (emit_end && end_label)
    {
      t = build1 (LABEL_EXPR, void_type_node, end_label);
      append_to_statement_list (t, &expr);
    }

  return expr;
}

/* EXPR is used in a boolean context; make sure it has BOOLEAN_TYPE.  */

static tree
gimple_boolify (tree expr)
{
  tree type = TREE_TYPE (expr);

  if (TREE_CODE (type) == BOOLEAN_TYPE)
    return expr;

  /* If this is the predicate of a COND_EXPR, it might not even be a
     truthvalue yet.  */
  expr = lang_hooks.truthvalue_conversion (expr);

  switch (TREE_CODE (expr))
    {
    case TRUTH_AND_EXPR:
    case TRUTH_OR_EXPR:
    case TRUTH_XOR_EXPR:
    case TRUTH_ANDIF_EXPR:
    case TRUTH_ORIF_EXPR:
      /* Also boolify the arguments of truth exprs.  */
      TREE_OPERAND (expr, 1) = gimple_boolify (TREE_OPERAND (expr, 1));
      /* FALLTHRU */

    case TRUTH_NOT_EXPR:
      TREE_OPERAND (expr, 0) = gimple_boolify (TREE_OPERAND (expr, 0));
      /* FALLTHRU */

    case EQ_EXPR: case NE_EXPR:
    case LE_EXPR: case GE_EXPR: case LT_EXPR: case GT_EXPR:
      /* These expressions always produce boolean results.  */
      TREE_TYPE (expr) = boolean_type_node;
      return expr;
    default:
      /* Other expressions that get here must have boolean values, but
	 might need to be converted to the appropriate mode.  */
      return convert (boolean_type_node, expr);
    }
}

/*  Convert the conditional expression pointed by EXPR_P '(p) ? a : b;'
    into

    if (p)			if (p)
      t1 = a;			  a;
    else		or	else
      t1 = b;			  b;
    t1;

    The second form is used when *EXPR_P is of type void.

    PRE_P points to the list where side effects that must happen before
	*EXPR_P should be stored.  */

static enum gimplify_status
gimplify_cond_expr (tree *expr_p, tree *pre_p, tree target)
{
  tree expr = *expr_p;
  enum gimplify_status ret;

  type = TREE_TYPE (expr);
  if (!type)
    TREE_TYPE (expr) = void_type_node;

  /* If this COND_EXPR has a value, copy the values into a temporary within
     the arms.  */
  else if (! VOID_TYPE_P (type))
    {
      if (target)
	{
	  ret = gimplify_expr (&target, pre_p, NULL,
			       is_gimple_min_lval, fb_lvalue);
	  if (ret != GS_ERROR)
	    ret = GS_OK;
	  tmp2 = tmp = create_tmp_var (TREE_TYPE (expr), "iftmp");
	  ret = GS_ALL_DONE;
	}

      /* Build the then clause, 't1 = a;'.  But don't build an assignment
	 if this branch is void; in C++ it can be, if it's a throw.  */
      if (TREE_TYPE (TREE_OPERAND (expr, 1)) != void_type_node)
	TREE_OPERAND (expr, 1)
	  = build (MODIFY_EXPR, void_type_node, tmp, TREE_OPERAND (expr, 1));

      /* Build the else clause, 't1 = b;'.  */
      if (TREE_TYPE (TREE_OPERAND (expr, 2)) != void_type_node)
	TREE_OPERAND (expr, 2)
	  = build (MODIFY_EXPR, void_type_node, tmp2, TREE_OPERAND (expr, 2));

      TREE_TYPE (expr) = void_type_node;
      recalculate_side_effects (expr);

      /* Move the COND_EXPR to the prequeue.  */
      return ret;
    }

  /* Make sure the condition has BOOLEAN_TYPE.  */
  TREE_OPERAND (expr, 0) = gimple_boolify (TREE_OPERAND (expr, 0));

  /* Break apart && and || conditions.  */
  if (TREE_CODE (TREE_OPERAND (expr, 0)) == TRUTH_ANDIF_EXPR
      || TREE_CODE (TREE_OPERAND (expr, 0)) == TRUTH_ORIF_EXPR)
    {
      expr = shortcut_cond_expr (expr);

      if (expr != *expr_p)
	{
	  *expr_p = expr;

	  /* We can't rely on gimplify_expr to re-gimplify the expanded
	     form properly, as cleanups might cause the target labels to be
	     wrapped in a TRY_FINALLY_EXPR.  To prevent that, we need to
	     set up a conditional context.  */
	  gimple_push_condition ();
	  gimplify_stmt (expr_p);
	  gimple_pop_condition (pre_p);

	  return GS_ALL_DONE;
	}
    }

  /* Now do the normal gimplification.  */
  ret = gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, NULL,
		       is_gimple_condexpr, fb_rvalue);

  gimple_push_condition ();

  gimplify_to_stmt_list (&TREE_OPERAND (expr, 1));
  gimplify_to_stmt_list (&TREE_OPERAND (expr, 2));
  recalculate_side_effects (expr);

  gimple_pop_condition (pre_p);

  if (ret == GS_ERROR)
    ;
  else if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1)))
    ret = GS_ALL_DONE;
  else if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 2)))
    /* Rewrite "if (a); else b" to "if (!a) b"  */
    {
      TREE_OPERAND (expr, 0) = invert_truthvalue (TREE_OPERAND (expr, 0));
      ret = gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, NULL,
			   is_gimple_condexpr, fb_rvalue);

      tmp = TREE_OPERAND (expr, 1);
      TREE_OPERAND (expr, 1) = TREE_OPERAND (expr, 2);
      TREE_OPERAND (expr, 2) = tmp;
    }
  else
    /* Both arms are empty; replace the COND_EXPR with its predicate.  */
    expr = TREE_OPERAND (expr, 0);

  *expr_p = expr;
  return ret;
}

/* A subroutine of gimplify_modify_expr.  Replace a MODIFY_EXPR with
   a call to __builtin_memcpy.  */

static enum gimplify_status
gimplify_modify_expr_to_memcpy (tree *expr_p, tree size, bool want_value)
{
  tree args, t, to, to_ptr, from;

  to = TREE_OPERAND (*expr_p, 0);
  from = TREE_OPERAND (*expr_p, 1);

  args = tree_cons (NULL, size, NULL);

  t = build_fold_addr_expr (from);
  args = tree_cons (NULL, t, args);

  to_ptr = build_fold_addr_expr (to);
  t = implicit_built_in_decls[BUILT_IN_MEMCPY];
  t = build_function_call_expr (t, args);

  if (want_value)
    {
      t = build1 (NOP_EXPR, TREE_TYPE (to_ptr), t);
      t = build1 (INDIRECT_REF, TREE_TYPE (to), t);
    }

  *expr_p = t;
  return GS_OK;
}

/* A subroutine of gimplify_modify_expr.  Replace a MODIFY_EXPR with
   a call to __builtin_memset.  In this case we know that the RHS is
   a CONSTRUCTOR with an empty element list.  */

static enum gimplify_status
gimplify_modify_expr_to_memset (tree *expr_p, tree size, bool want_value)
  args = tree_cons (NULL, size, NULL);

  args = tree_cons (NULL, integer_zero_node, args);

  to_ptr = build_fold_addr_expr (to);
  t = implicit_built_in_decls[BUILT_IN_MEMSET];
  t = build_function_call_expr (t, args);

  if (want_value)
    {
      t = build1 (NOP_EXPR, TREE_TYPE (to_ptr), t);
      t = build1 (INDIRECT_REF, TREE_TYPE (to), t);
    }

  *expr_p = t;
  return GS_OK;
}

/* A subroutine of gimplify_init_ctor_preeval.  Called via walk_tree,
   determine, cautiously, if a CONSTRUCTOR overlaps the lhs of an
   assignment.  Returns non-null if we detect a potential overlap.  */

struct gimplify_init_ctor_preeval_data
{
  /* The base decl of the lhs object.  May be NULL, in which case we
     have to assume the lhs is indirect.  */
  tree lhs_base_decl;

  /* The alias set of the lhs object.  */
  int lhs_alias_set;
};

static tree
gimplify_init_ctor_preeval_1 (tree *tp, int *walk_subtrees, void *xdata)
{
  struct gimplify_init_ctor_preeval_data *data
    = (struct gimplify_init_ctor_preeval_data *) xdata;
  tree t = *tp;

  /* If we find the base object, obviously we have overlap.  */
  if (data->lhs_base_decl == t)
    return t;

  /* If the constructor component is indirect, determine if we have a
     potential overlap with the lhs.  The only bits of information we
     have to go on at this point are addressability and alias sets.  */
  if (TREE_CODE (t) == INDIRECT_REF
      && (!data->lhs_base_decl || TREE_ADDRESSABLE (data->lhs_base_decl))
      && alias_sets_conflict_p (data->lhs_alias_set, get_alias_set (t)))
    return t;

    *walk_subtrees = 0;
  return NULL;
}

/* A subroutine of gimplify_init_constructor.  Pre-evaluate *EXPR_P,
   force values that overlap with the lhs (as described by *DATA)
   into temporaries.  */

static void
gimplify_init_ctor_preeval (tree *expr_p, tree *pre_p, tree *post_p,
			    struct gimplify_init_ctor_preeval_data *data)
{
  enum gimplify_status one;

  /* If the value is invariant, then there's nothing to pre-evaluate.
     But ensure it doesn't have any side-effects since a SAVE_EXPR is
     invariant but has side effects and might contain a reference to
     the object we're initializing.  */
  if (TREE_INVARIANT (*expr_p) && !TREE_SIDE_EFFECTS (*expr_p))
    return;

  /* If the type has non-trivial constructors, we can't pre-evaluate.  */
  if (TREE_ADDRESSABLE (TREE_TYPE (*expr_p)))
    return;

  /* Recurse for nested constructors.  */
  if (TREE_CODE (*expr_p) == CONSTRUCTOR)
    {
      tree list;
      for (list = CONSTRUCTOR_ELTS (*expr_p); list ; list = TREE_CHAIN (list))
	gimplify_init_ctor_preeval (&TREE_VALUE (list), pre_p, post_p, data);
      return;
    }

  /* We can't preevaluate if the type contains a placeholder.  */
  if (type_contains_placeholder_p (TREE_TYPE (*expr_p)))
    return;

  /* 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
     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
     exponential search behavior.  */
  one = gimplify_expr (expr_p, pre_p, post_p, is_gimple_mem_rhs, fb_rvalue);
  if (one == GS_ERROR)
    {
      *expr_p = NULL;
      return;
    }

  /* If we gimplified to a bare decl, we can be sure that it doesn't overlap
     with the lhs, since "a = { .x=a }" doesn't make sense.  This will
     always be true for all scalars, since is_gimple_mem_rhs insists on a
     temporary variable for them.  */
  if (DECL_P (*expr_p))
    return;

  /* If this is of variable size, we have no choice but to assume it doesn't
     overlap since we can't make a temporary for it.  */
  if (!TREE_CONSTANT (TYPE_SIZE (TREE_TYPE (*expr_p))))
    return;

  /* Otherwise, we must search for overlap ...  */
  if (!walk_tree (expr_p, gimplify_init_ctor_preeval_1, data, NULL))
    return;

  /* ... and if found, force the value into a temporary.  */
  *expr_p = get_formal_tmp_var (*expr_p, pre_p);
}

/* A subroutine of gimplify_init_constructor.  Generate individual
   MODIFY_EXPRs for a CONSTRUCTOR.  OBJECT is the LHS against which the
   assignments should happen.  LIST is the CONSTRUCTOR_ELTS of the
   CONSTRUCTOR.  CLEARED is true if the entire LHS object has been
   zeroed first.  */

static void
gimplify_init_ctor_eval (tree object, tree list, tree *pre_p, bool cleared)
{
  tree array_elt_type = NULL;

  if (TREE_CODE (TREE_TYPE (object)) == ARRAY_TYPE)
    array_elt_type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (object)));

  for (; list; list = TREE_CHAIN (list))
    {
      tree purpose, value, cref, init;

      purpose = TREE_PURPOSE (list);
      value = TREE_VALUE (list);

      /* NULL values are created above for gimplification errors.  */
      if (value == NULL)
	continue;

      if (cleared && initializer_zerop (value))
	continue;

      if (array_elt_type)
	{
	  /* ??? Here's to hoping the front end fills in all of the indicies,
	     so we don't have to figure out what's missing ourselves.  */
	  /* ??? Need to handle this.  */
	  gcc_assert (TREE_CODE (purpose) != RANGE_EXPR);

	  cref = build (ARRAY_REF, array_elt_type, unshare_expr (object),
			purpose, NULL_TREE, NULL_TREE);
	}
      else
	cref = build (COMPONENT_REF, TREE_TYPE (purpose),
		      unshare_expr (object), purpose, NULL_TREE);

      if (TREE_CODE (value) == CONSTRUCTOR)
	gimplify_init_ctor_eval (cref, CONSTRUCTOR_ELTS (value),
				 pre_p, cleared);
      else
	{
	  init = build (MODIFY_EXPR, TREE_TYPE (cref), cref, value);
	  gimplify_and_add (init, pre_p);
	}
    }
}

/* A subroutine of gimplify_modify_expr.  Break out elements of a
   CONSTRUCTOR used as an initializer into separate MODIFY_EXPRs.

   Note that we still need to clear any elements that don't have explicit
   initializers, so if not all elements are initialized we keep the
   original MODIFY_EXPR, we just remove all of the constructor elements.  */

static enum gimplify_status
gimplify_init_constructor (tree *expr_p, tree *pre_p,
			   tree *post_p, bool want_value)
{
  tree ctor = TREE_OPERAND (*expr_p, 1);
  tree type = TREE_TYPE (ctor);
  enum gimplify_status ret;
  tree elt_list;

  if (TREE_CODE (ctor) != CONSTRUCTOR)
    return GS_UNHANDLED;

  ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
		       is_gimple_lvalue, fb_lvalue);
  if (ret == GS_ERROR)
    return ret;
  object = TREE_OPERAND (*expr_p, 0);

  elt_list = CONSTRUCTOR_ELTS (ctor);

  ret = GS_ALL_DONE;
  switch (TREE_CODE (type))
    {
    case RECORD_TYPE:
    case UNION_TYPE:
    case QUAL_UNION_TYPE:
    case ARRAY_TYPE:
      {
	struct gimplify_init_ctor_preeval_data preeval_data;
	HOST_WIDE_INT num_elements, num_nonzero_elements;
	HOST_WIDE_INT num_nonconstant_elements;
	bool cleared;

	/* Aggregate types must lower constructors to initialization of
	   individual elements.  The exception is that a CONSTRUCTOR node
	   with no elements indicates zero-initialization of the whole.  */
	if (elt_list == NULL)

	categorize_ctor_elements (ctor, &num_nonzero_elements,
				  &num_nonconstant_elements);

	/* If a const aggregate variable is being initialized, then it
	   should never be a lose to promote the variable to be static.  */
	if (num_nonconstant_elements == 0
	    && TREE_READONLY (object)
	    && TREE_CODE (object) == VAR_DECL)
	  {
	    DECL_INITIAL (object) = ctor;
	    TREE_STATIC (object) = 1;
	    if (!DECL_NAME (object))
	      DECL_NAME (object) = create_tmp_var_name ("C");
	    walk_tree (&DECL_INITIAL (object), force_labels_r, NULL, NULL);

	    /* ??? C++ doesn't automatically append a .<number> to the
	       assembler name, and even when it does, it looks a FE private
	       data structures to figure out what that number should be,
	       which are not set for this variable.  I suppose this is
	       important for local statics for inline functions, which aren't
	       "local" in the object file sense.  So in order to get a unique
	       TU-local symbol, we must invoke the lhd version now.  */
	    lhd_set_decl_assembler_name (object);

	    *expr_p = NULL_TREE;
	    break;
	  }

	/* If there are "lots" of initialized elements, and all of them
	   are valid address constants, then the entire initializer can
	   be dropped to memory, and then memcpy'd out.  */
	if (num_nonconstant_elements == 0)
	  {
	    HOST_WIDE_INT size = int_size_in_bytes (type);
	    unsigned int align;

	    /* ??? We can still get unbounded array types, at least
	       from the C++ front end.  This seems wrong, but attempt
	       to work around it for now.  */
	    if (size < 0)
	      {
		size = int_size_in_bytes (TREE_TYPE (object));
		if (size >= 0)
		  TREE_TYPE (ctor) = type = TREE_TYPE (object);
	      }

	    /* Find the maximum alignment we can assume for the object.  */
	    /* ??? Make use of DECL_OFFSET_ALIGN.  */
	    if (DECL_P (object))
	      align = DECL_ALIGN (object);
	    else
	      align = TYPE_ALIGN (type);

	    if (size > 0 && !can_move_by_pieces (size, align))
	      {
		tree new = create_tmp_var_raw (type, "C");
		gimple_add_tmp_var (new);
		TREE_STATIC (new) = 1;
		TREE_READONLY (new) = 1;
		DECL_INITIAL (new) = ctor;
		if (align > DECL_ALIGN (new))
		  {
		    DECL_ALIGN (new) = align;
		    DECL_USER_ALIGN (new) = 1;
		  }
	        walk_tree (&DECL_INITIAL (new), force_labels_r, NULL, NULL);

		TREE_OPERAND (*expr_p, 1) = new;

		/* This is no longer an assignment of a CONSTRUCTOR, but
		   we still may have processing to do on the LHS.  So
		   pretend we didn't do anything here to let that happen.  */
		return GS_UNHANDLED;
	      }
	  }

	/* If there are "lots" of initialized elements, even discounting
	   those that are not address constants (and thus *must* be
	   computed at runtime), then partition the constructor into
	   constant and non-constant parts.  Block copy the constant
	   parts in, then generate code for the non-constant parts.  */
	/* TODO.  There's code in cp/typeck.c to do this.  */

	num_elements = count_type_elements (TREE_TYPE (ctor));

	/* If there are "lots" of zeros, then block clear the object first.  */
	cleared = false;
	if (num_elements - num_nonzero_elements > CLEAR_RATIO
	    && num_nonzero_elements < num_elements/4)
	  cleared = true;

	/* ??? This bit ought not be needed.  For any element not present
	   in the initializer, we should simply set them to zero.  Except
	   we'd need to *find* the elements that are not present, and that
	   requires trickery to avoid quadratic compile-time behavior in
	   large cases or excessive memory use in small cases.  */
	else
	  {
	    HOST_WIDE_INT len = list_length (elt_list);
	    if (TREE_CODE (type) == ARRAY_TYPE)
	      {
		tree nelts = array_type_nelts (type);
		if (!host_integerp (nelts, 1)
		    || tree_low_cst (nelts, 1) + 1 != len)
	  }

	if (cleared)
	  {
	    /* Zap the CONSTRUCTOR element list, which simplifies this case.
	       Note that we still have to gimplify, in order to handle the
	       case of variable sized types.  Avoid shared tree structures.  */
	    object = unshare_expr (object);
	    gimplify_stmt (expr_p);
	    append_to_statement_list (*expr_p, pre_p);
	  }

	preeval_data.lhs_base_decl = get_base_address (object);
	if (!DECL_P (preeval_data.lhs_base_decl))
	  preeval_data.lhs_base_decl = NULL;
	preeval_data.lhs_alias_set = get_alias_set (object);
	gimplify_init_ctor_preeval (&TREE_OPERAND (*expr_p, 1),
				    pre_p, post_p, &preeval_data);
	gimplify_init_ctor_eval (object, elt_list, pre_p, cleared);

	*expr_p = NULL_TREE;
      }
      break;

    case COMPLEX_TYPE:
      {
	tree r, i;

	/* Extract the real and imaginary parts out of the ctor.  */
	r = i = NULL_TREE;
	if (elt_list)
	  {
	    r = TREE_VALUE (elt_list);
	    elt_list = TREE_CHAIN (elt_list);
	    if (elt_list)
	      {
		i = TREE_VALUE (elt_list);
		gcc_assert (!TREE_CHAIN (elt_list));
	      }
	  }
	if (r == NULL || i == NULL)
	  {
	    tree zero = convert (TREE_TYPE (type), integer_zero_node);
	    if (r == NULL)
	      r = zero;
	    if (i == NULL)
	      i = zero;
	  }

	/* Complex types have either COMPLEX_CST or COMPLEX_EXPR to
	   represent creation of a complex value.  */
	if (TREE_CONSTANT (r) && TREE_CONSTANT (i))
	  {
	    ctor = build_complex (type, r, i);
	    TREE_OPERAND (*expr_p, 1) = ctor;
	  }
	else
	  {
	    ctor = build (COMPLEX_EXPR, type, r, i);
	    TREE_OPERAND (*expr_p, 1) = ctor;
	    ret = gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p,
				 rhs_predicate_for (TREE_OPERAND (*expr_p, 0)),
				 fb_rvalue);
    case VECTOR_TYPE:
      /* Go ahead and simplify constant constructors to VECTOR_CST.  */
      if (TREE_CONSTANT (ctor))
	TREE_OPERAND (*expr_p, 1) = build_vector (type, elt_list);
	  /* Vector types use CONSTRUCTOR all the way through gimple
	     compilation as a general initializer.  */
	  for (; elt_list; elt_list = TREE_CHAIN (elt_list))
	    {
	      enum gimplify_status tret;
	      tret = gimplify_expr (&TREE_VALUE (elt_list), pre_p, post_p,
				    is_gimple_val, fb_rvalue);
    default:
      /* So how did we get a CONSTRUCTOR for a scalar type?  */
  if (ret == GS_ERROR)
    return GS_ERROR;
  else if (want_value)
    {
      append_to_statement_list (*expr_p, pre_p);
      *expr_p = object;
      return GS_OK;
/* Subroutine of gimplify_modify_expr to do simplifications of MODIFY_EXPRs
   based on the code of the RHS.  We loop for as long as something changes.  */
static enum gimplify_status
gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, tree *pre_p,
			  tree *post_p, bool want_value)
{
  enum gimplify_status ret = GS_OK;
  while (ret != GS_UNHANDLED)
    switch (TREE_CODE (*from_p))
      {
      case TARGET_EXPR:
	  /* If we are initializing something from a TARGET_EXPR, strip the
	     TARGET_EXPR and initialize it directly, if possible.  This can't
	     be done if the initializer is void, since that implies that the
	     temporary is set in some non-trivial way.
	     ??? What about code that pulls out the temp and uses it
	     elsewhere? I think that such code never uses the TARGET_EXPR as
	     an initializer.  If I'm wrong, we'll abort because the temp won't
	     have any RTL.  In that case, I guess we'll need to replace
	     references somehow.  */
	  tree init = TARGET_EXPR_INITIAL (*from_p);
	  if (!VOID_TYPE_P (TREE_TYPE (init)))
	    {
	      *from_p = init;
	      ret = GS_OK;
	    }
	  else
	    ret = GS_UNHANDLED;
      case COMPOUND_EXPR:
	/* Remove any COMPOUND_EXPR in the RHS so the following cases will be
	   caught.  */
	gimplify_compound_expr (from_p, pre_p, true);
	ret = GS_OK;
	break;
      case CONSTRUCTOR:
	/* If we're initializing from a CONSTRUCTOR, break this into
	   individual MODIFY_EXPRs.  */
	return gimplify_init_constructor (expr_p, pre_p, post_p, want_value);
	/* If we're assigning to a non-register type, push the assignment
	   down into the branches.  This is mandatory for ADDRESSABLE types,
	   since we cannot generate temporaries for such, but it saves a
	   copy in other cases as well.  */
	if (!is_gimple_reg_type (TREE_TYPE (*from_p)))
	  {
	    *expr_p = *from_p;
	    return gimplify_cond_expr (expr_p, pre_p, *to_p);
	  }
	else
	  ret = GS_UNHANDLED;
	break;
/* Gimplify the MODIFY_EXPR node pointed by EXPR_P.

      modify_expr
	      : varname '=' rhs
	      | '*' ID '=' rhs

    PRE_P points to the list where side effects that must happen before
	*EXPR_P should be stored.

    POST_P points to the list where side effects that must happen after
	*EXPR_P should be stored.

    WANT_VALUE is nonzero iff we want to use the value of this expression
	in another expression.  */

static enum gimplify_status
gimplify_modify_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value)
{
  tree *from_p = &TREE_OPERAND (*expr_p, 1);
  tree *to_p = &TREE_OPERAND (*expr_p, 0);
  enum gimplify_status ret = GS_UNHANDLED;
  gcc_assert (TREE_CODE (*expr_p) == MODIFY_EXPR
	      || TREE_CODE (*expr_p) == INIT_EXPR);

  /* The distinction between MODIFY_EXPR and INIT_EXPR is no longer useful.  */
  if (TREE_CODE (*expr_p) == INIT_EXPR)
    TREE_SET_CODE (*expr_p, MODIFY_EXPR);

  /* See if any simplifications can be done based on what the RHS is.  */
  ret = gimplify_modify_expr_rhs (expr_p, from_p, to_p, pre_p, post_p,
				  want_value);
  if (ret != GS_UNHANDLED)
  /* If the value being copied is of variable width, compute the length
     of the copy into a WITH_SIZE_EXPR.   Note that we need to do this
     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.  */
  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;
  ret = gimplify_expr (from_p, pre_p, post_p,
		       rhs_predicate_for (*to_p), fb_rvalue);
  if (ret == GS_ERROR)
    return ret;

  /* Now see if the above changed *from_p to something we handle specially.  */
  ret = gimplify_modify_expr_rhs (expr_p, from_p, to_p, pre_p, post_p,
				  want_value);
  if (ret != GS_UNHANDLED)
    return ret;

  /* If we've got a variable sized assignment between two lvalues (i.e. does
     not involve a call), then we can make things a bit more straightforward
     by converting the assignment to memcpy or memset.  */
  if (TREE_CODE (*from_p) == WITH_SIZE_EXPR)
    {
      tree from = TREE_OPERAND (*from_p, 0);
      tree size = TREE_OPERAND (*from_p, 1);

      if (TREE_CODE (from) == CONSTRUCTOR)
	return gimplify_modify_expr_to_memset (expr_p, size, want_value);
      if (is_gimple_addressable (from))
	{
	  *from_p = from;
	  return gimplify_modify_expr_to_memcpy (expr_p, size, want_value);
	}
    }

  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 modifying it twice.  Not good.  */
      gcc_assert (TREE_CODE (*to_p) != SSA_NAME);
      *to_p = make_ssa_name (*to_p, *expr_p);
    }

  if (want_value)
    {
      append_to_statement_list (*expr_p, pre_p);
      *expr_p = *to_p;
/*  Gimplify a comparison between two variable-sized objects.  Do this
    with a call to BUILT_IN_MEMCMP.  */

static enum gimplify_status
gimplify_variable_sized_compare (tree *expr_p)
{
  tree op0 = TREE_OPERAND (*expr_p, 0);
  tree op1 = TREE_OPERAND (*expr_p, 1);
  tree args, t, dest;

  t = TYPE_SIZE_UNIT (TREE_TYPE (op0));
  t = unshare_expr (t);
  t = SUBSTITUTE_PLACEHOLDER_IN_EXPR (t, op0);
  t = build_fold_addr_expr (op1);
  dest = build_fold_addr_expr (op0);
  args = tree_cons (NULL, dest, args);
  t = implicit_built_in_decls[BUILT_IN_MEMCMP];
  t = build_function_call_expr (t, args);
  *expr_p
    = build (TREE_CODE (*expr_p), TREE_TYPE (*expr_p), t, integer_zero_node);

  return GS_OK;
}

/*  Gimplify TRUTH_ANDIF_EXPR and TRUTH_ORIF_EXPR expressions.  EXPR_P
    points to the expression to gimplify.

    Expressions of the form 'a && b' are gimplified to:

	a && b ? true : false

    gimplify_cond_expr will do the rest.

    PRE_P points to the list where side effects that must happen before
	*EXPR_P should be stored.  */

static enum gimplify_status
gimplify_boolean_expr (tree *expr_p)
{
  /* Preserve the original type of the expression.  */
  tree type = TREE_TYPE (*expr_p);

  *expr_p = build (COND_EXPR, type, *expr_p,
		   convert (type, boolean_true_node),
		   convert (type, boolean_false_node));

  return GS_OK;
}

/* Gimplifies an expression sequence.  This function gimplifies each
   expression and re-writes the original expression with the last
   expression of the sequence in GIMPLE form.

   PRE_P points to the list where the side effects for all the
       expressions in the sequence will be emitted.
   WANT_VALUE is true when the result of the last COMPOUND_EXPR is used.  */
/* ??? Should rearrange to share the pre-queue with all the indirect
   invocations of gimplify_expr.  Would probably save on creations
   of statement_list nodes.  */

static enum gimplify_status
gimplify_compound_expr (tree *expr_p, tree *pre_p, bool want_value)
{
  tree t = *expr_p;

  do
    {
      tree *sub_p = &TREE_OPERAND (t, 0);

      if (TREE_CODE (*sub_p) == COMPOUND_EXPR)
	gimplify_compound_expr (sub_p, pre_p, false);
      else
	gimplify_stmt (sub_p);
      append_to_statement_list (*sub_p, pre_p);

      t = TREE_OPERAND (t, 1);
    }
  while (TREE_CODE (t) == COMPOUND_EXPR);

  *expr_p = t;
  if (want_value)
    return GS_OK;
  else
    {
      gimplify_stmt (expr_p);
      return GS_ALL_DONE;
    }
}

/* Gimplifies a statement list.  These may be created either by an
   enlightened front-end, or by shortcut_cond_expr.  */

static enum gimplify_status
gimplify_statement_list (tree *expr_p)
{
  tree_stmt_iterator i = tsi_start (*expr_p);

  while (!tsi_end_p (i))
    {
      tree t;

      gimplify_stmt (tsi_stmt_ptr (i));

      t = tsi_stmt (i);
      if (t == NULL)
	tsi_delink (&i);
      else if (TREE_CODE (t) == STATEMENT_LIST)
	{
	  tsi_link_before (&i, t, TSI_SAME_STMT);
	  tsi_delink (&i);
	}
      else
	tsi_next (&i);
    }

  return GS_ALL_DONE;
}

/*  Gimplify a SAVE_EXPR node.  EXPR_P points to the expression to
    gimplify.  After gimplification, EXPR_P will point to a new temporary
    that holds the original value of the SAVE_EXPR node.

    PRE_P points to the list where side effects that must happen before
	*EXPR_P should be stored.  */

static enum gimplify_status
gimplify_save_expr (tree *expr_p, tree *pre_p, tree *post_p)
{