OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [gcc-4.2.2/] [gcc/] [tree-ssa.c] - Diff between revs 154 and 816

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 154 Rev 816
/* Miscellaneous SSA utility functions.
/* Miscellaneous SSA utility functions.
   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
 
 
This file is part of GCC.
This file is part of GCC.
 
 
GCC is free software; you can redistribute it and/or modify
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
the Free Software Foundation; either version 3, or (at your option)
any later version.
any later version.
 
 
GCC is distributed in the hope that it will be useful,
GCC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
GNU General Public License for more details.
 
 
You should have received a copy of the GNU General Public License
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3.  If not see
along with GCC; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */
<http://www.gnu.org/licenses/>.  */
 
 
#include "config.h"
#include "config.h"
#include "system.h"
#include "system.h"
#include "coretypes.h"
#include "coretypes.h"
#include "tm.h"
#include "tm.h"
#include "tree.h"
#include "tree.h"
#include "flags.h"
#include "flags.h"
#include "rtl.h"
#include "rtl.h"
#include "tm_p.h"
#include "tm_p.h"
#include "ggc.h"
#include "ggc.h"
#include "langhooks.h"
#include "langhooks.h"
#include "hard-reg-set.h"
#include "hard-reg-set.h"
#include "basic-block.h"
#include "basic-block.h"
#include "output.h"
#include "output.h"
#include "expr.h"
#include "expr.h"
#include "function.h"
#include "function.h"
#include "diagnostic.h"
#include "diagnostic.h"
#include "bitmap.h"
#include "bitmap.h"
#include "pointer-set.h"
#include "pointer-set.h"
#include "tree-flow.h"
#include "tree-flow.h"
#include "tree-gimple.h"
#include "tree-gimple.h"
#include "tree-inline.h"
#include "tree-inline.h"
#include "varray.h"
#include "varray.h"
#include "timevar.h"
#include "timevar.h"
#include "hashtab.h"
#include "hashtab.h"
#include "tree-dump.h"
#include "tree-dump.h"
#include "tree-pass.h"
#include "tree-pass.h"
#include "toplev.h"
#include "toplev.h"
 
 
/* Remove the corresponding arguments from the PHI nodes in E's
/* Remove the corresponding arguments from the PHI nodes in E's
   destination block and redirect it to DEST.  Return redirected edge.
   destination block and redirect it to DEST.  Return redirected edge.
   The list of removed arguments is stored in PENDING_STMT (e).  */
   The list of removed arguments is stored in PENDING_STMT (e).  */
 
 
edge
edge
ssa_redirect_edge (edge e, basic_block dest)
ssa_redirect_edge (edge e, basic_block dest)
{
{
  tree phi;
  tree phi;
  tree list = NULL, *last = &list;
  tree list = NULL, *last = &list;
  tree src, dst, node;
  tree src, dst, node;
 
 
  /* Remove the appropriate PHI arguments in E's destination block.  */
  /* Remove the appropriate PHI arguments in E's destination block.  */
  for (phi = phi_nodes (e->dest); phi; phi = PHI_CHAIN (phi))
  for (phi = phi_nodes (e->dest); phi; phi = PHI_CHAIN (phi))
    {
    {
      if (PHI_ARG_DEF (phi, e->dest_idx) == NULL_TREE)
      if (PHI_ARG_DEF (phi, e->dest_idx) == NULL_TREE)
        continue;
        continue;
 
 
      src = PHI_ARG_DEF (phi, e->dest_idx);
      src = PHI_ARG_DEF (phi, e->dest_idx);
      dst = PHI_RESULT (phi);
      dst = PHI_RESULT (phi);
      node = build_tree_list (dst, src);
      node = build_tree_list (dst, src);
      *last = node;
      *last = node;
      last = &TREE_CHAIN (node);
      last = &TREE_CHAIN (node);
    }
    }
 
 
  e = redirect_edge_succ_nodup (e, dest);
  e = redirect_edge_succ_nodup (e, dest);
  PENDING_STMT (e) = list;
  PENDING_STMT (e) = list;
 
 
  return e;
  return e;
}
}
 
 
/* Add PHI arguments queued in PENDINT_STMT list on edge E to edge
/* Add PHI arguments queued in PENDINT_STMT list on edge E to edge
   E->dest.  */
   E->dest.  */
 
 
void
void
flush_pending_stmts (edge e)
flush_pending_stmts (edge e)
{
{
  tree phi, arg;
  tree phi, arg;
 
 
  if (!PENDING_STMT (e))
  if (!PENDING_STMT (e))
    return;
    return;
 
 
  for (phi = phi_nodes (e->dest), arg = PENDING_STMT (e);
  for (phi = phi_nodes (e->dest), arg = PENDING_STMT (e);
       phi;
       phi;
       phi = PHI_CHAIN (phi), arg = TREE_CHAIN (arg))
       phi = PHI_CHAIN (phi), arg = TREE_CHAIN (arg))
    {
    {
      tree def = TREE_VALUE (arg);
      tree def = TREE_VALUE (arg);
      add_phi_arg (phi, def, e);
      add_phi_arg (phi, def, e);
    }
    }
 
 
  PENDING_STMT (e) = NULL;
  PENDING_STMT (e) = NULL;
}
}
 
 
/* Return true if SSA_NAME is malformed and mark it visited.
/* Return true if SSA_NAME is malformed and mark it visited.
 
 
   IS_VIRTUAL is true if this SSA_NAME was found inside a virtual
   IS_VIRTUAL is true if this SSA_NAME was found inside a virtual
      operand.  */
      operand.  */
 
 
static bool
static bool
verify_ssa_name (tree ssa_name, bool is_virtual)
verify_ssa_name (tree ssa_name, bool is_virtual)
{
{
  if (TREE_CODE (ssa_name) != SSA_NAME)
  if (TREE_CODE (ssa_name) != SSA_NAME)
    {
    {
      error ("expected an SSA_NAME object");
      error ("expected an SSA_NAME object");
      return true;
      return true;
    }
    }
 
 
  if (TREE_TYPE (ssa_name) != TREE_TYPE (SSA_NAME_VAR (ssa_name)))
  if (TREE_TYPE (ssa_name) != TREE_TYPE (SSA_NAME_VAR (ssa_name)))
    {
    {
      error ("type mismatch between an SSA_NAME and its symbol");
      error ("type mismatch between an SSA_NAME and its symbol");
      return true;
      return true;
    }
    }
 
 
  if (SSA_NAME_IN_FREE_LIST (ssa_name))
  if (SSA_NAME_IN_FREE_LIST (ssa_name))
    {
    {
      error ("found an SSA_NAME that had been released into the free pool");
      error ("found an SSA_NAME that had been released into the free pool");
      return true;
      return true;
    }
    }
 
 
  if (is_virtual && is_gimple_reg (ssa_name))
  if (is_virtual && is_gimple_reg (ssa_name))
    {
    {
      error ("found a virtual definition for a GIMPLE register");
      error ("found a virtual definition for a GIMPLE register");
      return true;
      return true;
    }
    }
 
 
  if (!is_virtual && !is_gimple_reg (ssa_name))
  if (!is_virtual && !is_gimple_reg (ssa_name))
    {
    {
      error ("found a real definition for a non-register");
      error ("found a real definition for a non-register");
      return true;
      return true;
    }
    }
 
 
  if (is_virtual && var_ann (SSA_NAME_VAR (ssa_name))
  if (is_virtual && var_ann (SSA_NAME_VAR (ssa_name))
      && get_subvars_for_var (SSA_NAME_VAR (ssa_name)) != NULL)
      && get_subvars_for_var (SSA_NAME_VAR (ssa_name)) != NULL)
    {
    {
      error ("found real variable when subvariables should have appeared");
      error ("found real variable when subvariables should have appeared");
      return true;
      return true;
    }
    }
 
 
  return false;
  return false;
}
}
 
 
 
 
/* Return true if the definition of SSA_NAME at block BB is malformed.
/* Return true if the definition of SSA_NAME at block BB is malformed.
 
 
   STMT is the statement where SSA_NAME is created.
   STMT is the statement where SSA_NAME is created.
 
 
   DEFINITION_BLOCK is an array of basic blocks indexed by SSA_NAME
   DEFINITION_BLOCK is an array of basic blocks indexed by SSA_NAME
      version numbers.  If DEFINITION_BLOCK[SSA_NAME_VERSION] is set,
      version numbers.  If DEFINITION_BLOCK[SSA_NAME_VERSION] is set,
      it means that the block in that array slot contains the
      it means that the block in that array slot contains the
      definition of SSA_NAME.
      definition of SSA_NAME.
 
 
   IS_VIRTUAL is true if SSA_NAME is created by a V_MAY_DEF or a
   IS_VIRTUAL is true if SSA_NAME is created by a V_MAY_DEF or a
      V_MUST_DEF.  */
      V_MUST_DEF.  */
 
 
static bool
static bool
verify_def (basic_block bb, basic_block *definition_block, tree ssa_name,
verify_def (basic_block bb, basic_block *definition_block, tree ssa_name,
            tree stmt, bool is_virtual)
            tree stmt, bool is_virtual)
{
{
  if (verify_ssa_name (ssa_name, is_virtual))
  if (verify_ssa_name (ssa_name, is_virtual))
    goto err;
    goto err;
 
 
  if (definition_block[SSA_NAME_VERSION (ssa_name)])
  if (definition_block[SSA_NAME_VERSION (ssa_name)])
    {
    {
      error ("SSA_NAME created in two different blocks %i and %i",
      error ("SSA_NAME created in two different blocks %i and %i",
             definition_block[SSA_NAME_VERSION (ssa_name)]->index, bb->index);
             definition_block[SSA_NAME_VERSION (ssa_name)]->index, bb->index);
      goto err;
      goto err;
    }
    }
 
 
  definition_block[SSA_NAME_VERSION (ssa_name)] = bb;
  definition_block[SSA_NAME_VERSION (ssa_name)] = bb;
 
 
  if (SSA_NAME_DEF_STMT (ssa_name) != stmt)
  if (SSA_NAME_DEF_STMT (ssa_name) != stmt)
    {
    {
      error ("SSA_NAME_DEF_STMT is wrong");
      error ("SSA_NAME_DEF_STMT is wrong");
      fprintf (stderr, "Expected definition statement:\n");
      fprintf (stderr, "Expected definition statement:\n");
      print_generic_stmt (stderr, SSA_NAME_DEF_STMT (ssa_name), TDF_VOPS);
      print_generic_stmt (stderr, SSA_NAME_DEF_STMT (ssa_name), TDF_VOPS);
      fprintf (stderr, "\nActual definition statement:\n");
      fprintf (stderr, "\nActual definition statement:\n");
      print_generic_stmt (stderr, stmt, TDF_VOPS);
      print_generic_stmt (stderr, stmt, TDF_VOPS);
      goto err;
      goto err;
    }
    }
 
 
  return false;
  return false;
 
 
err:
err:
  fprintf (stderr, "while verifying SSA_NAME ");
  fprintf (stderr, "while verifying SSA_NAME ");
  print_generic_expr (stderr, ssa_name, 0);
  print_generic_expr (stderr, ssa_name, 0);
  fprintf (stderr, " in statement\n");
  fprintf (stderr, " in statement\n");
  print_generic_stmt (stderr, stmt, TDF_VOPS);
  print_generic_stmt (stderr, stmt, TDF_VOPS);
 
 
  return true;
  return true;
}
}
 
 
 
 
/* Return true if the use of SSA_NAME at statement STMT in block BB is
/* Return true if the use of SSA_NAME at statement STMT in block BB is
   malformed.
   malformed.
 
 
   DEF_BB is the block where SSA_NAME was found to be created.
   DEF_BB is the block where SSA_NAME was found to be created.
 
 
   IDOM contains immediate dominator information for the flowgraph.
   IDOM contains immediate dominator information for the flowgraph.
 
 
   CHECK_ABNORMAL is true if the caller wants to check whether this use
   CHECK_ABNORMAL is true if the caller wants to check whether this use
      is flowing through an abnormal edge (only used when checking PHI
      is flowing through an abnormal edge (only used when checking PHI
      arguments).
      arguments).
 
 
   IS_VIRTUAL is true if SSA_NAME is created by a V_MAY_DEF or a
   IS_VIRTUAL is true if SSA_NAME is created by a V_MAY_DEF or a
      V_MUST_DEF.
      V_MUST_DEF.
 
 
   If NAMES_DEFINED_IN_BB is not NULL, it contains a bitmap of ssa names
   If NAMES_DEFINED_IN_BB is not NULL, it contains a bitmap of ssa names
     that are defined before STMT in basic block BB.  */
     that are defined before STMT in basic block BB.  */
 
 
static bool
static bool
verify_use (basic_block bb, basic_block def_bb, use_operand_p use_p,
verify_use (basic_block bb, basic_block def_bb, use_operand_p use_p,
            tree stmt, bool check_abnormal, bool is_virtual,
            tree stmt, bool check_abnormal, bool is_virtual,
            bitmap names_defined_in_bb)
            bitmap names_defined_in_bb)
{
{
  bool err = false;
  bool err = false;
  tree ssa_name = USE_FROM_PTR (use_p);
  tree ssa_name = USE_FROM_PTR (use_p);
 
 
  err = verify_ssa_name (ssa_name, is_virtual);
  err = verify_ssa_name (ssa_name, is_virtual);
 
 
  if (!TREE_VISITED (ssa_name))
  if (!TREE_VISITED (ssa_name))
    if (verify_imm_links (stderr, ssa_name))
    if (verify_imm_links (stderr, ssa_name))
      err = true;
      err = true;
 
 
  TREE_VISITED (ssa_name) = 1;
  TREE_VISITED (ssa_name) = 1;
 
 
  if (IS_EMPTY_STMT (SSA_NAME_DEF_STMT (ssa_name))
  if (IS_EMPTY_STMT (SSA_NAME_DEF_STMT (ssa_name))
      && default_def (SSA_NAME_VAR (ssa_name)) == ssa_name)
      && default_def (SSA_NAME_VAR (ssa_name)) == ssa_name)
    ; /* Default definitions have empty statements.  Nothing to do.  */
    ; /* Default definitions have empty statements.  Nothing to do.  */
  else if (!def_bb)
  else if (!def_bb)
    {
    {
      error ("missing definition");
      error ("missing definition");
      err = true;
      err = true;
    }
    }
  else if (bb != def_bb
  else if (bb != def_bb
           && !dominated_by_p (CDI_DOMINATORS, bb, def_bb))
           && !dominated_by_p (CDI_DOMINATORS, bb, def_bb))
    {
    {
      error ("definition in block %i does not dominate use in block %i",
      error ("definition in block %i does not dominate use in block %i",
             def_bb->index, bb->index);
             def_bb->index, bb->index);
      err = true;
      err = true;
    }
    }
  else if (bb == def_bb
  else if (bb == def_bb
           && names_defined_in_bb != NULL
           && names_defined_in_bb != NULL
           && !bitmap_bit_p (names_defined_in_bb, SSA_NAME_VERSION (ssa_name)))
           && !bitmap_bit_p (names_defined_in_bb, SSA_NAME_VERSION (ssa_name)))
    {
    {
      error ("definition in block %i follows the use", def_bb->index);
      error ("definition in block %i follows the use", def_bb->index);
      err = true;
      err = true;
    }
    }
 
 
  if (check_abnormal
  if (check_abnormal
      && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssa_name))
      && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssa_name))
    {
    {
      error ("SSA_NAME_OCCURS_IN_ABNORMAL_PHI should be set");
      error ("SSA_NAME_OCCURS_IN_ABNORMAL_PHI should be set");
      err = true;
      err = true;
    }
    }
 
 
  /* Make sure the use is in an appropriate list by checking the previous
  /* Make sure the use is in an appropriate list by checking the previous
     element to make sure it's the same.  */
     element to make sure it's the same.  */
  if (use_p->prev == NULL)
  if (use_p->prev == NULL)
    {
    {
      error ("no immediate_use list");
      error ("no immediate_use list");
      err = true;
      err = true;
    }
    }
  else
  else
    {
    {
      tree listvar ;
      tree listvar ;
      if (use_p->prev->use == NULL)
      if (use_p->prev->use == NULL)
        listvar = use_p->prev->stmt;
        listvar = use_p->prev->stmt;
      else
      else
        listvar = USE_FROM_PTR (use_p->prev);
        listvar = USE_FROM_PTR (use_p->prev);
      if (listvar != ssa_name)
      if (listvar != ssa_name)
        {
        {
          error ("wrong immediate use list");
          error ("wrong immediate use list");
          err = true;
          err = true;
        }
        }
    }
    }
 
 
  if (err)
  if (err)
    {
    {
      fprintf (stderr, "for SSA_NAME: ");
      fprintf (stderr, "for SSA_NAME: ");
      print_generic_expr (stderr, ssa_name, TDF_VOPS);
      print_generic_expr (stderr, ssa_name, TDF_VOPS);
      fprintf (stderr, " in statement:\n");
      fprintf (stderr, " in statement:\n");
      print_generic_stmt (stderr, stmt, TDF_VOPS);
      print_generic_stmt (stderr, stmt, TDF_VOPS);
    }
    }
 
 
  return err;
  return err;
}
}
 
 
 
 
/* Return true if any of the arguments for PHI node PHI at block BB is
/* Return true if any of the arguments for PHI node PHI at block BB is
   malformed.
   malformed.
 
 
   DEFINITION_BLOCK is an array of basic blocks indexed by SSA_NAME version
   DEFINITION_BLOCK is an array of basic blocks indexed by SSA_NAME version
      numbers.  If DEFINITION_BLOCK[SSA_NAME_VERSION] is set, it means that the
      numbers.  If DEFINITION_BLOCK[SSA_NAME_VERSION] is set, it means that the
      block in that array slot contains the definition of SSA_NAME.  */
      block in that array slot contains the definition of SSA_NAME.  */
 
 
static bool
static bool
verify_phi_args (tree phi, basic_block bb, basic_block *definition_block)
verify_phi_args (tree phi, basic_block bb, basic_block *definition_block)
{
{
  edge e;
  edge e;
  bool err = false;
  bool err = false;
  unsigned i, phi_num_args = PHI_NUM_ARGS (phi);
  unsigned i, phi_num_args = PHI_NUM_ARGS (phi);
 
 
  if (EDGE_COUNT (bb->preds) != phi_num_args)
  if (EDGE_COUNT (bb->preds) != phi_num_args)
    {
    {
      error ("incoming edge count does not match number of PHI arguments");
      error ("incoming edge count does not match number of PHI arguments");
      err = true;
      err = true;
      goto error;
      goto error;
    }
    }
 
 
  for (i = 0; i < phi_num_args; i++)
  for (i = 0; i < phi_num_args; i++)
    {
    {
      use_operand_p op_p = PHI_ARG_DEF_PTR (phi, i);
      use_operand_p op_p = PHI_ARG_DEF_PTR (phi, i);
      tree op = USE_FROM_PTR (op_p);
      tree op = USE_FROM_PTR (op_p);
 
 
 
 
      e = EDGE_PRED (bb, i);
      e = EDGE_PRED (bb, i);
 
 
      if (op == NULL_TREE)
      if (op == NULL_TREE)
        {
        {
          error ("PHI argument is missing for edge %d->%d",
          error ("PHI argument is missing for edge %d->%d",
                 e->src->index,
                 e->src->index,
                 e->dest->index);
                 e->dest->index);
          err = true;
          err = true;
          goto error;
          goto error;
        }
        }
 
 
      if (TREE_CODE (op) != SSA_NAME && !is_gimple_min_invariant (op))
      if (TREE_CODE (op) != SSA_NAME && !is_gimple_min_invariant (op))
        {
        {
          error ("PHI argument is not SSA_NAME, or invariant");
          error ("PHI argument is not SSA_NAME, or invariant");
          err = true;
          err = true;
        }
        }
 
 
      if (TREE_CODE (op) == SSA_NAME)
      if (TREE_CODE (op) == SSA_NAME)
        err = verify_use (e->src, definition_block[SSA_NAME_VERSION (op)], op_p,
        err = verify_use (e->src, definition_block[SSA_NAME_VERSION (op)], op_p,
                          phi, e->flags & EDGE_ABNORMAL,
                          phi, e->flags & EDGE_ABNORMAL,
                          !is_gimple_reg (PHI_RESULT (phi)),
                          !is_gimple_reg (PHI_RESULT (phi)),
                          NULL);
                          NULL);
 
 
      if (e->dest != bb)
      if (e->dest != bb)
        {
        {
          error ("wrong edge %d->%d for PHI argument",
          error ("wrong edge %d->%d for PHI argument",
                 e->src->index, e->dest->index);
                 e->src->index, e->dest->index);
          err = true;
          err = true;
        }
        }
 
 
      if (err)
      if (err)
        {
        {
          fprintf (stderr, "PHI argument\n");
          fprintf (stderr, "PHI argument\n");
          print_generic_stmt (stderr, op, TDF_VOPS);
          print_generic_stmt (stderr, op, TDF_VOPS);
          goto error;
          goto error;
        }
        }
    }
    }
 
 
error:
error:
  if (err)
  if (err)
    {
    {
      fprintf (stderr, "for PHI node\n");
      fprintf (stderr, "for PHI node\n");
      print_generic_stmt (stderr, phi, TDF_VOPS);
      print_generic_stmt (stderr, phi, TDF_VOPS);
    }
    }
 
 
 
 
  return err;
  return err;
}
}
 
 
 
 
static void
static void
verify_flow_insensitive_alias_info (void)
verify_flow_insensitive_alias_info (void)
{
{
  tree var;
  tree var;
  bitmap visited = BITMAP_ALLOC (NULL);
  bitmap visited = BITMAP_ALLOC (NULL);
  referenced_var_iterator rvi;
  referenced_var_iterator rvi;
 
 
  FOR_EACH_REFERENCED_VAR (var, rvi)
  FOR_EACH_REFERENCED_VAR (var, rvi)
    {
    {
      size_t j;
      size_t j;
      var_ann_t ann;
      var_ann_t ann;
      VEC(tree,gc) *may_aliases;
      VEC(tree,gc) *may_aliases;
      tree alias;
      tree alias;
 
 
      ann = var_ann (var);
      ann = var_ann (var);
      may_aliases = ann->may_aliases;
      may_aliases = ann->may_aliases;
 
 
      for (j = 0; VEC_iterate (tree, may_aliases, j, alias); j++)
      for (j = 0; VEC_iterate (tree, may_aliases, j, alias); j++)
        {
        {
          bitmap_set_bit (visited, DECL_UID (alias));
          bitmap_set_bit (visited, DECL_UID (alias));
 
 
          if (!may_be_aliased (alias))
          if (!may_be_aliased (alias))
            {
            {
              error ("non-addressable variable inside an alias set");
              error ("non-addressable variable inside an alias set");
              debug_variable (alias);
              debug_variable (alias);
              goto err;
              goto err;
            }
            }
        }
        }
    }
    }
 
 
  FOR_EACH_REFERENCED_VAR (var, rvi)
  FOR_EACH_REFERENCED_VAR (var, rvi)
    {
    {
      var_ann_t ann;
      var_ann_t ann;
      ann = var_ann (var);
      ann = var_ann (var);
 
 
      if (!MTAG_P (var)
      if (!MTAG_P (var)
          && ann->is_aliased
          && ann->is_aliased
          && !bitmap_bit_p (visited, DECL_UID (var)))
          && !bitmap_bit_p (visited, DECL_UID (var)))
        {
        {
          error ("addressable variable that is aliased but is not in any alias set");
          error ("addressable variable that is aliased but is not in any alias set");
          goto err;
          goto err;
        }
        }
    }
    }
 
 
  BITMAP_FREE (visited);
  BITMAP_FREE (visited);
  return;
  return;
 
 
err:
err:
  debug_variable (var);
  debug_variable (var);
  internal_error ("verify_flow_insensitive_alias_info failed");
  internal_error ("verify_flow_insensitive_alias_info failed");
}
}
 
 
 
 
static void
static void
verify_flow_sensitive_alias_info (void)
verify_flow_sensitive_alias_info (void)
{
{
  size_t i;
  size_t i;
  tree ptr;
  tree ptr;
 
 
  for (i = 1; i < num_ssa_names; i++)
  for (i = 1; i < num_ssa_names; i++)
    {
    {
      tree var;
      tree var;
      var_ann_t ann;
      var_ann_t ann;
      struct ptr_info_def *pi;
      struct ptr_info_def *pi;
 
 
 
 
      ptr = ssa_name (i);
      ptr = ssa_name (i);
      if (!ptr)
      if (!ptr)
        continue;
        continue;
 
 
      /* We only care for pointers that are actually referenced in the
      /* We only care for pointers that are actually referenced in the
         program.  */
         program.  */
      if (!POINTER_TYPE_P (TREE_TYPE (ptr)) || !TREE_VISITED (ptr))
      if (!POINTER_TYPE_P (TREE_TYPE (ptr)) || !TREE_VISITED (ptr))
        continue;
        continue;
 
 
      /* RESULT_DECL is special.  If it's a GIMPLE register, then it
      /* RESULT_DECL is special.  If it's a GIMPLE register, then it
         is only written-to only once in the return statement.
         is only written-to only once in the return statement.
         Otherwise, aggregate RESULT_DECLs may be written-to more than
         Otherwise, aggregate RESULT_DECLs may be written-to more than
         once in virtual operands.  */
         once in virtual operands.  */
      var = SSA_NAME_VAR (ptr);
      var = SSA_NAME_VAR (ptr);
      if (TREE_CODE (var) == RESULT_DECL
      if (TREE_CODE (var) == RESULT_DECL
          && is_gimple_reg (ptr))
          && is_gimple_reg (ptr))
        continue;
        continue;
 
 
      pi = SSA_NAME_PTR_INFO (ptr);
      pi = SSA_NAME_PTR_INFO (ptr);
      if (pi == NULL)
      if (pi == NULL)
        continue;
        continue;
 
 
      ann = var_ann (var);
      ann = var_ann (var);
      if (pi->is_dereferenced && !pi->name_mem_tag && !ann->symbol_mem_tag)
      if (pi->is_dereferenced && !pi->name_mem_tag && !ann->symbol_mem_tag)
        {
        {
          error ("dereferenced pointers should have a name or a symbol tag");
          error ("dereferenced pointers should have a name or a symbol tag");
          goto err;
          goto err;
        }
        }
 
 
      if (pi->name_mem_tag
      if (pi->name_mem_tag
          && (pi->pt_vars == NULL || bitmap_empty_p (pi->pt_vars)))
          && (pi->pt_vars == NULL || bitmap_empty_p (pi->pt_vars)))
        {
        {
          error ("pointers with a memory tag, should have points-to sets");
          error ("pointers with a memory tag, should have points-to sets");
          goto err;
          goto err;
        }
        }
 
 
      if (pi->value_escapes_p
      if (pi->value_escapes_p
          && pi->name_mem_tag
          && pi->name_mem_tag
          && !is_call_clobbered (pi->name_mem_tag))
          && !is_call_clobbered (pi->name_mem_tag))
        {
        {
          error ("pointer escapes but its name tag is not call-clobbered");
          error ("pointer escapes but its name tag is not call-clobbered");
          goto err;
          goto err;
        }
        }
    }
    }
 
 
  return;
  return;
 
 
err:
err:
  debug_variable (ptr);
  debug_variable (ptr);
  internal_error ("verify_flow_sensitive_alias_info failed");
  internal_error ("verify_flow_sensitive_alias_info failed");
}
}
 
 
DEF_VEC_P (bitmap);
DEF_VEC_P (bitmap);
DEF_VEC_ALLOC_P (bitmap,heap);
DEF_VEC_ALLOC_P (bitmap,heap);
 
 
/* Verify that all name tags have different points to sets.
/* Verify that all name tags have different points to sets.
   This algorithm takes advantage of the fact that every variable with the
   This algorithm takes advantage of the fact that every variable with the
   same name tag must have the same points-to set.
   same name tag must have the same points-to set.
   So we check a single variable for each name tag, and verify that its
   So we check a single variable for each name tag, and verify that its
   points-to set is different from every other points-to set for other name
   points-to set is different from every other points-to set for other name
   tags.
   tags.
 
 
   Additionally, given a pointer P_i with name tag NMT and symbol tag
   Additionally, given a pointer P_i with name tag NMT and symbol tag
   SMT, this function verified the alias set of SMT is a superset of
   SMT, this function verified the alias set of SMT is a superset of
   the alias set of NMT.  */
   the alias set of NMT.  */
 
 
static void
static void
verify_name_tags (void)
verify_name_tags (void)
{
{
  size_t i;
  size_t i;
  size_t j;
  size_t j;
  bitmap first, second;
  bitmap first, second;
  VEC(tree,heap) *name_tag_reps = NULL;
  VEC(tree,heap) *name_tag_reps = NULL;
  VEC(bitmap,heap) *pt_vars_for_reps = NULL;
  VEC(bitmap,heap) *pt_vars_for_reps = NULL;
  bitmap type_aliases = BITMAP_ALLOC (NULL);
  bitmap type_aliases = BITMAP_ALLOC (NULL);
 
 
  /* First we compute the name tag representatives and their points-to sets.  */
  /* First we compute the name tag representatives and their points-to sets.  */
  for (i = 0; i < num_ssa_names; i++)
  for (i = 0; i < num_ssa_names; i++)
    {
    {
      struct ptr_info_def *pi;
      struct ptr_info_def *pi;
      tree smt, ptr = ssa_name (i);
      tree smt, ptr = ssa_name (i);
 
 
      if (ptr == NULL_TREE)
      if (ptr == NULL_TREE)
        continue;
        continue;
 
 
      pi = SSA_NAME_PTR_INFO (ptr);
      pi = SSA_NAME_PTR_INFO (ptr);
 
 
      if (!TREE_VISITED (ptr)
      if (!TREE_VISITED (ptr)
          || !POINTER_TYPE_P (TREE_TYPE (ptr))
          || !POINTER_TYPE_P (TREE_TYPE (ptr))
          || !pi
          || !pi
          || !pi->name_mem_tag
          || !pi->name_mem_tag
          || TREE_VISITED (pi->name_mem_tag))
          || TREE_VISITED (pi->name_mem_tag))
        continue;
        continue;
 
 
      TREE_VISITED (pi->name_mem_tag) = 1;
      TREE_VISITED (pi->name_mem_tag) = 1;
 
 
      if (pi->pt_vars == NULL)
      if (pi->pt_vars == NULL)
        continue;
        continue;
 
 
      VEC_safe_push (tree, heap, name_tag_reps, ptr);
      VEC_safe_push (tree, heap, name_tag_reps, ptr);
      VEC_safe_push (bitmap, heap, pt_vars_for_reps, pi->pt_vars);
      VEC_safe_push (bitmap, heap, pt_vars_for_reps, pi->pt_vars);
 
 
      /* Verify that alias set of PTR's symbol tag is a superset of the
      /* Verify that alias set of PTR's symbol tag is a superset of the
         alias set of PTR's name tag.  */
         alias set of PTR's name tag.  */
      smt = var_ann (SSA_NAME_VAR (ptr))->symbol_mem_tag;
      smt = var_ann (SSA_NAME_VAR (ptr))->symbol_mem_tag;
      if (smt)
      if (smt)
        {
        {
          size_t i;
          size_t i;
          VEC(tree,gc) *aliases = var_ann (smt)->may_aliases;
          VEC(tree,gc) *aliases = var_ann (smt)->may_aliases;
          tree alias;
          tree alias;
 
 
          bitmap_clear (type_aliases);
          bitmap_clear (type_aliases);
          for (i = 0; VEC_iterate (tree, aliases, i, alias); i++)
          for (i = 0; VEC_iterate (tree, aliases, i, alias); i++)
            bitmap_set_bit (type_aliases, DECL_UID (alias));
            bitmap_set_bit (type_aliases, DECL_UID (alias));
 
 
          /* When grouping, we may have added PTR's symbol tag into the
          /* When grouping, we may have added PTR's symbol tag into the
             alias set of PTR's name tag.  To prevent a false
             alias set of PTR's name tag.  To prevent a false
             positive, pretend that SMT is in its own alias set.  */
             positive, pretend that SMT is in its own alias set.  */
          bitmap_set_bit (type_aliases, DECL_UID (smt));
          bitmap_set_bit (type_aliases, DECL_UID (smt));
 
 
          if (bitmap_equal_p (type_aliases, pi->pt_vars))
          if (bitmap_equal_p (type_aliases, pi->pt_vars))
            continue;
            continue;
 
 
          if (!bitmap_intersect_compl_p (type_aliases, pi->pt_vars))
          if (!bitmap_intersect_compl_p (type_aliases, pi->pt_vars))
            {
            {
              error ("alias set of a pointer's symbol tag should be a superset of the corresponding name tag");
              error ("alias set of a pointer's symbol tag should be a superset of the corresponding name tag");
              debug_variable (smt);
              debug_variable (smt);
              debug_variable (pi->name_mem_tag);
              debug_variable (pi->name_mem_tag);
              goto err;
              goto err;
            }
            }
        }
        }
    }
    }
 
 
  /* Now compare all the representative bitmaps with all other representative
  /* Now compare all the representative bitmaps with all other representative
     bitmaps, to verify that they are all different.  */
     bitmaps, to verify that they are all different.  */
  for (i = 0; VEC_iterate (bitmap, pt_vars_for_reps, i, first); i++)
  for (i = 0; VEC_iterate (bitmap, pt_vars_for_reps, i, first); i++)
    {
    {
       for (j = i + 1; VEC_iterate (bitmap, pt_vars_for_reps, j, second); j++)
       for (j = i + 1; VEC_iterate (bitmap, pt_vars_for_reps, j, second); j++)
         {
         {
           if (bitmap_equal_p (first, second))
           if (bitmap_equal_p (first, second))
             {
             {
               error ("two different pointers with identical points-to sets but different name tags");
               error ("two different pointers with identical points-to sets but different name tags");
               debug_variable (VEC_index (tree, name_tag_reps, j));
               debug_variable (VEC_index (tree, name_tag_reps, j));
               goto err;
               goto err;
             }
             }
         }
         }
    }
    }
 
 
  /* Lastly, clear out the visited flags.  */
  /* Lastly, clear out the visited flags.  */
  for (i = 0; i < num_ssa_names; i++)
  for (i = 0; i < num_ssa_names; i++)
    {
    {
      if (ssa_name (i))
      if (ssa_name (i))
        {
        {
          tree ptr = ssa_name (i);
          tree ptr = ssa_name (i);
          struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
          struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
          if (!TREE_VISITED (ptr)
          if (!TREE_VISITED (ptr)
              || !POINTER_TYPE_P (TREE_TYPE (ptr))
              || !POINTER_TYPE_P (TREE_TYPE (ptr))
              || !pi
              || !pi
              || !pi->name_mem_tag)
              || !pi->name_mem_tag)
            continue;
            continue;
          TREE_VISITED (pi->name_mem_tag) = 0;
          TREE_VISITED (pi->name_mem_tag) = 0;
        }
        }
    }
    }
 
 
  /* We do not have to free the bitmaps or trees in the vectors, as
  /* We do not have to free the bitmaps or trees in the vectors, as
     they are not owned by us.  */
     they are not owned by us.  */
  VEC_free (bitmap, heap, pt_vars_for_reps);
  VEC_free (bitmap, heap, pt_vars_for_reps);
  VEC_free (tree, heap, name_tag_reps);
  VEC_free (tree, heap, name_tag_reps);
  BITMAP_FREE (type_aliases);
  BITMAP_FREE (type_aliases);
  return;
  return;
 
 
err:
err:
  debug_variable (VEC_index (tree, name_tag_reps, i));
  debug_variable (VEC_index (tree, name_tag_reps, i));
  internal_error ("verify_name_tags failed");
  internal_error ("verify_name_tags failed");
}
}
 
 
 
 
/* Verify the consistency of call clobbering information.  */
/* Verify the consistency of call clobbering information.  */
static void
static void
verify_call_clobbering (void)
verify_call_clobbering (void)
{
{
  unsigned int i;
  unsigned int i;
  bitmap_iterator bi;
  bitmap_iterator bi;
  tree var;
  tree var;
  referenced_var_iterator rvi;
  referenced_var_iterator rvi;
 
 
  /* At all times, the result of the DECL_CALL_CLOBBERED flag should
  /* At all times, the result of the DECL_CALL_CLOBBERED flag should
     match the result of the call_clobbered_vars bitmap.  Verify both
     match the result of the call_clobbered_vars bitmap.  Verify both
     that everything in call_clobbered_vars is marked
     that everything in call_clobbered_vars is marked
     DECL_CALL_CLOBBERED, and that everything marked
     DECL_CALL_CLOBBERED, and that everything marked
     DECL_CALL_CLOBBERED is in call_clobbered_vars.  */
     DECL_CALL_CLOBBERED is in call_clobbered_vars.  */
  EXECUTE_IF_SET_IN_BITMAP (call_clobbered_vars, 0, i, bi)
  EXECUTE_IF_SET_IN_BITMAP (call_clobbered_vars, 0, i, bi)
    {
    {
      var = referenced_var (i);
      var = referenced_var (i);
      if (!MTAG_P (var) && !DECL_CALL_CLOBBERED (var))
      if (!MTAG_P (var) && !DECL_CALL_CLOBBERED (var))
        {
        {
          error ("variable in call_clobbered_vars but not marked DECL_CALL_CLOBBERED");
          error ("variable in call_clobbered_vars but not marked DECL_CALL_CLOBBERED");
          debug_variable (var);
          debug_variable (var);
          goto err;
          goto err;
        }
        }
    }
    }
  FOR_EACH_REFERENCED_VAR (var, rvi)
  FOR_EACH_REFERENCED_VAR (var, rvi)
    {
    {
      if (!MTAG_P (var) && DECL_CALL_CLOBBERED (var)
      if (!MTAG_P (var) && DECL_CALL_CLOBBERED (var)
          && !bitmap_bit_p (call_clobbered_vars, DECL_UID (var)))
          && !bitmap_bit_p (call_clobbered_vars, DECL_UID (var)))
        {
        {
          error ("variable marked DECL_CALL_CLOBBERED but not in call_clobbered_vars bitmap.");
          error ("variable marked DECL_CALL_CLOBBERED but not in call_clobbered_vars bitmap.");
          debug_variable (var);
          debug_variable (var);
          goto err;
          goto err;
        }
        }
    }
    }
  return;
  return;
 
 
 err:
 err:
    internal_error ("verify_call_clobbering failed");
    internal_error ("verify_call_clobbering failed");
}
}
 
 
/* Verify the consistency of aliasing information.  */
/* Verify the consistency of aliasing information.  */
 
 
static void
static void
verify_alias_info (void)
verify_alias_info (void)
{
{
  verify_flow_sensitive_alias_info ();
  verify_flow_sensitive_alias_info ();
  verify_name_tags ();
  verify_name_tags ();
  verify_call_clobbering ();
  verify_call_clobbering ();
  verify_flow_insensitive_alias_info ();
  verify_flow_insensitive_alias_info ();
}
}
 
 
 
 
/* Verify common invariants in the SSA web.
/* Verify common invariants in the SSA web.
   TODO: verify the variable annotations.  */
   TODO: verify the variable annotations.  */
 
 
void
void
verify_ssa (bool check_modified_stmt)
verify_ssa (bool check_modified_stmt)
{
{
  size_t i;
  size_t i;
  basic_block bb;
  basic_block bb;
  basic_block *definition_block = XCNEWVEC (basic_block, num_ssa_names);
  basic_block *definition_block = XCNEWVEC (basic_block, num_ssa_names);
  ssa_op_iter iter;
  ssa_op_iter iter;
  tree op;
  tree op;
  enum dom_state orig_dom_state = dom_computed[CDI_DOMINATORS];
  enum dom_state orig_dom_state = dom_computed[CDI_DOMINATORS];
  bitmap names_defined_in_bb = BITMAP_ALLOC (NULL);
  bitmap names_defined_in_bb = BITMAP_ALLOC (NULL);
 
 
  gcc_assert (!need_ssa_update_p ());
  gcc_assert (!need_ssa_update_p ());
 
 
  verify_stmts ();
  verify_stmts ();
 
 
  timevar_push (TV_TREE_SSA_VERIFY);
  timevar_push (TV_TREE_SSA_VERIFY);
 
 
  /* Keep track of SSA names present in the IL.  */
  /* Keep track of SSA names present in the IL.  */
  for (i = 1; i < num_ssa_names; i++)
  for (i = 1; i < num_ssa_names; i++)
    {
    {
      tree name = ssa_name (i);
      tree name = ssa_name (i);
      if (name)
      if (name)
        {
        {
          tree stmt;
          tree stmt;
          TREE_VISITED (name) = 0;
          TREE_VISITED (name) = 0;
 
 
          stmt = SSA_NAME_DEF_STMT (name);
          stmt = SSA_NAME_DEF_STMT (name);
          if (!IS_EMPTY_STMT (stmt))
          if (!IS_EMPTY_STMT (stmt))
            {
            {
              basic_block bb = bb_for_stmt (stmt);
              basic_block bb = bb_for_stmt (stmt);
              verify_def (bb, definition_block,
              verify_def (bb, definition_block,
                          name, stmt, !is_gimple_reg (name));
                          name, stmt, !is_gimple_reg (name));
 
 
            }
            }
        }
        }
    }
    }
 
 
  calculate_dominance_info (CDI_DOMINATORS);
  calculate_dominance_info (CDI_DOMINATORS);
 
 
  /* Now verify all the uses and make sure they agree with the definitions
  /* Now verify all the uses and make sure they agree with the definitions
     found in the previous pass.  */
     found in the previous pass.  */
  FOR_EACH_BB (bb)
  FOR_EACH_BB (bb)
    {
    {
      edge e;
      edge e;
      tree phi;
      tree phi;
      edge_iterator ei;
      edge_iterator ei;
      block_stmt_iterator bsi;
      block_stmt_iterator bsi;
 
 
      /* Make sure that all edges have a clear 'aux' field.  */
      /* Make sure that all edges have a clear 'aux' field.  */
      FOR_EACH_EDGE (e, ei, bb->preds)
      FOR_EACH_EDGE (e, ei, bb->preds)
        {
        {
          if (e->aux)
          if (e->aux)
            {
            {
              error ("AUX pointer initialized for edge %d->%d", e->src->index,
              error ("AUX pointer initialized for edge %d->%d", e->src->index,
                      e->dest->index);
                      e->dest->index);
              goto err;
              goto err;
            }
            }
        }
        }
 
 
      /* Verify the arguments for every PHI node in the block.  */
      /* Verify the arguments for every PHI node in the block.  */
      for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
      for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
        {
        {
          if (verify_phi_args (phi, bb, definition_block))
          if (verify_phi_args (phi, bb, definition_block))
            goto err;
            goto err;
          bitmap_set_bit (names_defined_in_bb,
          bitmap_set_bit (names_defined_in_bb,
                          SSA_NAME_VERSION (PHI_RESULT (phi)));
                          SSA_NAME_VERSION (PHI_RESULT (phi)));
        }
        }
 
 
      /* Now verify all the uses and vuses in every statement of the block.  */
      /* Now verify all the uses and vuses in every statement of the block.  */
      for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
      for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
        {
        {
          tree stmt = bsi_stmt (bsi);
          tree stmt = bsi_stmt (bsi);
          use_operand_p use_p;
          use_operand_p use_p;
 
 
          if (check_modified_stmt && stmt_modified_p (stmt))
          if (check_modified_stmt && stmt_modified_p (stmt))
            {
            {
              error ("stmt (%p) marked modified after optimization pass : ",
              error ("stmt (%p) marked modified after optimization pass : ",
                     (void *)stmt);
                     (void *)stmt);
              print_generic_stmt (stderr, stmt, TDF_VOPS);
              print_generic_stmt (stderr, stmt, TDF_VOPS);
              goto err;
              goto err;
            }
            }
 
 
          if (TREE_CODE (stmt) == MODIFY_EXPR
          if (TREE_CODE (stmt) == MODIFY_EXPR
              && TREE_CODE (TREE_OPERAND (stmt, 0)) != SSA_NAME)
              && TREE_CODE (TREE_OPERAND (stmt, 0)) != SSA_NAME)
            {
            {
              tree lhs, base_address;
              tree lhs, base_address;
 
 
              lhs = TREE_OPERAND (stmt, 0);
              lhs = TREE_OPERAND (stmt, 0);
              base_address = get_base_address (lhs);
              base_address = get_base_address (lhs);
 
 
              if (base_address
              if (base_address
                  && SSA_VAR_P (base_address)
                  && SSA_VAR_P (base_address)
                  && ZERO_SSA_OPERANDS (stmt, SSA_OP_VMAYDEF|SSA_OP_VMUSTDEF))
                  && ZERO_SSA_OPERANDS (stmt, SSA_OP_VMAYDEF|SSA_OP_VMUSTDEF))
                {
                {
                  error ("statement makes a memory store, but has no "
                  error ("statement makes a memory store, but has no "
                         "V_MAY_DEFS nor V_MUST_DEFS");
                         "V_MAY_DEFS nor V_MUST_DEFS");
                  print_generic_stmt (stderr, stmt, TDF_VOPS);
                  print_generic_stmt (stderr, stmt, TDF_VOPS);
                  goto err;
                  goto err;
                }
                }
            }
            }
 
 
          FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter,
          FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter,
                                    SSA_OP_ALL_USES | SSA_OP_ALL_KILLS)
                                    SSA_OP_ALL_USES | SSA_OP_ALL_KILLS)
            {
            {
              op = USE_FROM_PTR (use_p);
              op = USE_FROM_PTR (use_p);
              if (verify_use (bb, definition_block[SSA_NAME_VERSION (op)],
              if (verify_use (bb, definition_block[SSA_NAME_VERSION (op)],
                              use_p, stmt, false, !is_gimple_reg (op),
                              use_p, stmt, false, !is_gimple_reg (op),
                              names_defined_in_bb))
                              names_defined_in_bb))
                goto err;
                goto err;
            }
            }
 
 
          FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_ALL_DEFS)
          FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_ALL_DEFS)
            bitmap_set_bit (names_defined_in_bb, SSA_NAME_VERSION (op));
            bitmap_set_bit (names_defined_in_bb, SSA_NAME_VERSION (op));
        }
        }
 
 
      bitmap_clear (names_defined_in_bb);
      bitmap_clear (names_defined_in_bb);
    }
    }
 
 
  /* Finally, verify alias information.  */
  /* Finally, verify alias information.  */
  verify_alias_info ();
  verify_alias_info ();
 
 
  free (definition_block);
  free (definition_block);
 
 
  /* Restore the dominance information to its prior known state, so
  /* Restore the dominance information to its prior known state, so
     that we do not perturb the compiler's subsequent behavior.  */
     that we do not perturb the compiler's subsequent behavior.  */
  if (orig_dom_state == DOM_NONE)
  if (orig_dom_state == DOM_NONE)
    free_dominance_info (CDI_DOMINATORS);
    free_dominance_info (CDI_DOMINATORS);
  else
  else
    dom_computed[CDI_DOMINATORS] = orig_dom_state;
    dom_computed[CDI_DOMINATORS] = orig_dom_state;
 
 
  BITMAP_FREE (names_defined_in_bb);
  BITMAP_FREE (names_defined_in_bb);
  timevar_pop (TV_TREE_SSA_VERIFY);
  timevar_pop (TV_TREE_SSA_VERIFY);
  return;
  return;
 
 
err:
err:
  internal_error ("verify_ssa failed");
  internal_error ("verify_ssa failed");
}
}
 
 
/* Return true if the uid in both int tree maps are equal.  */
/* Return true if the uid in both int tree maps are equal.  */
 
 
int
int
int_tree_map_eq (const void *va, const void *vb)
int_tree_map_eq (const void *va, const void *vb)
{
{
  const struct int_tree_map *a = (const struct int_tree_map *) va;
  const struct int_tree_map *a = (const struct int_tree_map *) va;
  const struct int_tree_map *b = (const struct int_tree_map *) vb;
  const struct int_tree_map *b = (const struct int_tree_map *) vb;
  return (a->uid == b->uid);
  return (a->uid == b->uid);
}
}
 
 
/* Hash a UID in a int_tree_map.  */
/* Hash a UID in a int_tree_map.  */
 
 
unsigned int
unsigned int
int_tree_map_hash (const void *item)
int_tree_map_hash (const void *item)
{
{
  return ((const struct int_tree_map *)item)->uid;
  return ((const struct int_tree_map *)item)->uid;
}
}
 
 
 
 
/* Initialize global DFA and SSA structures.  */
/* Initialize global DFA and SSA structures.  */
 
 
void
void
init_tree_ssa (void)
init_tree_ssa (void)
{
{
  referenced_vars = htab_create_ggc (20, int_tree_map_hash,
  referenced_vars = htab_create_ggc (20, int_tree_map_hash,
                                     int_tree_map_eq, NULL);
                                     int_tree_map_eq, NULL);
  default_defs = htab_create_ggc (20, int_tree_map_hash, int_tree_map_eq, NULL);
  default_defs = htab_create_ggc (20, int_tree_map_hash, int_tree_map_eq, NULL);
  call_clobbered_vars = BITMAP_ALLOC (NULL);
  call_clobbered_vars = BITMAP_ALLOC (NULL);
  addressable_vars = BITMAP_ALLOC (NULL);
  addressable_vars = BITMAP_ALLOC (NULL);
  init_alias_heapvars ();
  init_alias_heapvars ();
  init_ssanames ();
  init_ssanames ();
  init_phinodes ();
  init_phinodes ();
  global_var = NULL_TREE;
  global_var = NULL_TREE;
  aliases_computed_p = false;
  aliases_computed_p = false;
}
}
 
 
 
 
/* Deallocate memory associated with SSA data structures for FNDECL.  */
/* Deallocate memory associated with SSA data structures for FNDECL.  */
 
 
void
void
delete_tree_ssa (void)
delete_tree_ssa (void)
{
{
  size_t i;
  size_t i;
  basic_block bb;
  basic_block bb;
  block_stmt_iterator bsi;
  block_stmt_iterator bsi;
  referenced_var_iterator rvi;
  referenced_var_iterator rvi;
  tree var;
  tree var;
 
 
  /* Release any ssa_names still in use.  */
  /* Release any ssa_names still in use.  */
  for (i = 0; i < num_ssa_names; i++)
  for (i = 0; i < num_ssa_names; i++)
    {
    {
      tree var = ssa_name (i);
      tree var = ssa_name (i);
      if (var && TREE_CODE (var) == SSA_NAME)
      if (var && TREE_CODE (var) == SSA_NAME)
        {
        {
          SSA_NAME_IMM_USE_NODE (var).prev = &(SSA_NAME_IMM_USE_NODE (var));
          SSA_NAME_IMM_USE_NODE (var).prev = &(SSA_NAME_IMM_USE_NODE (var));
          SSA_NAME_IMM_USE_NODE (var).next = &(SSA_NAME_IMM_USE_NODE (var));
          SSA_NAME_IMM_USE_NODE (var).next = &(SSA_NAME_IMM_USE_NODE (var));
        }
        }
      release_ssa_name (var);
      release_ssa_name (var);
    }
    }
 
 
  /* Remove annotations from every tree in the function.  */
  /* Remove annotations from every tree in the function.  */
  FOR_EACH_BB (bb)
  FOR_EACH_BB (bb)
    {
    {
      for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
      for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
        {
        {
          tree stmt = bsi_stmt (bsi);
          tree stmt = bsi_stmt (bsi);
          stmt_ann_t ann = get_stmt_ann (stmt);
          stmt_ann_t ann = get_stmt_ann (stmt);
 
 
          free_ssa_operands (&ann->operands);
          free_ssa_operands (&ann->operands);
          ann->addresses_taken = 0;
          ann->addresses_taken = 0;
          mark_stmt_modified (stmt);
          mark_stmt_modified (stmt);
        }
        }
      set_phi_nodes (bb, NULL);
      set_phi_nodes (bb, NULL);
    }
    }
 
 
  /* Remove annotations from every referenced variable.  */
  /* Remove annotations from every referenced variable.  */
  FOR_EACH_REFERENCED_VAR (var, rvi)
  FOR_EACH_REFERENCED_VAR (var, rvi)
    {
    {
      ggc_free (var->common.ann);
      ggc_free (var->common.ann);
      var->common.ann = NULL;
      var->common.ann = NULL;
    }
    }
  htab_delete (referenced_vars);
  htab_delete (referenced_vars);
  referenced_vars = NULL;
  referenced_vars = NULL;
 
 
  fini_ssanames ();
  fini_ssanames ();
  fini_phinodes ();
  fini_phinodes ();
 
 
  global_var = NULL_TREE;
  global_var = NULL_TREE;
 
 
  htab_delete (default_defs);
  htab_delete (default_defs);
  BITMAP_FREE (call_clobbered_vars);
  BITMAP_FREE (call_clobbered_vars);
  call_clobbered_vars = NULL;
  call_clobbered_vars = NULL;
  BITMAP_FREE (addressable_vars);
  BITMAP_FREE (addressable_vars);
  addressable_vars = NULL;
  addressable_vars = NULL;
  modified_noreturn_calls = NULL;
  modified_noreturn_calls = NULL;
  aliases_computed_p = false;
  aliases_computed_p = false;
  delete_alias_heapvars ();
  delete_alias_heapvars ();
  gcc_assert (!need_ssa_update_p ());
  gcc_assert (!need_ssa_update_p ());
}
}
 
 
 
 
/* Return true if the conversion from INNER_TYPE to OUTER_TYPE is a
/* Return true if the conversion from INNER_TYPE to OUTER_TYPE is a
   useless type conversion, otherwise return false.  */
   useless type conversion, otherwise return false.  */
 
 
bool
bool
tree_ssa_useless_type_conversion_1 (tree outer_type, tree inner_type)
tree_ssa_useless_type_conversion_1 (tree outer_type, tree inner_type)
{
{
  if (inner_type == outer_type)
  if (inner_type == outer_type)
    return true;
    return true;
 
 
  /* Changes in machine mode are never useless conversions.  */
  /* Changes in machine mode are never useless conversions.  */
  if (TYPE_MODE (inner_type) != TYPE_MODE (outer_type))
  if (TYPE_MODE (inner_type) != TYPE_MODE (outer_type))
    return false;
    return false;
 
 
  /* If the inner and outer types are effectively the same, then
  /* If the inner and outer types are effectively the same, then
     strip the type conversion and enter the equivalence into
     strip the type conversion and enter the equivalence into
     the table.  */
     the table.  */
  if (lang_hooks.types_compatible_p (inner_type, outer_type))
  if (lang_hooks.types_compatible_p (inner_type, outer_type))
    return true;
    return true;
 
 
  /* If both types are pointers and the outer type is a (void *), then
  /* If both types are pointers and the outer type is a (void *), then
     the conversion is not necessary.  The opposite is not true since
     the conversion is not necessary.  The opposite is not true since
     that conversion would result in a loss of information if the
     that conversion would result in a loss of information if the
     equivalence was used.  Consider an indirect function call where
     equivalence was used.  Consider an indirect function call where
     we need to know the exact type of the function to correctly
     we need to know the exact type of the function to correctly
     implement the ABI.  */
     implement the ABI.  */
  else if (POINTER_TYPE_P (inner_type)
  else if (POINTER_TYPE_P (inner_type)
           && POINTER_TYPE_P (outer_type)
           && POINTER_TYPE_P (outer_type)
           && TYPE_REF_CAN_ALIAS_ALL (inner_type)
           && TYPE_REF_CAN_ALIAS_ALL (inner_type)
              == TYPE_REF_CAN_ALIAS_ALL (outer_type)
              == TYPE_REF_CAN_ALIAS_ALL (outer_type)
           && TREE_CODE (TREE_TYPE (outer_type)) == VOID_TYPE)
           && TREE_CODE (TREE_TYPE (outer_type)) == VOID_TYPE)
    return true;
    return true;
 
 
  /* Don't lose casts between pointers to volatile and non-volatile
  /* Don't lose casts between pointers to volatile and non-volatile
     qualified types.  Doing so would result in changing the semantics
     qualified types.  Doing so would result in changing the semantics
     of later accesses.  */
     of later accesses.  */
  else if (POINTER_TYPE_P (inner_type)
  else if (POINTER_TYPE_P (inner_type)
           && POINTER_TYPE_P (outer_type)
           && POINTER_TYPE_P (outer_type)
           && TYPE_VOLATILE (TREE_TYPE (outer_type))
           && TYPE_VOLATILE (TREE_TYPE (outer_type))
              != TYPE_VOLATILE (TREE_TYPE (inner_type)))
              != TYPE_VOLATILE (TREE_TYPE (inner_type)))
    return false;
    return false;
 
 
  /* Pointers/references are equivalent if their pointed to types
  /* Pointers/references are equivalent if their pointed to types
     are effectively the same.  This allows to strip conversions between
     are effectively the same.  This allows to strip conversions between
     pointer types with different type qualifiers.  */
     pointer types with different type qualifiers.  */
  else if (POINTER_TYPE_P (inner_type)
  else if (POINTER_TYPE_P (inner_type)
           && POINTER_TYPE_P (outer_type)
           && POINTER_TYPE_P (outer_type)
           && TYPE_REF_CAN_ALIAS_ALL (inner_type)
           && TYPE_REF_CAN_ALIAS_ALL (inner_type)
              == TYPE_REF_CAN_ALIAS_ALL (outer_type)
              == TYPE_REF_CAN_ALIAS_ALL (outer_type)
           && lang_hooks.types_compatible_p (TREE_TYPE (inner_type),
           && lang_hooks.types_compatible_p (TREE_TYPE (inner_type),
                                             TREE_TYPE (outer_type)))
                                             TREE_TYPE (outer_type)))
    return true;
    return true;
 
 
  /* If both the inner and outer types are integral types, then the
  /* If both the inner and outer types are integral types, then the
     conversion is not necessary if they have the same mode and
     conversion is not necessary if they have the same mode and
     signedness and precision, and both or neither are boolean.  Some
     signedness and precision, and both or neither are boolean.  Some
     code assumes an invariant that boolean types stay boolean and do
     code assumes an invariant that boolean types stay boolean and do
     not become 1-bit bit-field types.  Note that types with precision
     not become 1-bit bit-field types.  Note that types with precision
     not using all bits of the mode (such as bit-field types in C)
     not using all bits of the mode (such as bit-field types in C)
     mean that testing of precision is necessary.  */
     mean that testing of precision is necessary.  */
  else if (INTEGRAL_TYPE_P (inner_type)
  else if (INTEGRAL_TYPE_P (inner_type)
           && INTEGRAL_TYPE_P (outer_type)
           && INTEGRAL_TYPE_P (outer_type)
           && TYPE_UNSIGNED (inner_type) == TYPE_UNSIGNED (outer_type)
           && TYPE_UNSIGNED (inner_type) == TYPE_UNSIGNED (outer_type)
           && TYPE_PRECISION (inner_type) == TYPE_PRECISION (outer_type)
           && TYPE_PRECISION (inner_type) == TYPE_PRECISION (outer_type)
           && simple_cst_equal (TYPE_MAX_VALUE (inner_type), TYPE_MAX_VALUE (outer_type))
           && simple_cst_equal (TYPE_MAX_VALUE (inner_type), TYPE_MAX_VALUE (outer_type))
           && simple_cst_equal (TYPE_MIN_VALUE (inner_type), TYPE_MIN_VALUE (outer_type)))
           && simple_cst_equal (TYPE_MIN_VALUE (inner_type), TYPE_MIN_VALUE (outer_type)))
    {
    {
      bool first_boolean = (TREE_CODE (inner_type) == BOOLEAN_TYPE);
      bool first_boolean = (TREE_CODE (inner_type) == BOOLEAN_TYPE);
      bool second_boolean = (TREE_CODE (outer_type) == BOOLEAN_TYPE);
      bool second_boolean = (TREE_CODE (outer_type) == BOOLEAN_TYPE);
      if (first_boolean == second_boolean)
      if (first_boolean == second_boolean)
        return true;
        return true;
    }
    }
 
 
  /* Recurse for complex types.  */
  /* Recurse for complex types.  */
  else if (TREE_CODE (inner_type) == COMPLEX_TYPE
  else if (TREE_CODE (inner_type) == COMPLEX_TYPE
           && TREE_CODE (outer_type) == COMPLEX_TYPE
           && TREE_CODE (outer_type) == COMPLEX_TYPE
           && tree_ssa_useless_type_conversion_1 (TREE_TYPE (outer_type),
           && tree_ssa_useless_type_conversion_1 (TREE_TYPE (outer_type),
                                                  TREE_TYPE (inner_type)))
                                                  TREE_TYPE (inner_type)))
    return true;
    return true;
 
 
  return false;
  return false;
}
}
 
 
/* Return true if EXPR is a useless type conversion, otherwise return
/* Return true if EXPR is a useless type conversion, otherwise return
   false.  */
   false.  */
 
 
bool
bool
tree_ssa_useless_type_conversion (tree expr)
tree_ssa_useless_type_conversion (tree expr)
{
{
  /* If we have an assignment that merely uses a NOP_EXPR to change
  /* If we have an assignment that merely uses a NOP_EXPR to change
     the top of the RHS to the type of the LHS and the type conversion
     the top of the RHS to the type of the LHS and the type conversion
     is "safe", then strip away the type conversion so that we can
     is "safe", then strip away the type conversion so that we can
     enter LHS = RHS into the const_and_copies table.  */
     enter LHS = RHS into the const_and_copies table.  */
  if (TREE_CODE (expr) == NOP_EXPR || TREE_CODE (expr) == CONVERT_EXPR
  if (TREE_CODE (expr) == NOP_EXPR || TREE_CODE (expr) == CONVERT_EXPR
      || TREE_CODE (expr) == VIEW_CONVERT_EXPR
      || TREE_CODE (expr) == VIEW_CONVERT_EXPR
      || TREE_CODE (expr) == NON_LVALUE_EXPR)
      || TREE_CODE (expr) == NON_LVALUE_EXPR)
    return tree_ssa_useless_type_conversion_1 (TREE_TYPE (expr),
    return tree_ssa_useless_type_conversion_1 (TREE_TYPE (expr),
                                               TREE_TYPE (TREE_OPERAND (expr,
                                               TREE_TYPE (TREE_OPERAND (expr,
                                                                        0)));
                                                                        0)));
 
 
 
 
  return false;
  return false;
}
}
 
 
/* Returns true if statement STMT may read memory.  */
/* Returns true if statement STMT may read memory.  */
 
 
bool
bool
stmt_references_memory_p (tree stmt)
stmt_references_memory_p (tree stmt)
{
{
  stmt_ann_t ann = stmt_ann (stmt);
  stmt_ann_t ann = stmt_ann (stmt);
 
 
  if (ann->has_volatile_ops)
  if (ann->has_volatile_ops)
    return true;
    return true;
 
 
  return (!ZERO_SSA_OPERANDS (stmt, SSA_OP_ALL_VIRTUALS));
  return (!ZERO_SSA_OPERANDS (stmt, SSA_OP_ALL_VIRTUALS));
}
}
 
 
/* Internal helper for walk_use_def_chains.  VAR, FN and DATA are as
/* Internal helper for walk_use_def_chains.  VAR, FN and DATA are as
   described in walk_use_def_chains.
   described in walk_use_def_chains.
 
 
   VISITED is a pointer set used to mark visited SSA_NAMEs to avoid
   VISITED is a pointer set used to mark visited SSA_NAMEs to avoid
      infinite loops.  We used to have a bitmap for this to just mark
      infinite loops.  We used to have a bitmap for this to just mark
      SSA versions we had visited.  But non-sparse bitmaps are way too
      SSA versions we had visited.  But non-sparse bitmaps are way too
      expensive, while sparse bitmaps may cause quadratic behavior.
      expensive, while sparse bitmaps may cause quadratic behavior.
 
 
   IS_DFS is true if the caller wants to perform a depth-first search
   IS_DFS is true if the caller wants to perform a depth-first search
      when visiting PHI nodes.  A DFS will visit each PHI argument and
      when visiting PHI nodes.  A DFS will visit each PHI argument and
      call FN after each one.  Otherwise, all the arguments are
      call FN after each one.  Otherwise, all the arguments are
      visited first and then FN is called with each of the visited
      visited first and then FN is called with each of the visited
      arguments in a separate pass.  */
      arguments in a separate pass.  */
 
 
static bool
static bool
walk_use_def_chains_1 (tree var, walk_use_def_chains_fn fn, void *data,
walk_use_def_chains_1 (tree var, walk_use_def_chains_fn fn, void *data,
                       struct pointer_set_t *visited, bool is_dfs)
                       struct pointer_set_t *visited, bool is_dfs)
{
{
  tree def_stmt;
  tree def_stmt;
 
 
  if (pointer_set_insert (visited, var))
  if (pointer_set_insert (visited, var))
    return false;
    return false;
 
 
  def_stmt = SSA_NAME_DEF_STMT (var);
  def_stmt = SSA_NAME_DEF_STMT (var);
 
 
  if (TREE_CODE (def_stmt) != PHI_NODE)
  if (TREE_CODE (def_stmt) != PHI_NODE)
    {
    {
      /* If we reached the end of the use-def chain, call FN.  */
      /* If we reached the end of the use-def chain, call FN.  */
      return fn (var, def_stmt, data);
      return fn (var, def_stmt, data);
    }
    }
  else
  else
    {
    {
      int i;
      int i;
 
 
      /* When doing a breadth-first search, call FN before following the
      /* When doing a breadth-first search, call FN before following the
         use-def links for each argument.  */
         use-def links for each argument.  */
      if (!is_dfs)
      if (!is_dfs)
        for (i = 0; i < PHI_NUM_ARGS (def_stmt); i++)
        for (i = 0; i < PHI_NUM_ARGS (def_stmt); i++)
          if (fn (PHI_ARG_DEF (def_stmt, i), def_stmt, data))
          if (fn (PHI_ARG_DEF (def_stmt, i), def_stmt, data))
            return true;
            return true;
 
 
      /* Follow use-def links out of each PHI argument.  */
      /* Follow use-def links out of each PHI argument.  */
      for (i = 0; i < PHI_NUM_ARGS (def_stmt); i++)
      for (i = 0; i < PHI_NUM_ARGS (def_stmt); i++)
        {
        {
          tree arg = PHI_ARG_DEF (def_stmt, i);
          tree arg = PHI_ARG_DEF (def_stmt, i);
          if (TREE_CODE (arg) == SSA_NAME
          if (TREE_CODE (arg) == SSA_NAME
              && walk_use_def_chains_1 (arg, fn, data, visited, is_dfs))
              && walk_use_def_chains_1 (arg, fn, data, visited, is_dfs))
            return true;
            return true;
        }
        }
 
 
      /* When doing a depth-first search, call FN after following the
      /* When doing a depth-first search, call FN after following the
         use-def links for each argument.  */
         use-def links for each argument.  */
      if (is_dfs)
      if (is_dfs)
        for (i = 0; i < PHI_NUM_ARGS (def_stmt); i++)
        for (i = 0; i < PHI_NUM_ARGS (def_stmt); i++)
          if (fn (PHI_ARG_DEF (def_stmt, i), def_stmt, data))
          if (fn (PHI_ARG_DEF (def_stmt, i), def_stmt, data))
            return true;
            return true;
    }
    }
 
 
  return false;
  return false;
}
}
 
 
 
 
 
 
/* Walk use-def chains starting at the SSA variable VAR.  Call
/* Walk use-def chains starting at the SSA variable VAR.  Call
   function FN at each reaching definition found.  FN takes three
   function FN at each reaching definition found.  FN takes three
   arguments: VAR, its defining statement (DEF_STMT) and a generic
   arguments: VAR, its defining statement (DEF_STMT) and a generic
   pointer to whatever state information that FN may want to maintain
   pointer to whatever state information that FN may want to maintain
   (DATA).  FN is able to stop the walk by returning true, otherwise
   (DATA).  FN is able to stop the walk by returning true, otherwise
   in order to continue the walk, FN should return false.
   in order to continue the walk, FN should return false.
 
 
   Note, that if DEF_STMT is a PHI node, the semantics are slightly
   Note, that if DEF_STMT is a PHI node, the semantics are slightly
   different.  The first argument to FN is no longer the original
   different.  The first argument to FN is no longer the original
   variable VAR, but the PHI argument currently being examined.  If FN
   variable VAR, but the PHI argument currently being examined.  If FN
   wants to get at VAR, it should call PHI_RESULT (PHI).
   wants to get at VAR, it should call PHI_RESULT (PHI).
 
 
   If IS_DFS is true, this function will:
   If IS_DFS is true, this function will:
 
 
        1- walk the use-def chains for all the PHI arguments, and,
        1- walk the use-def chains for all the PHI arguments, and,
        2- call (*FN) (ARG, PHI, DATA) on all the PHI arguments.
        2- call (*FN) (ARG, PHI, DATA) on all the PHI arguments.
 
 
   If IS_DFS is false, the two steps above are done in reverse order
   If IS_DFS is false, the two steps above are done in reverse order
   (i.e., a breadth-first search).  */
   (i.e., a breadth-first search).  */
 
 
 
 
void
void
walk_use_def_chains (tree var, walk_use_def_chains_fn fn, void *data,
walk_use_def_chains (tree var, walk_use_def_chains_fn fn, void *data,
                     bool is_dfs)
                     bool is_dfs)
{
{
  tree def_stmt;
  tree def_stmt;
 
 
  gcc_assert (TREE_CODE (var) == SSA_NAME);
  gcc_assert (TREE_CODE (var) == SSA_NAME);
 
 
  def_stmt = SSA_NAME_DEF_STMT (var);
  def_stmt = SSA_NAME_DEF_STMT (var);
 
 
  /* We only need to recurse if the reaching definition comes from a PHI
  /* We only need to recurse if the reaching definition comes from a PHI
     node.  */
     node.  */
  if (TREE_CODE (def_stmt) != PHI_NODE)
  if (TREE_CODE (def_stmt) != PHI_NODE)
    (*fn) (var, def_stmt, data);
    (*fn) (var, def_stmt, data);
  else
  else
    {
    {
      struct pointer_set_t *visited = pointer_set_create ();
      struct pointer_set_t *visited = pointer_set_create ();
      walk_use_def_chains_1 (var, fn, data, visited, is_dfs);
      walk_use_def_chains_1 (var, fn, data, visited, is_dfs);
      pointer_set_destroy (visited);
      pointer_set_destroy (visited);
    }
    }
}
}
 
 


/* Emit warnings for uninitialized variables.  This is done in two passes.
/* Emit warnings for uninitialized variables.  This is done in two passes.
 
 
   The first pass notices real uses of SSA names with default definitions.
   The first pass notices real uses of SSA names with default definitions.
   Such uses are unconditionally uninitialized, and we can be certain that
   Such uses are unconditionally uninitialized, and we can be certain that
   such a use is a mistake.  This pass is run before most optimizations,
   such a use is a mistake.  This pass is run before most optimizations,
   so that we catch as many as we can.
   so that we catch as many as we can.
 
 
   The second pass follows PHI nodes to find uses that are potentially
   The second pass follows PHI nodes to find uses that are potentially
   uninitialized.  In this case we can't necessarily prove that the use
   uninitialized.  In this case we can't necessarily prove that the use
   is really uninitialized.  This pass is run after most optimizations,
   is really uninitialized.  This pass is run after most optimizations,
   so that we thread as many jumps and possible, and delete as much dead
   so that we thread as many jumps and possible, and delete as much dead
   code as possible, in order to reduce false positives.  We also look
   code as possible, in order to reduce false positives.  We also look
   again for plain uninitialized variables, since optimization may have
   again for plain uninitialized variables, since optimization may have
   changed conditionally uninitialized to unconditionally uninitialized.  */
   changed conditionally uninitialized to unconditionally uninitialized.  */
 
 
/* Emit a warning for T, an SSA_NAME, being uninitialized.  The exact
/* Emit a warning for T, an SSA_NAME, being uninitialized.  The exact
   warning text is in MSGID and LOCUS may contain a location or be null.  */
   warning text is in MSGID and LOCUS may contain a location or be null.  */
 
 
static void
static void
warn_uninit (tree t, const char *gmsgid, void *data)
warn_uninit (tree t, const char *gmsgid, void *data)
{
{
  tree var = SSA_NAME_VAR (t);
  tree var = SSA_NAME_VAR (t);
  tree def = SSA_NAME_DEF_STMT (t);
  tree def = SSA_NAME_DEF_STMT (t);
  tree context = (tree) data;
  tree context = (tree) data;
  location_t *locus, *fun_locus;
  location_t *locus, *fun_locus;
 
 
  /* Default uses (indicated by an empty definition statement),
  /* Default uses (indicated by an empty definition statement),
     are uninitialized.  */
     are uninitialized.  */
  if (!IS_EMPTY_STMT (def))
  if (!IS_EMPTY_STMT (def))
    return;
    return;
 
 
  /* Except for PARMs of course, which are always initialized.  */
  /* Except for PARMs of course, which are always initialized.  */
  if (TREE_CODE (var) == PARM_DECL)
  if (TREE_CODE (var) == PARM_DECL)
    return;
    return;
 
 
  /* Hard register variables get their initial value from the ether.  */
  /* Hard register variables get their initial value from the ether.  */
  if (TREE_CODE (var) == VAR_DECL && DECL_HARD_REGISTER (var))
  if (TREE_CODE (var) == VAR_DECL && DECL_HARD_REGISTER (var))
    return;
    return;
 
 
  /* TREE_NO_WARNING either means we already warned, or the front end
  /* TREE_NO_WARNING either means we already warned, or the front end
     wishes to suppress the warning.  */
     wishes to suppress the warning.  */
  if (TREE_NO_WARNING (var))
  if (TREE_NO_WARNING (var))
    return;
    return;
 
 
  locus = (context != NULL && EXPR_HAS_LOCATION (context)
  locus = (context != NULL && EXPR_HAS_LOCATION (context)
           ? EXPR_LOCUS (context)
           ? EXPR_LOCUS (context)
           : &DECL_SOURCE_LOCATION (var));
           : &DECL_SOURCE_LOCATION (var));
  warning (0, gmsgid, locus, var);
  warning (0, gmsgid, locus, var);
  fun_locus = &DECL_SOURCE_LOCATION (cfun->decl);
  fun_locus = &DECL_SOURCE_LOCATION (cfun->decl);
  if (locus->file != fun_locus->file
  if (locus->file != fun_locus->file
      || locus->line < fun_locus->line
      || locus->line < fun_locus->line
      || locus->line > cfun->function_end_locus.line)
      || locus->line > cfun->function_end_locus.line)
    inform ("%J%qD was declared here", var, var);
    inform ("%J%qD was declared here", var, var);
 
 
  TREE_NO_WARNING (var) = 1;
  TREE_NO_WARNING (var) = 1;
}
}
 
 
/* Called via walk_tree, look for SSA_NAMEs that have empty definitions
/* Called via walk_tree, look for SSA_NAMEs that have empty definitions
   and warn about them.  */
   and warn about them.  */
 
 
static tree
static tree
warn_uninitialized_var (tree *tp, int *walk_subtrees, void *data)
warn_uninitialized_var (tree *tp, int *walk_subtrees, void *data)
{
{
  tree t = *tp;
  tree t = *tp;
 
 
  switch (TREE_CODE (t))
  switch (TREE_CODE (t))
    {
    {
    case SSA_NAME:
    case SSA_NAME:
      /* We only do data flow with SSA_NAMEs, so that's all we
      /* We only do data flow with SSA_NAMEs, so that's all we
         can warn about.  */
         can warn about.  */
      warn_uninit (t, "%H%qD is used uninitialized in this function", data);
      warn_uninit (t, "%H%qD is used uninitialized in this function", data);
      *walk_subtrees = 0;
      *walk_subtrees = 0;
      break;
      break;
 
 
    case REALPART_EXPR:
    case REALPART_EXPR:
    case IMAGPART_EXPR:
    case IMAGPART_EXPR:
      /* The total store transformation performed during gimplification
      /* The total store transformation performed during gimplification
         creates uninitialized variable uses.  If all is well, these will
         creates uninitialized variable uses.  If all is well, these will
         be optimized away, so don't warn now.  */
         be optimized away, so don't warn now.  */
      if (TREE_CODE (TREE_OPERAND (t, 0)) == SSA_NAME)
      if (TREE_CODE (TREE_OPERAND (t, 0)) == SSA_NAME)
        *walk_subtrees = 0;
        *walk_subtrees = 0;
      break;
      break;
 
 
    default:
    default:
      if (IS_TYPE_OR_DECL_P (t))
      if (IS_TYPE_OR_DECL_P (t))
        *walk_subtrees = 0;
        *walk_subtrees = 0;
      break;
      break;
    }
    }
 
 
  return NULL_TREE;
  return NULL_TREE;
}
}
 
 
/* Look for inputs to PHI that are SSA_NAMEs that have empty definitions
/* Look for inputs to PHI that are SSA_NAMEs that have empty definitions
   and warn about them.  */
   and warn about them.  */
 
 
static void
static void
warn_uninitialized_phi (tree phi)
warn_uninitialized_phi (tree phi)
{
{
  int i, n = PHI_NUM_ARGS (phi);
  int i, n = PHI_NUM_ARGS (phi);
 
 
  /* Don't look at memory tags.  */
  /* Don't look at memory tags.  */
  if (!is_gimple_reg (PHI_RESULT (phi)))
  if (!is_gimple_reg (PHI_RESULT (phi)))
    return;
    return;
 
 
  for (i = 0; i < n; ++i)
  for (i = 0; i < n; ++i)
    {
    {
      tree op = PHI_ARG_DEF (phi, i);
      tree op = PHI_ARG_DEF (phi, i);
      if (TREE_CODE (op) == SSA_NAME)
      if (TREE_CODE (op) == SSA_NAME)
        warn_uninit (op, "%H%qD may be used uninitialized in this function",
        warn_uninit (op, "%H%qD may be used uninitialized in this function",
                     NULL);
                     NULL);
    }
    }
}
}
 
 
static unsigned int
static unsigned int
execute_early_warn_uninitialized (void)
execute_early_warn_uninitialized (void)
{
{
  block_stmt_iterator bsi;
  block_stmt_iterator bsi;
  basic_block bb;
  basic_block bb;
 
 
  FOR_EACH_BB (bb)
  FOR_EACH_BB (bb)
    for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
    for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
      {
      {
        tree context = bsi_stmt (bsi);
        tree context = bsi_stmt (bsi);
        walk_tree (bsi_stmt_ptr (bsi), warn_uninitialized_var,
        walk_tree (bsi_stmt_ptr (bsi), warn_uninitialized_var,
                   context, NULL);
                   context, NULL);
      }
      }
  return 0;
  return 0;
}
}
 
 
static unsigned int
static unsigned int
execute_late_warn_uninitialized (void)
execute_late_warn_uninitialized (void)
{
{
  basic_block bb;
  basic_block bb;
  tree phi;
  tree phi;
 
 
  /* Re-do the plain uninitialized variable check, as optimization may have
  /* Re-do the plain uninitialized variable check, as optimization may have
     straightened control flow.  Do this first so that we don't accidentally
     straightened control flow.  Do this first so that we don't accidentally
     get a "may be" warning when we'd have seen an "is" warning later.  */
     get a "may be" warning when we'd have seen an "is" warning later.  */
  execute_early_warn_uninitialized ();
  execute_early_warn_uninitialized ();
 
 
  FOR_EACH_BB (bb)
  FOR_EACH_BB (bb)
    for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
    for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
      warn_uninitialized_phi (phi);
      warn_uninitialized_phi (phi);
  return 0;
  return 0;
}
}
 
 
static bool
static bool
gate_warn_uninitialized (void)
gate_warn_uninitialized (void)
{
{
  return warn_uninitialized != 0;
  return warn_uninitialized != 0;
}
}
 
 
struct tree_opt_pass pass_early_warn_uninitialized =
struct tree_opt_pass pass_early_warn_uninitialized =
{
{
  NULL,                                 /* name */
  NULL,                                 /* name */
  gate_warn_uninitialized,              /* gate */
  gate_warn_uninitialized,              /* gate */
  execute_early_warn_uninitialized,     /* execute */
  execute_early_warn_uninitialized,     /* execute */
  NULL,                                 /* sub */
  NULL,                                 /* sub */
  NULL,                                 /* next */
  NULL,                                 /* next */
  0,                                     /* static_pass_number */
  0,                                     /* static_pass_number */
  0,                                     /* tv_id */
  0,                                     /* tv_id */
  PROP_ssa,                             /* properties_required */
  PROP_ssa,                             /* properties_required */
  0,                                     /* properties_provided */
  0,                                     /* properties_provided */
  0,                                     /* properties_destroyed */
  0,                                     /* properties_destroyed */
  0,                                     /* todo_flags_start */
  0,                                     /* todo_flags_start */
  0,                                    /* todo_flags_finish */
  0,                                    /* todo_flags_finish */
  0                                      /* letter */
  0                                      /* letter */
};
};
 
 
struct tree_opt_pass pass_late_warn_uninitialized =
struct tree_opt_pass pass_late_warn_uninitialized =
{
{
  NULL,                                 /* name */
  NULL,                                 /* name */
  gate_warn_uninitialized,              /* gate */
  gate_warn_uninitialized,              /* gate */
  execute_late_warn_uninitialized,      /* execute */
  execute_late_warn_uninitialized,      /* execute */
  NULL,                                 /* sub */
  NULL,                                 /* sub */
  NULL,                                 /* next */
  NULL,                                 /* next */
  0,                                     /* static_pass_number */
  0,                                     /* static_pass_number */
  0,                                     /* tv_id */
  0,                                     /* tv_id */
  PROP_ssa,                             /* properties_required */
  PROP_ssa,                             /* properties_required */
  0,                                     /* properties_provided */
  0,                                     /* properties_provided */
  0,                                     /* properties_destroyed */
  0,                                     /* properties_destroyed */
  0,                                     /* todo_flags_start */
  0,                                     /* todo_flags_start */
  0,                                    /* todo_flags_finish */
  0,                                    /* todo_flags_finish */
  0                                      /* letter */
  0                                      /* letter */
};
};
 
 
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.