Skip to content
Snippets Groups Projects
gimplify.c 226 KiB
Newer Older
/* Tree lowering pass.  This pass converts the GENERIC functions-as-trees
   tree representation into the GIMPLE form.
   Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008
   Major work done by Sebastian Pop <s.pop@laposte.net>,
   Diego Novillo <dnovillo@redhat.com> and Jason Merrill <jason@redhat.com>.

This file is part of GCC.

GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.

GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */

#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
#include "rtl.h"
#include "varray.h"
#include "gimple.h"
#include "tree-iterator.h"
#include "tree-inline.h"
#include "diagnostic.h"
#include "langhooks.h"
#include "langhooks-def.h"
#include "tree-flow.h"
#include "timevar.h"
#include "except.h"
#include "hashtab.h"
#include "flags.h"
#include "real.h"
#include "function.h"
#include "output.h"
#include "expr.h"
#include "ggc.h"
#include "target.h"
Diego Novillo's avatar
Diego Novillo committed
#include "optabs.h"
#include "pointer-set.h"
#include "splay-tree.h"
#include "vec.h"
#include "gimple.h"
Diego Novillo's avatar
Diego Novillo committed

enum gimplify_omp_var_data
{
  GOVD_SEEN = 1,
  GOVD_EXPLICIT = 2,
  GOVD_SHARED = 4,
  GOVD_PRIVATE = 8,
  GOVD_FIRSTPRIVATE = 16,
  GOVD_LASTPRIVATE = 32,
  GOVD_REDUCTION = 64,
  GOVD_LOCAL = 128,
  GOVD_DEBUG_PRIVATE = 256,
  GOVD_PRIVATE_OUTER_REF = 512,
Diego Novillo's avatar
Diego Novillo committed
  GOVD_DATA_SHARE_CLASS = (GOVD_SHARED | GOVD_PRIVATE | GOVD_FIRSTPRIVATE
			   | GOVD_LASTPRIVATE | GOVD_REDUCTION | GOVD_LOCAL)
};

enum omp_region_type
{
  ORT_WORKSHARE = 0,
  ORT_TASK = 1,
  ORT_PARALLEL = 2,
  ORT_COMBINED_PARALLEL = 3
};

Diego Novillo's avatar
Diego Novillo committed
struct gimplify_omp_ctx
Diego Novillo's avatar
Diego Novillo committed
  struct gimplify_omp_ctx *outer_context;
  splay_tree variables;
  struct pointer_set_t *privatized_types;
  location_t location;
  enum omp_clause_default_kind default_kind;
  enum omp_region_type region_type;
Diego Novillo's avatar
Diego Novillo committed
};

static struct gimplify_ctx *gimplify_ctxp;
static struct gimplify_omp_ctx *gimplify_omp_ctxp;


/* Formal (expression) temporary table handling: Multiple occurrences of
   the same scalar expression are evaluated into the same temporary.  */

typedef struct gimple_temp_hash_elt
{
  tree val;   /* Key */
  tree temp;  /* Value */
} elt_t;

static enum gimplify_status gimplify_compound_expr (tree *, gimple_seq *, bool);
/* Mark X addressable.  Unlike the langhook we expect X to be in gimple
   form and we don't do any syntax checking.  */
static void
mark_addressable (tree x)
{
  while (handled_component_p (x))
    x = TREE_OPERAND (x, 0);
  if (TREE_CODE (x) != VAR_DECL && TREE_CODE (x) != PARM_DECL)
    return ;
  TREE_ADDRESSABLE (x) = 1;
}
/* Return a hash value for a formal temporary table entry.  */

static hashval_t
gimple_tree_hash (const void *p)
{
  tree t = ((const elt_t *) p)->val;
  return iterative_hash_expr (t, 0);
}

/* Compare two formal temporary table entries.  */

static int
gimple_tree_eq (const void *p1, const void *p2)
{
  tree t1 = ((const elt_t *) p1)->val;
  tree t2 = ((const elt_t *) p2)->val;
  enum tree_code code = TREE_CODE (t1);

  if (TREE_CODE (t2) != code
      || TREE_TYPE (t1) != TREE_TYPE (t2))
    return 0;

  if (!operand_equal_p (t1, t2, 0))
    return 0;

  /* Only allow them to compare equal if they also hash equal; otherwise
     results are nondeterminate, and we fail bootstrap comparison.  */
  gcc_assert (gimple_tree_hash (p1) == gimple_tree_hash (p2));
/* Link gimple statement GS to the end of the sequence *SEQ_P.  If
   *SEQ_P is NULL, a new sequence is allocated.  This function is
   similar to gimple_seq_add_stmt, but does not scan the operands.
   During gimplification, we need to manipulate statement sequences
   before the def/use vectors have been constructed.  */

static void
gimplify_seq_add_stmt (gimple_seq *seq_p, gimple gs)
{
  gimple_stmt_iterator si;

  if (gs == NULL)
    return;

  if (*seq_p == NULL)
    *seq_p = gimple_seq_alloc ();

  si = gsi_last (*seq_p);

  gsi_insert_after_without_update (&si, gs, GSI_NEW_STMT);
}

/* Append sequence SRC to the end of sequence *DST_P.  If *DST_P is
   NULL, a new sequence is allocated.   This function is
   similar to gimple_seq_add_seq, but does not scan the operands.
   During gimplification, we need to manipulate statement sequences
   before the def/use vectors have been constructed.  */

static void
gimplify_seq_add_seq (gimple_seq *dst_p, gimple_seq src)
{
  gimple_stmt_iterator si;

  if (src == NULL)
    return;

  if (*dst_p == NULL)
    *dst_p = gimple_seq_alloc ();

  si = gsi_last (*dst_p);
  gsi_insert_seq_after_without_update (&si, src, GSI_NEW_STMT);
}

/* Set up a context for the gimplifier.  */

void
push_gimplify_context (struct gimplify_ctx *c)
  memset (c, '\0', sizeof (*c));
Diego Novillo's avatar
Diego Novillo committed
  c->prev_context = gimplify_ctxp;
  gimplify_ctxp = c;
}

/* Tear down a context for the gimplifier.  If BODY is non-null, then
   put the temporaries into the outer BIND_EXPR.  Otherwise, put them
   in the local_decls.

   BODY is not a sequence, but the first tuple in a sequence.  */
pop_gimplify_context (gimple body)
Diego Novillo's avatar
Diego Novillo committed
  struct gimplify_ctx *c = gimplify_ctxp;
  gcc_assert (c && (c->bind_expr_stack == NULL
		    || VEC_empty (gimple, c->bind_expr_stack)));
  VEC_free (gimple, heap, c->bind_expr_stack);
Diego Novillo's avatar
Diego Novillo committed
  gimplify_ctxp = c->prev_context;
Diego Novillo's avatar
Diego Novillo committed
  for (t = c->temps; t ; t = TREE_CHAIN (t))
    DECL_GIMPLE_FORMAL_TEMP_P (t) = 0;

    declare_vars (c->temps, body, false);
Diego Novillo's avatar
Diego Novillo committed
    record_vars (c->temps);
Diego Novillo's avatar
Diego Novillo committed
    htab_delete (c->temp_htab);
gimple_push_bind_expr (gimple gimple_bind)
  if (gimplify_ctxp->bind_expr_stack == NULL)
    gimplify_ctxp->bind_expr_stack = VEC_alloc (gimple, heap, 8);
  VEC_safe_push (gimple, heap, gimplify_ctxp->bind_expr_stack, gimple_bind);
gimple_pop_bind_expr (void)
{
  VEC_pop (gimple, gimplify_ctxp->bind_expr_stack);
gimple_current_bind_expr (void)
{
  return VEC_last (gimple, gimplify_ctxp->bind_expr_stack);
}

/* Return the stack GIMPLE_BINDs created during gimplification.  */

VEC(gimple, heap) *
gimple_bind_expr_stack (void)
{
  return gimplify_ctxp->bind_expr_stack;
}

/* Returns true iff there is a COND_EXPR between us and the innermost
   CLEANUP_POINT_EXPR.  This info is used by gimple_push_cleanup.  */

static bool
gimple_conditional_context (void)
{
  return gimplify_ctxp->conditions > 0;
}

/* Note that we've entered a COND_EXPR.  */

static void
gimple_push_condition (void)
{
    gcc_assert (gimple_seq_empty_p (gimplify_ctxp->conditional_cleanups));
  ++(gimplify_ctxp->conditions);
}

/* Note that we've left a COND_EXPR.  If we're back at unconditional scope
   now, add any conditional cleanups we've seen to the prequeue.  */

static void
gimple_pop_condition (gimple_seq *pre_p)
{
  int conds = --(gimplify_ctxp->conditions);
      gimplify_seq_add_seq (pre_p, gimplify_ctxp->conditional_cleanups);
      gimplify_ctxp->conditional_cleanups = NULL;
Diego Novillo's avatar
Diego Novillo committed
/* A stable comparison routine for use with splay trees and DECLs.  */

static int
splay_tree_compare_decl_uid (splay_tree_key xa, splay_tree_key xb)
{
  tree a = (tree) xa;
  tree b = (tree) xb;

  return DECL_UID (a) - DECL_UID (b);
}

/* Create a new omp construct that deals with variable remapping.  */

static struct gimplify_omp_ctx *
new_omp_context (enum omp_region_type region_type)
Diego Novillo's avatar
Diego Novillo committed
{
  struct gimplify_omp_ctx *c;

  c = XCNEW (struct gimplify_omp_ctx);
  c->outer_context = gimplify_omp_ctxp;
  c->variables = splay_tree_new (splay_tree_compare_decl_uid, 0, 0);
  c->privatized_types = pointer_set_create ();
  c->location = input_location;
  c->region_type = region_type;
  if (region_type != ORT_TASK)
    c->default_kind = OMP_CLAUSE_DEFAULT_SHARED;
  else
    c->default_kind = OMP_CLAUSE_DEFAULT_UNSPECIFIED;
Diego Novillo's avatar
Diego Novillo committed

  return c;
}

/* Destroy an omp construct that deals with variable remapping.  */

static void
delete_omp_context (struct gimplify_omp_ctx *c)
{
  splay_tree_delete (c->variables);
  pointer_set_destroy (c->privatized_types);
  XDELETE (c);
}

static void omp_add_variable (struct gimplify_omp_ctx *, tree, unsigned int);
static bool omp_notice_variable (struct gimplify_omp_ctx *, tree, bool);

/* A subroutine of append_to_statement_list{,_force}.  T is not NULL.  */
append_to_statement_list_1 (tree t, tree *list_p)
{
  tree list = *list_p;
  tree_stmt_iterator i;

  if (!list)
    {
      if (t && TREE_CODE (t) == STATEMENT_LIST)
	{
	  *list_p = t;
	  return;
	}
      *list_p = list = alloc_stmt_list ();
    }

  i = tsi_last (list);
  tsi_link_after (&i, t, TSI_CONTINUE_LINKING);
}

/* Add T to the end of the list container pointed to by LIST_P.
   If T is an expression with no effects, it is ignored.  */

void
append_to_statement_list (tree t, tree *list_p)
{
  if (t && TREE_SIDE_EFFECTS (t))
    append_to_statement_list_1 (t, list_p);
}

/* Similar, but the statement is always added, regardless of side effects.  */

void
append_to_statement_list_force (tree t, tree *list_p)
{
  if (t != NULL_TREE)
    append_to_statement_list_1 (t, list_p);
/* Both gimplify the statement T and append it to *SEQ_P.  This function
   behaves exactly as gimplify_stmt, but you don't have to pass T as a
   reference.  */
gimplify_and_add (tree t, gimple_seq *seq_p)
{
  gimplify_stmt (&t, seq_p);
}

/* Gimplify statement T into sequence *SEQ_P, and return the first
   tuple in the sequence of generated tuples for this statement.
   Return NULL if gimplifying T produced no tuples.  */

static gimple
gimplify_and_return_first (tree t, gimple_seq *seq_p)
  gimple_stmt_iterator last = gsi_last (*seq_p);

  gimplify_and_add (t, seq_p);

  if (!gsi_end_p (last))
    {
      gsi_next (&last);
      return gsi_stmt (last);
    }
  else
    return gimple_seq_first_stmt (*seq_p);
/* Strip off a legitimate source ending from the input string NAME of
   length LEN.  Rather than having to know the names used by all of
   our front ends, we strip off an ending of a period followed by
   up to five characters.  (Java uses ".class".)  */

static inline void
remove_suffix (char *name, int len)
{
  int i;

  for (i = 2;  i < 8 && len > i;  i++)
    {
      if (name[len - i] == '.')
	{
	  name[len - i] = '\0';
	  break;
	}
    }
}

/* Subroutine for find_single_pointer_decl.  */

static tree
find_single_pointer_decl_1 (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
			    void *data)
{
  tree *pdecl = (tree *) data;

  /* We are only looking for pointers at the same level as the
     original tree; we must not look through any indirections.
     Returning anything other than NULL_TREE will cause the caller to
     not find a base.  */
  if (REFERENCE_CLASS_P (*tp))
    return *tp;

  if (DECL_P (*tp) && POINTER_TYPE_P (TREE_TYPE (*tp)))
    {
      if (*pdecl)
	{
	  /* We already found a pointer decl; return anything other
	     than NULL_TREE to unwind from walk_tree signalling that
	     we have a duplicate.  */
	  return *tp;
	}
      *pdecl = *tp;
    }

  return NULL_TREE;
}

/* Find the single DECL of pointer type in the tree T, used directly
   rather than via an indirection, and return it.  If there are zero
   or more than one such DECLs, return NULL.  */

static tree
find_single_pointer_decl (tree t)
{
  tree decl = NULL_TREE;

  if (walk_tree (&t, find_single_pointer_decl_1, &decl, NULL))
    {
      /* find_single_pointer_decl_1 returns a nonzero value, causing
	 walk_tree to return a nonzero value, to indicate that it
	 found more than one pointer DECL or that it found an
	 indirection.  */
/* Create a new temporary name with PREFIX.  Returns an identifier.  */

static GTY(()) unsigned int tmp_var_id_num;

create_tmp_var_name (const char *prefix)
{
  char *tmp_name;

  if (prefix)
    {
      char *preftmp = ASTRDUP (prefix);
      remove_suffix (preftmp, strlen (preftmp));
      prefix = preftmp;
    }

  ASM_FORMAT_PRIVATE_NAME (tmp_name, prefix ? prefix : "T", tmp_var_id_num++);
  return get_identifier (tmp_name);
}


/* Create a new temporary variable declaration of type TYPE.
   Does NOT push it into the current binding.  */

tree
create_tmp_var_raw (tree type, const char *prefix)
{
  tree tmp_var;
  tree new_type;

  /* Make the type of the variable writable.  */
  new_type = build_type_variant (type, 0, 0);
  TYPE_ATTRIBUTES (new_type) = TYPE_ATTRIBUTES (type);

  tmp_var = build_decl (VAR_DECL, prefix ? create_tmp_var_name (prefix) : NULL,
			type);

  /* The variable was declared by the compiler.  */
  DECL_ARTIFICIAL (tmp_var) = 1;
  /* And we don't want debug info for it.  */
  DECL_IGNORED_P (tmp_var) = 1;

  /* Make the variable writable.  */
  TREE_READONLY (tmp_var) = 0;

  DECL_EXTERNAL (tmp_var) = 0;
  TREE_STATIC (tmp_var) = 0;
  TREE_USED (tmp_var) = 1;

  return tmp_var;
}

/* Create a new temporary variable declaration of type TYPE.  DOES push the
   variable into the current binding.  Further, assume that this is called
   only from gimplification or optimization, at which point the creation of
   certain types are bugs.  */

tree
create_tmp_var (tree type, const char *prefix)
{
  tree tmp_var;

  /* We don't allow types that are addressable (meaning we can't make copies),
     or incomplete.  We also used to reject every variable size objects here,
     but now support those for which a constant upper bound can be obtained.
     The processing for variable sizes is performed in gimple_add_tmp_var,
     point at which it really matters and possibly reached via paths not going
     through this function, e.g. after direct calls to create_tmp_var_raw.  */
  gcc_assert (!TREE_ADDRESSABLE (type) && COMPLETE_TYPE_P (type));

  tmp_var = create_tmp_var_raw (type, prefix);
  gimple_add_tmp_var (tmp_var);
  return tmp_var;
}

/* Create a temporary with a name derived from VAL.  Subroutine of
   lookup_tmp_var; nobody else should call this function.  */

static inline tree
create_tmp_from_val (tree val)
{
  return create_tmp_var (TREE_TYPE (val), get_name (val));
}

/* Create a temporary to hold the value of VAL.  If IS_FORMAL, try to reuse
   an existing expression temporary.  */

static tree
lookup_tmp_var (tree val, bool is_formal)
{
  /* If not optimizing, never really reuse a temporary.  local-alloc
     won't allocate any variable that is used in more than one basic
     block, which means it will go into memory, causing much extra
     work in reload and final and poorer code generation, outweighing
     the extra memory allocation here.  */
  if (!optimize || !is_formal || TREE_SIDE_EFFECTS (val))
    ret = create_tmp_from_val (val);
  else
    {
      elt_t elt, *elt_p;
      void **slot;

      elt.val = val;
      if (gimplify_ctxp->temp_htab == NULL)
        gimplify_ctxp->temp_htab
	  = htab_create (1000, gimple_tree_hash, gimple_tree_eq, free);
      slot = htab_find_slot (gimplify_ctxp->temp_htab, (void *)&elt, INSERT);
      if (*slot == NULL)
	{
	  elt_p = XNEW (elt_t);
	  elt_p->val = val;
	  elt_p->temp = ret = create_tmp_from_val (val);
	{
	  elt_p = (elt_t *) *slot;
          ret = elt_p->temp;
	}

  if (is_formal)
    DECL_GIMPLE_FORMAL_TEMP_P (ret) = 1;

  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);
}

/* Returns true iff T is a valid RHS for an assignment to a renamed
   user -- or front-end generated artificial -- variable.  */

static bool
is_gimple_reg_or_call_rhs (tree t)
{
  /* If the RHS of the MODIFY_EXPR may throw or make a nonlocal goto
     and the LHS is a user variable, then we need to introduce a formal
     temporary.  This way the optimizers can determine that the user
     variable is only modified if evaluation of the RHS does not throw.

     Don't force a temp of a non-renamable type; the copy could be
     arbitrarily expensive.  Instead we will generate a VDEF for
     the assignment.  */

  if (is_gimple_reg_type (TREE_TYPE (t))
      && ((TREE_CODE (t) == CALL_EXPR && TREE_SIDE_EFFECTS (t))
	  || tree_could_throw_p (t)))
    return false;

  return is_gimple_formal_tmp_or_call_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:

   1) The value of the unfactored expression represented by VAL will not
      change between the initialization and use of the temporary, and
   2) The temporary will not be otherwise modified.

   For instance, #1 means that this is inappropriate for SAVE_EXPR temps,
   and #2 means it is inappropriate for && temps.

   For other cases, use get_initialized_tmp_var instead.  */

static tree
internal_get_tmp_var (tree val, gimple_seq *pre_p, gimple_seq *post_p,
                      bool is_formal)
  /* 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);

  if (is_formal)
    {
      tree u = find_single_pointer_decl (val);

      if (u && TREE_CODE (u) == VAR_DECL && DECL_BASED_ON_RESTRICT_P (u))
	u = DECL_GET_RESTRICT_BASE (u);
      if (u && TYPE_RESTRICT (TREE_TYPE (u)))
	{
	  if (DECL_BASED_ON_RESTRICT_P (t))
	    gcc_assert (u == DECL_GET_RESTRICT_BASE (t));
	  else
	    {
	      DECL_BASED_ON_RESTRICT_P (t) = 1;
	      SET_DECL_RESTRICT_BASE (t, u);
	    }
	}
    }

  if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE
      || TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE)
    DECL_GIMPLE_REG_P (t) = 1;
  mod = build2 (INIT_EXPR, TREE_TYPE (t), t, unshare_expr (val));
  if (EXPR_HAS_LOCATION (val))
    SET_EXPR_LOCUS (mod, EXPR_LOCUS (val));
  else
    SET_EXPR_LOCATION (mod, input_location);
  /* gimplify_modify_expr might want to reduce this further.  */
  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.  */
  if (gimplify_ctxp->into_ssa)
    {
      gimple last = gimple_seq_last_stmt (*pre_p);
      t = gimple_get_lhs (last);
    }
/* Returns a formal temporary variable initialized with VAL.  PRE_P
   points to a sequence where side-effects needed to compute VAL should be
   stored.  */
get_formal_tmp_var (tree val, gimple_seq *pre_p)
{
  return internal_get_tmp_var (val, pre_p, NULL, true);
}

/* Returns a temporary variable initialized with VAL.  PRE_P and POST_P
   are as in gimplify_expr.  */

tree
get_initialized_tmp_var (tree val, gimple_seq *pre_p, gimple_seq *post_p)
{
  return internal_get_tmp_var (val, pre_p, post_p, false);
}

/* Declares all the variables in VARS in SCOPE.  If DEBUG_INFO is
   true, generate debug info for them; otherwise don't.  */
declare_vars (tree vars, gimple scope, bool debug_info)
{
  tree last = vars;
  if (last)
    {
      gcc_assert (gimple_code (scope) == GIMPLE_BIND);

      temps = nreverse (last);
      gcc_assert (!block || TREE_CODE (block) == BLOCK);
	  TREE_CHAIN (last) = gimple_bind_vars (scope);
	  gimple_bind_set_vars (scope, temps);
	}
      else
	{
	  /* We need to attach the nodes both to the BIND_EXPR and to its
	     associated BLOCK for debugging purposes.  The key point here
	     is that the BLOCK_VARS of the BIND_EXPR_BLOCK of a BIND_EXPR
	     is a subchain of the BIND_EXPR_VARS of the BIND_EXPR.  */
	  if (BLOCK_VARS (block))
	    BLOCK_VARS (block) = chainon (BLOCK_VARS (block), temps);
	  else
	    {
	      gimple_bind_set_vars (scope,
	      			    chainon (gimple_bind_vars (scope), temps));
/* For VAR a VAR_DECL of variable size, try to find a constant upper bound
   for the size and adjust DECL_SIZE/DECL_SIZE_UNIT accordingly.  Abort if
   no such upper bound can be obtained.  */

static void
force_constant_size (tree var)
{
  /* The only attempt we make is by querying the maximum size of objects
     of the variable's type.  */

  HOST_WIDE_INT max_size;

  gcc_assert (TREE_CODE (var) == VAR_DECL);

  max_size = max_int_size_in_bytes (TREE_TYPE (var));

  gcc_assert (max_size >= 0);

  DECL_SIZE_UNIT (var)
    = build_int_cst (TREE_TYPE (DECL_SIZE_UNIT (var)), max_size);
  DECL_SIZE (var)
    = build_int_cst (TREE_TYPE (DECL_SIZE (var)), max_size * BITS_PER_UNIT);
}

void
gimple_add_tmp_var (tree tmp)
{
  gcc_assert (!TREE_CHAIN (tmp) && !DECL_SEEN_IN_BIND_EXPR_P (tmp));
  /* Later processing assumes that the object size is constant, which might
     not be true at this point.  Force the use of a constant upper bound in
     this case.  */
  if (!host_integerp (DECL_SIZE_UNIT (tmp), 1))
    force_constant_size (tmp);

  DECL_CONTEXT (tmp) = current_function_decl;
  DECL_SEEN_IN_BIND_EXPR_P (tmp) = 1;

  if (gimplify_ctxp)
    {
      TREE_CHAIN (tmp) = gimplify_ctxp->temps;
      gimplify_ctxp->temps = tmp;
Diego Novillo's avatar
Diego Novillo committed

      /* Mark temporaries local within the nearest enclosing parallel.  */
      if (gimplify_omp_ctxp)
	{
	  struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp;
	  while (ctx && ctx->region_type == ORT_WORKSHARE)
Diego Novillo's avatar
Diego Novillo committed
	    ctx = ctx->outer_context;
	  if (ctx)
	    omp_add_variable (ctx, tmp, GOVD_LOCAL | GOVD_SEEN);
	}
    }
  else if (cfun)
    record_vars (tmp);
  else
    {
      gimple_seq body_seq;

      /* This case is for nested functions.  We need to expose the locals
	 they create.  */
      body_seq = gimple_body (current_function_decl);
      declare_vars (tmp, gimple_seq_first_stmt (body_seq), false);
    }
}

/* Determines whether to assign a location to the statement GS.  */

static bool
should_carry_location_p (gimple gs)
{
  /* Don't emit a line note for a label.  We particularly don't want to
     emit one for the break label, since it doesn't actually correspond
     to the beginning of the loop/switch.  */
  if (gimple_code (gs) == GIMPLE_LABEL)
    return false;

  return true;
tree_should_carry_location_p (const_tree stmt)
{
  /* Don't emit a line note for a label.  We particularly don't want to
     emit one for the break label, since it doesn't actually correspond
     to the beginning of the loop/switch.  */
  if (TREE_CODE (stmt) == LABEL_EXPR)
    return false;

  /* Do not annotate empty statements, since it confuses gcov.  */
  if (!TREE_SIDE_EFFECTS (stmt))
    return false;

  return true;
}

/* Return true if a location should not be emitted for this statement
   by annotate_one_with_location.  */

static inline bool
gimple_do_not_emit_location_p (gimple g)
{
  return gimple_plf (g, GF_PLF_1);
}

/* Mark statement G so a location will not be emitted by
   annotate_one_with_location.  */

static inline void
gimple_set_do_not_emit_location (gimple g)
{
  /* The PLF flags are initialized to 0 when a new tuple is created,
     so no need to initialize it anywhere.  */
  gimple_set_plf (g, GF_PLF_1, true);
}

/* Set the location for gimple statement GS to LOCUS.  */

static void
annotate_one_with_location (gimple gs, location_t location)
{
  if (!gimple_has_location (gs) 
      && !gimple_do_not_emit_location_p (gs)
      && should_carry_location_p (gs))
    gimple_set_location (gs, location);
}

/* Same, but for tree T.  */

tree_annotate_one_with_location (tree t, location_t location)
  if (CAN_HAVE_LOCATION_P (t)
      && ! EXPR_HAS_LOCATION (t) && tree_should_carry_location_p (t))
    SET_EXPR_LOCATION (t, location);
}


/* Set LOCATION for all the statements after iterator GSI in sequence
   SEQ.  If GSI is pointing to the end of the sequence, start with the
   first statement in SEQ.  */

static void
annotate_all_with_location_after (gimple_seq seq, gimple_stmt_iterator gsi,
				  location_t location)
{
  if (gsi_end_p (gsi))
    gsi = gsi_start (seq);
  else
    gsi_next (&gsi);

  for (; !gsi_end_p (gsi); gsi_next (&gsi))
    annotate_one_with_location (gsi_stmt (gsi), location);
}


/* Set the location for all the statements in a sequence STMT_P to LOCUS.  */

void
annotate_all_with_location (gimple_seq stmt_p, location_t location)
{
  gimple_stmt_iterator i;

  if (gimple_seq_empty_p (stmt_p))
    return;

  for (i = gsi_start (stmt_p); !gsi_end_p (i); gsi_next (&i))
    {
      gimple gs = gsi_stmt (i);
      annotate_one_with_location (gs, location);
    }
/* Same, but for statement or statement list in *STMT_P.  */

tree_annotate_all_with_location (tree *stmt_p, location_t location)
{
  tree_stmt_iterator i;

  if (!*stmt_p)
    return;

  for (i = tsi_start (*stmt_p); !tsi_end_p (i); tsi_next (&i))
    {
      tree t = tsi_stmt (i);

      /* Assuming we've already been gimplified, we shouldn't
	  see nested chaining constructs anymore.  */
      gcc_assert (TREE_CODE (t) != STATEMENT_LIST
		  && TREE_CODE (t) != COMPOUND_EXPR);
      tree_annotate_one_with_location (t, location);
/* Similar to copy_tree_r() but do not copy SAVE_EXPR or TARGET_EXPR nodes.
   These nodes model computations that should only be done once.  If we