Skip to content
Snippets Groups Projects
gimplify.c 353 KiB
Newer Older
      return fold_convert_loc (loc, boolean_type_node, expr);
Jakub Jelinek's avatar
Jakub Jelinek committed
/* Given a conditional expression *EXPR_P without side effects, gimplify
   its operands.  New statements are inserted to PRE_P.  */

static enum gimplify_status
gimplify_pure_cond_expr (tree *expr_p, gimple_seq *pre_p)
Jakub Jelinek's avatar
Jakub Jelinek committed
{
  tree expr = *expr_p, cond;
  enum gimplify_status ret, tret;
  enum tree_code code;

  cond = gimple_boolify (COND_EXPR_COND (expr));

  /* We need to handle && and || specially, as their gimplification
     creates pure cond_expr, thus leading to an infinite cycle otherwise.  */
  code = TREE_CODE (cond);
  if (code == TRUTH_ANDIF_EXPR)
    TREE_SET_CODE (cond, TRUTH_AND_EXPR);
  else if (code == TRUTH_ORIF_EXPR)
    TREE_SET_CODE (cond, TRUTH_OR_EXPR);
  ret = gimplify_expr (&cond, pre_p, NULL, is_gimple_condexpr, fb_rvalue);
Jakub Jelinek's avatar
Jakub Jelinek committed
  COND_EXPR_COND (*expr_p) = cond;

  tret = gimplify_expr (&COND_EXPR_THEN (expr), pre_p, NULL,
				   is_gimple_val, fb_rvalue);
  ret = MIN (ret, tret);
  tret = gimplify_expr (&COND_EXPR_ELSE (expr), pre_p, NULL,
				   is_gimple_val, fb_rvalue);

  return MIN (ret, tret);
}

/* Return true if evaluating EXPR could trap.
Jakub Jelinek's avatar
Jakub Jelinek committed
   EXPR is GENERIC, while tree_could_trap_p can be called
   only on GIMPLE.  */

static bool
generic_expr_could_trap_p (tree expr)
{
  unsigned i, n;

  if (!expr || is_gimple_val (expr))
    return false;

  if (!EXPR_P (expr) || tree_could_trap_p (expr))
    return true;

  n = TREE_OPERAND_LENGTH (expr);
  for (i = 0; i < n; i++)
    if (generic_expr_could_trap_p (TREE_OPERAND (expr, i)))
      return true;

  return false;
}

/*  Convert the conditional expression pointed to 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

static enum gimplify_status
gimplify_cond_expr (tree *expr_p, gimple_seq *pre_p, fallback_t fallback)
{
  tree expr = *expr_p;
  tree type = TREE_TYPE (expr);
  location_t loc = EXPR_LOCATION (expr);
  tree tmp, arm1, arm2;
  enum gimplify_status ret;
  tree label_true, label_false, label_cont;
  bool have_then_clause_p, have_else_clause_p;
  enum tree_code pred_code;
  gimple_seq seq = NULL;

  /* If this COND_EXPR has a value, copy the values into a temporary within
     the arms.  */
      tree then_ = TREE_OPERAND (expr, 1), else_ = TREE_OPERAND (expr, 2);
      /* If either an rvalue is ok or we do not require an lvalue, create the
	 temporary.  But we cannot do that if the type is addressable.  */
      if (((fallback & fb_rvalue) || !(fallback & fb_lvalue))
Jakub Jelinek's avatar
Jakub Jelinek committed
	  if (gimplify_ctxp->allow_rhs_cond_expr
	      /* If either branch has side effects or could trap, it can't be
		 evaluated unconditionally.  */
	      && !TREE_SIDE_EFFECTS (then_)
	      && !generic_expr_could_trap_p (then_)
	      && !TREE_SIDE_EFFECTS (else_)
	      && !generic_expr_could_trap_p (else_))
Jakub Jelinek's avatar
Jakub Jelinek committed
	    return gimplify_pure_cond_expr (expr_p, pre_p);

	  tmp = create_tmp_var (type, "iftmp");
	  result = tmp;

      /* Otherwise, only create and copy references to the values.  */
	  type = build_pointer_type (type);
	  if (!VOID_TYPE_P (TREE_TYPE (then_)))
	    then_ = build_fold_addr_expr_loc (loc, then_);
	  if (!VOID_TYPE_P (TREE_TYPE (else_)))
	    else_ = build_fold_addr_expr_loc (loc, else_);
 
	  expr
	    = build3 (COND_EXPR, type, TREE_OPERAND (expr, 0), then_, else_);
Jakub Jelinek's avatar
Jakub Jelinek committed

	  tmp = create_tmp_var (type, "iftmp");
	  result = build_simple_mem_ref_loc (loc, tmp);
      /* Build the new then clause, `tmp = then_;'.  But don't build the
	 assignment if the value is void; in C++ it can be if it's a throw.  */
      if (!VOID_TYPE_P (TREE_TYPE (then_)))
	TREE_OPERAND (expr, 1) = build2 (MODIFY_EXPR, type, tmp, then_);
      /* Similarly, build the new else clause, `tmp = else_;'.  */
      if (!VOID_TYPE_P (TREE_TYPE (else_)))
	TREE_OPERAND (expr, 2) = build2 (MODIFY_EXPR, type, tmp, else_);

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

      /* Move the COND_EXPR to the prequeue.  */
  /* Remove any COMPOUND_EXPR so the following cases will be caught.  */
  STRIP_TYPE_NOPS (TREE_OPERAND (expr, 0));
  if (TREE_CODE (TREE_OPERAND (expr, 0)) == COMPOUND_EXPR)
    gimplify_compound_expr (&TREE_OPERAND (expr, 0), pre_p, true);

  /* 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 ();
	  gimple_seq_add_seq (pre_p, seq);
  /* Gimplify condition.  */
  ret = gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, NULL, is_gimple_condexpr,
		       fb_rvalue);
    return GS_ERROR;
  gcc_assert (TREE_OPERAND (expr, 0) != NULL_TREE);

  gimple_push_condition ();
  have_then_clause_p = have_else_clause_p = false;
  if (TREE_OPERAND (expr, 1) != NULL
      && TREE_CODE (TREE_OPERAND (expr, 1)) == GOTO_EXPR
      && TREE_CODE (GOTO_DESTINATION (TREE_OPERAND (expr, 1))) == LABEL_DECL
      && (DECL_CONTEXT (GOTO_DESTINATION (TREE_OPERAND (expr, 1)))
	  == current_function_decl)
      /* For -O0 avoid this optimization if the COND_EXPR and GOTO_EXPR
	 have different locations, otherwise we end up with incorrect
	 location information on the branches.  */
      && (optimize
	  || !EXPR_HAS_LOCATION (expr)
	  || !EXPR_HAS_LOCATION (TREE_OPERAND (expr, 1))
	  || EXPR_LOCATION (expr) == EXPR_LOCATION (TREE_OPERAND (expr, 1))))
    {
      label_true = GOTO_DESTINATION (TREE_OPERAND (expr, 1));
      have_then_clause_p = true;
    label_true = create_artificial_label (UNKNOWN_LOCATION);
  if (TREE_OPERAND (expr, 2) != NULL
      && TREE_CODE (TREE_OPERAND (expr, 2)) == GOTO_EXPR
      && TREE_CODE (GOTO_DESTINATION (TREE_OPERAND (expr, 2))) == LABEL_DECL
      && (DECL_CONTEXT (GOTO_DESTINATION (TREE_OPERAND (expr, 2)))
	  == current_function_decl)
      /* For -O0 avoid this optimization if the COND_EXPR and GOTO_EXPR
	 have different locations, otherwise we end up with incorrect
	 location information on the branches.  */
      && (optimize
	  || !EXPR_HAS_LOCATION (expr)
	  || !EXPR_HAS_LOCATION (TREE_OPERAND (expr, 2))
	  || EXPR_LOCATION (expr) == EXPR_LOCATION (TREE_OPERAND (expr, 2))))
    {
      label_false = GOTO_DESTINATION (TREE_OPERAND (expr, 2));
      have_else_clause_p = true;
    }
  else
    label_false = create_artificial_label (UNKNOWN_LOCATION);
  gimple_cond_get_ops_from_tree (COND_EXPR_COND (expr), &pred_code, &arm1,
				 &arm2);
  cond_stmt = gimple_build_cond (pred_code, arm1, arm2, label_true,
  gimple_set_no_warning (cond_stmt, TREE_NO_WARNING (COND_EXPR_COND (expr)));
  gimplify_seq_add_stmt (&seq, cond_stmt);
  gimple_stmt_iterator gsi = gsi_last (seq);
  maybe_fold_stmt (&gsi);

  label_cont = NULL_TREE;
  if (!have_then_clause_p)
    {
      /* For if (...) {} else { code; } put label_true after
	 the else block.  */
      if (TREE_OPERAND (expr, 1) == NULL_TREE
	  && !have_else_clause_p
	  && TREE_OPERAND (expr, 2) != NULL_TREE)
	label_cont = label_true;
      else
	{
	  gimplify_seq_add_stmt (&seq, gimple_build_label (label_true));
	  have_then_clause_p = gimplify_stmt (&TREE_OPERAND (expr, 1), &seq);
	  /* For if (...) { code; } else {} or
	     if (...) { code; } else goto label; or
	     if (...) { code; return; } else { ... }
	     label_cont isn't needed.  */
	  if (!have_else_clause_p
	      && TREE_OPERAND (expr, 2) != NULL_TREE
	      && gimple_seq_may_fallthru (seq))
	    {
	      gimple *g;
	      label_cont = create_artificial_label (UNKNOWN_LOCATION);

	      g = gimple_build_goto (label_cont);

	      /* GIMPLE_COND's are very low level; they have embedded
		 gotos.  This particular embedded goto should not be marked
		 with the location of the original COND_EXPR, as it would
		 correspond to the COND_EXPR's condition, not the ELSE or the
		 THEN arms.  To avoid marking it with the wrong location, flag
		 it as "no location".  */
	      gimple_set_do_not_emit_location (g);

	      gimplify_seq_add_stmt (&seq, g);
	    }
	}
    }
  if (!have_else_clause_p)
    {
      gimplify_seq_add_stmt (&seq, gimple_build_label (label_false));
      have_else_clause_p = gimplify_stmt (&TREE_OPERAND (expr, 2), &seq);
    }
  if (label_cont)
    gimplify_seq_add_stmt (&seq, gimple_build_label (label_cont));

  gimple_pop_condition (pre_p);
  gimple_seq_add_seq (pre_p, seq);

  if (ret == GS_ERROR)
    ; /* Do nothing.  */
  else if (have_then_clause_p || have_else_clause_p)
    ret = GS_ALL_DONE;
  else
    {
      /* Both arms are empty; replace the COND_EXPR with its predicate.  */
      expr = TREE_OPERAND (expr, 0);
      gimplify_stmt (&expr, pre_p);
    }

  *expr_p = NULL;
  return ret;
}

/* Prepare the node pointed to by EXPR_P, an is_gimple_addressable expression,
   to be marked addressable.

   We cannot rely on such an expression being directly markable if a temporary
   has been created by the gimplification.  In this case, we create another
   temporary and initialize it with a copy, which will become a store after we
   mark it addressable.  This can happen if the front-end passed us something
   that it could not mark addressable yet, like a Fortran pass-by-reference
   parameter (int) floatvar.  */

static void
prepare_gimple_addressable (tree *expr_p, gimple_seq *seq_p)
{
  while (handled_component_p (*expr_p))
    expr_p = &TREE_OPERAND (*expr_p, 0);
  if (is_gimple_reg (*expr_p))
    {
      tree var = get_initialized_tmp_var (*expr_p, seq_p, NULL);
      DECL_GIMPLE_REG_P (var) = 0;
      *expr_p = var;
    }
/* 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,
    				gimple_seq *seq_p)
  tree t, to, to_ptr, from, from_ptr;
  location_t loc = EXPR_LOCATION (*expr_p);
  to = TREE_OPERAND (*expr_p, 0);
  from = TREE_OPERAND (*expr_p, 1);
  /* Mark the RHS addressable.  Beware that it may not be possible to do so
     directly if a temporary has been created by the gimplification.  */
  prepare_gimple_addressable (&from, seq_p);

  mark_addressable (from);
  from_ptr = build_fold_addr_expr_loc (loc, from);
  gimplify_arg (&from_ptr, seq_p, loc);
  mark_addressable (to);
  to_ptr = build_fold_addr_expr_loc (loc, to);
  gimplify_arg (&to_ptr, seq_p, loc);

  gs = gimple_build_call (t, 3, to_ptr, from_ptr, size);
      gimple_call_set_lhs (gs, t);
      gimplify_seq_add_stmt (seq_p, gs);

      *expr_p = build_simple_mem_ref (t);
  gimplify_seq_add_stmt (seq_p, gs);
  *expr_p = NULL;
  return GS_ALL_DONE;
}

/* 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,
    				gimple_seq *seq_p)
  location_t loc = EXPR_LOCATION (*expr_p);
  /* Assert our assumptions, to abort instead of producing wrong code
     silently if they are not met.  Beware that the RHS CONSTRUCTOR might
     not be immediately exposed.  */
H.J. Lu's avatar
H.J. Lu committed
  from = TREE_OPERAND (*expr_p, 1);
  if (TREE_CODE (from) == WITH_SIZE_EXPR)
    from = TREE_OPERAND (from, 0);

  gcc_assert (TREE_CODE (from) == CONSTRUCTOR
	      && vec_safe_is_empty (CONSTRUCTOR_ELTS (from)));
  to = TREE_OPERAND (*expr_p, 0);
  to_ptr = build_fold_addr_expr_loc (loc, to);
  gimplify_arg (&to_ptr, seq_p, loc);

  gs = gimple_build_call (t, 3, to_ptr, integer_zero_node, size);
      gimple_call_set_lhs (gs, t);
      gimplify_seq_add_stmt (seq_p, gs);

      *expr_p = build1 (INDIRECT_REF, TREE_TYPE (to), t);
      return GS_ALL_DONE;
  gimplify_seq_add_stmt (seq_p, gs);
  *expr_p = NULL;
  return GS_ALL_DONE;
/* A subroutine of gimplify_init_ctor_preeval.  Called via walk_tree,
   determine, cautiously, if a CONSTRUCTOR overlaps the lhs of an
   assignment.  Return 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.  */
  alias_set_type 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 ((INDIRECT_REF_P (t)
       || TREE_CODE (t) == MEM_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;

  /* If the constructor component is a call, determine if it can hide a
     potential overlap with the lhs through an INDIRECT_REF like above.
     ??? Ugh - this is completely broken.  In fact this whole analysis
     doesn't look conservative.  */
  if (TREE_CODE (t) == CALL_EXPR)
    {
      tree type, fntype = TREE_TYPE (TREE_TYPE (CALL_EXPR_FN (t)));

      for (type = TYPE_ARG_TYPES (fntype); type; type = TREE_CHAIN (type))
	if (POINTER_TYPE_P (TREE_VALUE (type))
	    && (!data->lhs_base_decl || TREE_ADDRESSABLE (data->lhs_base_decl))
	    && alias_sets_conflict_p (data->lhs_alias_set,
				      get_alias_set
				        (TREE_TYPE (TREE_VALUE (type)))))
	  return t;
    }

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

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

  /* If the value is constant, then there's nothing to pre-evaluate.  */
  if (TREE_CONSTANT (*expr_p))
    {
      /* Ensure it does not have side effects, it might contain a reference to
	 the object we're initializing.  */
      gcc_assert (!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)
    {
      unsigned HOST_WIDE_INT ix;
      constructor_elt *ce;
      vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (*expr_p);
	gimplify_init_ctor_preeval (&ce->value, pre_p, post_p, data);
  /* If this is a variable sized type, we must remember the size.  */
  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
     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_CODE (TYPE_SIZE (TREE_TYPE (*expr_p))) != INTEGER_CST)
    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_ctor_eval.  Create a loop for
   a RANGE_EXPR in a CONSTRUCTOR for an array.

      var = lower;
    loop_entry:
      object[var] = value;
      if (var == upper)
	goto loop_exit;
      var = var + 1;
      goto loop_entry;
    loop_exit:

   We increment var _after_ the loop exit check because we might otherwise
   fail if upper == TYPE_MAX_VALUE (type for upper).

   Note that we never have to deal with SAVE_EXPRs here, because this has
   already been taken care of for us, in gimplify_init_ctor_preeval().  */

static void gimplify_init_ctor_eval (tree, vec<constructor_elt, va_gc> *,

static void
gimplify_init_ctor_eval_range (tree object, tree lower, tree upper,
			       tree value, tree array_elt_type,
			       gimple_seq *pre_p, bool cleared)
  tree loop_entry_label, loop_exit_label, fall_thru_label;
  loop_entry_label = create_artificial_label (UNKNOWN_LOCATION);
  loop_exit_label = create_artificial_label (UNKNOWN_LOCATION);
  fall_thru_label = create_artificial_label (UNKNOWN_LOCATION);

  /* Create and initialize the index variable.  */
  var_type = TREE_TYPE (upper);
  gimplify_seq_add_stmt (pre_p, gimple_build_assign (var, lower));
  gimplify_seq_add_stmt (pre_p, gimple_build_label (loop_entry_label));

  /* Build the reference.  */
  cref = build4 (ARRAY_REF, array_elt_type, unshare_expr (object),
		 var, NULL_TREE, NULL_TREE);

  /* If we are a constructor, just call gimplify_init_ctor_eval to do
     the store.  Otherwise just assign value to the reference.  */

  if (TREE_CODE (value) == CONSTRUCTOR)
    /* NB we might have to call ourself recursively through
       gimplify_init_ctor_eval if the value is a constructor.  */
    gimplify_init_ctor_eval (cref, CONSTRUCTOR_ELTS (value),
			     pre_p, cleared);
  else
    gimplify_seq_add_stmt (pre_p, gimple_build_assign (cref, value));

  /* We exit the loop when the index var is equal to the upper bound.  */
  gimplify_seq_add_stmt (pre_p,
			 gimple_build_cond (EQ_EXPR, var, upper,
					    loop_exit_label, fall_thru_label));

  gimplify_seq_add_stmt (pre_p, gimple_build_label (fall_thru_label));

  /* Otherwise, increment the index var...  */
  tmp = build2 (PLUS_EXPR, var_type, var,
		fold_convert (var_type, integer_one_node));
  gimplify_seq_add_stmt (pre_p, gimple_build_assign (var, tmp));
  gimplify_seq_add_stmt (pre_p, gimple_build_goto (loop_entry_label));
  gimplify_seq_add_stmt (pre_p, gimple_build_label (loop_exit_label));
/* Return true if FDECL is accessing a field that is zero sized.  */
zero_sized_field_decl (const_tree fdecl)
H.J. Lu's avatar
H.J. Lu committed
  if (TREE_CODE (fdecl) == FIELD_DECL && DECL_SIZE (fdecl)
zero_sized_type (const_tree type)
{
  if (AGGREGATE_TYPE_P (type) && TYPE_SIZE (type)
      && integer_zerop (TYPE_SIZE (type)))
    return true;
  return false;
}

/* A subroutine of gimplify_init_constructor.  Generate individual
   MODIFY_EXPRs for a CONSTRUCTOR.  OBJECT is the LHS against which the
   assignments should happen.  ELTS 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, vec<constructor_elt, va_gc> *elts,
			 gimple_seq *pre_p, bool cleared)
  unsigned HOST_WIDE_INT ix;
  tree purpose, value;

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

  FOR_EACH_CONSTRUCTOR_ELT (elts, ix, purpose, value)

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

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

      /* ??? Here's to hoping the front end fills in all of the indices,
	 so we don't have to figure out what's missing ourselves.  */
      gcc_assert (purpose);

      /* Skip zero-sized fields, unless value has side-effects.  This can
	 happen with calls to functions returning a zero-sized type, which
	 we shouldn't discard.  As a number of downstream passes don't
	 expect sets of zero-sized fields, we rely on the gimplification of
	 the MODIFY_EXPR we make below to drop the assignment statement.  */
      if (! TREE_SIDE_EFFECTS (value) && zero_sized_field_decl (purpose))
      /* If we have a RANGE_EXPR, we have to build a loop to assign the
	 whole range.  */
      if (TREE_CODE (purpose) == RANGE_EXPR)
	  tree lower = TREE_OPERAND (purpose, 0);
	  tree upper = TREE_OPERAND (purpose, 1);

	  /* If the lower bound is equal to upper, just treat it as if
	     upper was the index.  */
	  if (simple_cst_equal (lower, upper))
	    purpose = upper;
	  else
	    {
	      gimplify_init_ctor_eval_range (object, lower, upper, value,
					     array_elt_type, pre_p, cleared);
	      continue;
	    }
	}
	  /* Do not use bitsizetype for ARRAY_REF indices.  */
	  if (TYPE_DOMAIN (TREE_TYPE (object)))
	    purpose
	      = fold_convert (TREE_TYPE (TYPE_DOMAIN (TREE_TYPE (object))),
			      purpose);
	  cref = build4 (ARRAY_REF, array_elt_type, unshare_expr (object),
			 purpose, NULL_TREE, NULL_TREE);
	{
	  gcc_assert (TREE_CODE (purpose) == FIELD_DECL);
	  cref = build3 (COMPONENT_REF, TREE_TYPE (purpose),
			 unshare_expr (object), purpose, NULL_TREE);
      if (TREE_CODE (value) == CONSTRUCTOR
	  && TREE_CODE (TREE_TYPE (value)) != VECTOR_TYPE)
	gimplify_init_ctor_eval (cref, CONSTRUCTOR_ELTS (value),
				 pre_p, cleared);
      else
	{
	  tree init = build2 (INIT_EXPR, TREE_TYPE (cref), cref, value);
	  gimplify_and_add (init, pre_p);
/* Return the appropriate RHS predicate for this LHS.  */
Andrew MacLeod's avatar
Andrew MacLeod committed
gimple_predicate
  if (is_gimple_reg (lhs))
    return is_gimple_reg_rhs_or_call;
    return is_gimple_mem_rhs_or_call;
/* Gimplify a C99 compound literal expression.  This just means adding
   the DECL_EXPR before the current statement and using its anonymous
   decl instead.  */

static enum gimplify_status
gimplify_compound_literal_expr (tree *expr_p, gimple_seq *pre_p,
{
  tree decl_s = COMPOUND_LITERAL_EXPR_DECL_EXPR (*expr_p);
  tree decl = DECL_EXPR_DECL (decl_s);
  /* Mark the decl as addressable if the compound literal
     expression is addressable now, otherwise it is marked too late
     after we gimplify the initialization expression.  */
  if (TREE_ADDRESSABLE (*expr_p))
    TREE_ADDRESSABLE (decl) = 1;
  /* Otherwise, if we don't need an lvalue and have a literal directly
     substitute it.  Check if it matches the gimple predicate, as
     otherwise we'd generate a new temporary, and we can as well just
     use the decl we already have.  */
  else if (!TREE_ADDRESSABLE (decl)
	   && init
	   && (fallback & fb_lvalue) == 0
	   && gimple_test_f (init))
    {
      *expr_p = init;
      return GS_OK;
    }

  /* Preliminarily mark non-addressed complex variables as eligible
     for promotion to gimple registers.  We'll transform their uses
     as we find them.  */
  if ((TREE_CODE (TREE_TYPE (decl)) == COMPLEX_TYPE
       || TREE_CODE (TREE_TYPE (decl)) == VECTOR_TYPE)
      && !TREE_THIS_VOLATILE (decl)
      && !needs_to_live_in_memory (decl))
    DECL_GIMPLE_REG_P (decl) = 1;

  /* If the decl is not addressable, then it is being used in some
     expression or on the right hand side of a statement, and it can
     be put into a readonly data section.  */
  if (!TREE_ADDRESSABLE (decl) && (fallback & fb_lvalue) == 0)
    TREE_READONLY (decl) = 1;

  /* This decl isn't mentioned in the enclosing block, so add it to the
     list of temps.  FIXME it seems a bit of a kludge to say that
     anonymous artificial vars aren't pushed, but everything else is.  */
  if (DECL_NAME (decl) == NULL_TREE && !DECL_SEEN_IN_BIND_EXPR_P (decl))
    gimple_add_tmp_var (decl);

  gimplify_and_add (decl_s, pre_p);
  *expr_p = decl;
  return GS_OK;
}

/* Optimize embedded COMPOUND_LITERAL_EXPRs within a CONSTRUCTOR,
   return a new CONSTRUCTOR if something changed.  */

static tree
optimize_compound_literals_in_ctor (tree orig_ctor)
{
  tree ctor = orig_ctor;
  vec<constructor_elt, va_gc> *elts = CONSTRUCTOR_ELTS (ctor);
  unsigned int idx, num = vec_safe_length (elts);

  for (idx = 0; idx < num; idx++)
    {
      tree newval = value;
      if (TREE_CODE (value) == CONSTRUCTOR)
	newval = optimize_compound_literals_in_ctor (value);
      else if (TREE_CODE (value) == COMPOUND_LITERAL_EXPR)
	{
	  tree decl_s = COMPOUND_LITERAL_EXPR_DECL_EXPR (value);
	  tree decl = DECL_EXPR_DECL (decl_s);
	  tree init = DECL_INITIAL (decl);

	  if (!TREE_ADDRESSABLE (value)
	      && !TREE_ADDRESSABLE (decl)
	      && init
	      && TREE_CODE (init) == CONSTRUCTOR)
	    newval = optimize_compound_literals_in_ctor (init);
	}
      if (newval == value)
	continue;

      if (ctor == orig_ctor)
	{
	  ctor = copy_node (orig_ctor);
	  CONSTRUCTOR_ELTS (ctor) = vec_safe_copy (elts);
	  elts = CONSTRUCTOR_ELTS (ctor);
	}
/* 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.

   If NOTIFY_TEMP_CREATION is true, do not gimplify, just return
   GS_ERROR if we would have to create a temporary when gimplifying
   this constructor.  Otherwise, return GS_OK.

   If NOTIFY_TEMP_CREATION is false, just do the gimplification.  */
gimplify_init_constructor (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
			   bool want_value, bool notify_temp_creation)
  gcc_assert (TREE_CODE (TREE_OPERAND (*expr_p, 1)) == CONSTRUCTOR);
      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);
  ctor = TREE_OPERAND (*expr_p, 1) =
    optimize_compound_literals_in_ctor (TREE_OPERAND (*expr_p, 1));
  type = TREE_TYPE (ctor);
  elts = CONSTRUCTOR_ELTS (ctor);
  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_ctor_elements, num_nonzero_elements;
	bool cleared, complete_p, valid_const_initializer;

	/* 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.  */
	/* Fetch information about the constructor to direct later processing.
	   We might want to make static versions of it in various cases, and
	   can only do so if it known to be a valid constant initializer.  */
	valid_const_initializer
	  = categorize_ctor_elements (ctor, &num_nonzero_elements,
				      &num_ctor_elements, &complete_p);

	/* If a const aggregate variable is being initialized, then it
	   should never be a lose to promote the variable to be static.  */
	    && TREE_CODE (object) == VAR_DECL
	    && (flag_merge_constants >= 2 || !TREE_ADDRESSABLE (object)))
	    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 at 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, 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.  */

	if (int_size_in_bytes (TREE_TYPE (ctor)) < 0)
	  /* store_constructor will ignore the clearing of variable-sized
	     objects.  Initializers for such objects must explicitly set
	     every field that needs to be set.  */
	  cleared = false;
	else if (!complete_p && !CONSTRUCTOR_NO_CLEARING (ctor))
	  /* If the constructor isn't complete, clear the whole object
	     beforehand, unless CONSTRUCTOR_NO_CLEARING is set on it.

	     ??? This ought not to 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 if (num_ctor_elements - num_nonzero_elements
		 > CLEAR_RATIO (optimize_function_for_speed_p (cfun))
		 && num_nonzero_elements < num_ctor_elements / 4)
	  /* If there are "lots" of zeros, it's more efficient to clear
	     the memory and then set the nonzero elements.  */
	/* 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.  Don't do this
	   for sparse arrays, though, as it's more efficient to follow
	   the standard CONSTRUCTOR behavior of memset followed by
	   individual element initialization.  Also don't do this for small
	   all-zero initializers (which aren't big enough to merit
	   clearing), and don't try to make bitwise copies of
Ilya Enkovich's avatar
Ilya Enkovich committed
	   TREE_ADDRESSABLE types.

	   We cannot apply such transformation when compiling chkp static
	   initializer because creation of initializer image in the memory
	   will require static initialization of bounds for it.  It should
	   result in another gimplification of similar initializer and we
	   may fall into infinite loop.  */
	if (valid_const_initializer
	    && !(cleared || num_nonzero_elements == 0)
Ilya Enkovich's avatar
Ilya Enkovich committed
	    && !TREE_ADDRESSABLE (type)
	    && (!current_function_decl
		|| !lookup_attribute ("chkp ctor",
				      DECL_ATTRIBUTES (current_function_decl))))
	  {
	    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);
	      }