On Fri, Dec 4, 2020 at 4:58 AM Erick Ochoa <
erick.oc...@theobroma-systems.com> wrote:

>
> This commit includes the following components:
>
>    Type-based escape analysis to determine structs that can be modified at
>    link-time.
>    Field access analysis to determine which fields are never read.
>
> The type-based escape analysis provides a list of types, that are not
> visible outside of the current linking unit (e.g. parameter types of
> external
> functions).
>
> The field access analyses non-escaping structs for fields that
> are not used in the linking unit and thus can be removed.
>
> 2020-11-04  Erick Ochoa  <erick.oc...@theobroma-systems.com>
>
>      * Makefile.in: Add file to list of new sources.
>      * common.opt: Add new flags.
>      * ipa-type-escape-analysis.c: New file.
> ---
>   gcc/Makefile.in                |    1 +
>   gcc/common.opt                 |    8 +
>   gcc/ipa-type-escape-analysis.c | 3428 ++++++++++++++++++++++++++++++++
>   gcc/ipa-type-escape-analysis.h | 1152 +++++++++++
>   gcc/passes.def                 |    1 +
>   gcc/timevar.def                |    1 +
>   gcc/tree-pass.h                |    2 +
>   7 files changed, 4593 insertions(+)
>   create mode 100644 gcc/ipa-type-escape-analysis.c
>   create mode 100644 gcc/ipa-type-escape-analysis.h
>
> diff --git a/gcc/Makefile.in b/gcc/Makefile.in
> index 978a08f7b04..8b18c9217a2 100644
> --- a/gcc/Makefile.in
> +++ b/gcc/Makefile.in
> @@ -1415,6 +1415,7 @@ OBJS = \
>         incpath.o \
>         init-regs.o \
>         internal-fn.o \
> +       ipa-type-escape-analysis.o \
>         ipa-cp.o \
>         ipa-sra.o \
>         ipa-devirt.o \
> diff --git a/gcc/common.opt b/gcc/common.opt
> index d4cbb2f86a5..85351738a29 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -3460,4 +3460,12 @@ fipa-ra
>   Common Report Var(flag_ipa_ra) Optimization
>   Use caller save register across calls if possible.
>   +fipa-type-escape-analysis
> +Common Report Var(flag_ipa_type_escape_analysis) Optimization
> +This flag is only used for debugging the type escape analysis
> +
> +Wdfa
> +Common Var(warn_dfa) Init(1) Warning
> +Warn about dead fields at link time.
> +
>

I don't really like the name "-Wdfa" very much; could you maybe come up
with a longer and more descriptive name instead? Say, "-Wunused-field" or
"-Wunused-private-field" depending on the kind of field:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=72789
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92801


>   ; This comment is to ensure we retain the blank line above.
> diff --git a/gcc/ipa-type-escape-analysis.c
> b/gcc/ipa-type-escape-analysis.c
> new file mode 100644
> index 00000000000..32c8bf997fb
> --- /dev/null
> +++ b/gcc/ipa-type-escape-analysis.c
> @@ -0,0 +1,3428 @@
> +/* IPA Type Escape Analysis and Dead Field Elimination
> +   Copyright (C) 2019-2020 Free Software Foundation, Inc.
> +
> +  Contributed by Erick Ochoa <erick.oc...@theobroma-systems.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/>.  */
> +
> +/* Interprocedural dead field analysis (IPA-DFA)
> +
> +   The goal of this analysis is to
> +
> +   1) discover RECORD_TYPEs which do not escape the current linking unit.
> +
> +   2) discover fields in RECORD_TYPEs that are never read.
> +
> +   3) merge the results from 1 and 2 to determine which fields are not
> needed.
> +
> +   The algorithm basically consists of the following stages:
> +
> +   1) Partition all TYPE_P trees into two sets: those trees which reach a
> +   tree of RECORD_TYPE.
> +
> +   2.a) Analyze callsites to determine if arguments and return types are
> +   escaping.
> +   2.b) Analyze casts to determine if it would be safe to mark a field
> as dead.
> +   2.c) Analyze for constructors and static initialization and mark this
> as
> +   TYPE_P trees as unable to be modified
> +   2.d) Analyze if FIELD_DECL are accessed via pointer arithmetic and mark
> +   FIELD_DECLs before as unable to be modified.
> +   2.e) Analyze if an address of a FIELD_DECL is taken and mark the whole
> +   RECORD_TYPE as unable to be modified.
> +   2.f) Propagate this information to nested TYPE_P trees.
> +   2.g) Propagate this information across different TYPE_P trees that
> represent
> +   equivalent TYPE_P types.
> +
> +   3.a) Analyze FIELD_DECL to determine whether they are read,
> +   written or neither.
> +   3.b) Unify this information across different RECORD_TYPE trees that
> +   represent equivalent types
> +   3.c) Determine which FIELD_DECL can be deleted.
> +
> +   4) Calculate the intersection of non-escaping RECORD_TYPEs with
> RECORD_TYPEs
> +   that have a field that can be deleted.
> +
> +   First stage - Determining if a TYPE_P points to a RECORD_TYPE
> +   =============================================================
> +
> +   This stage is computed through the *Collector classes.  Those are
> +   TypeCollector, ExprCollector and GimpleTypeCollector which walk up
> and down
> +   types, expressions, and gimple respectively and propagate
> information about
> +   TYPE_P trees and mantain information on the type partitions.
> +
> +   Second stage - Determining if a TYPE_P escapes
> +   ==============================================
> +
> +   This stage is computed through the *Escaper classes.  Those are
> +   TypeEscaper, ExprEscaper, GimpleEscaper, GimpleCaster classes.  These
> +   classes walk up and down types, expressions and gimple respectively and
> +   propagate reasons why a TYPE_P tree might be escaping.
> +   Reasons are always ORed and equivalent TYPE_P trees might hold
> different
> +   results up to when equivalence is computed for all TYPE_P trees and
> reasons
> +   are propagated until a fixedpoint is achieved.
> +
> +   Third stage - Calculating FIELD_DECL accesses
> +   =============================================
> +
> +   This stage is computed through the *Accessor classes.  Those are
> +   TypeAccessor, ExprAccessor, and GimpleAccessor.  These classes walk
> up and
> +   down TYPE_P, expressions, and gimple respectively and propagate access
> +   information.  If an expression occurs in the LHS, it is marked as
> written
> +   and if it occurs on the RHS, it is marked as read.  Special cases where
> +   addresses of a FIELD_DECLs are taken mark all FIELD_DECL in a
> RECORD_TYPE
> +   as read.
> +
> +   Fourth stage - Intersection of accesses and non_escaping
> +   ========================================================
> +
> +   This stage happens in the function
> obtain_unescaped_and_unaccessed_fields.
> +   First all FIELD_DECLs are translated to their respective field offset.
> +   Then all field offsets for FIELD_DECLs which are READ are stored
> +   in a set.  We then compute the complement of this set and these are the
> +   offsets of FIELD_DECLs which are never read.
> +
> +   Offsets are needed if we are to find dead fields for anonymous fields.
> +*/
> +
> +
> +#include <vector>
> +#include <set>
> +#include <map>
> +#include <stack>
> +#include <string>
> +
> +#include "config.h"
> +#include "system.h"
> +#include "coretypes.h"
> +#include "backend.h"
> +#include "tree.h"
> +#include "gimple-expr.h"
> +#include "predict.h"
> +#include "alloc-pool.h"
> +#include "tree-pass.h"
> +#include "cgraph.h"
> +#include "diagnostic.h"
> +#include "fold-const.h"
> +#include "gimple-fold.h"
> +#include "symbol-summary.h"
> +#include "tree-vrp.h"
> +#include "ipa-prop.h"
> +#include "tree-pretty-print.h"
> +#include "tree-inline.h"
> +#include "ipa-fnsummary.h"
> +#include "ipa-utils.h"
> +#include "tree-ssa-ccp.h"
> +#include "stringpool.h"
> +#include "attribs.h"
> +#include "basic-block.h" //needed for gimple.h
> +#include "function.h"    //needed for gimple.h
> +#include "gimple.h"
> +#include "stor-layout.h"
> +#include "cfg.h" // needed for gimple-iterator.h
> +#include "gimple-iterator.h"
> +#include "gimplify.h"      //unshare_expr
> +#include "value-range.h"   // make_ssa_name dependency
> +#include "tree-ssanames.h" // make_ssa_name
> +#include "ssa.h"
> +#include "tree-into-ssa.h"
> +#include "gimple-ssa.h" // update_stmt
> +#include "tree.h"
> +#include "gimple-expr.h"
> +#include "predict.h"
> +#include "alloc-pool.h"
> +#include "tree-pass.h"
> +#include "cgraph.h"
> +#include "diagnostic.h"
> +#include "fold-const.h"
> +#include "gimple-fold.h"
> +#include "symbol-summary.h"
> +#include "tree-vrp.h"
> +#include "ipa-prop.h"
> +#include "tree-pretty-print.h"
> +#include "tree-inline.h"
> +#include "ipa-fnsummary.h"
> +#include "ipa-utils.h"
> +#include "tree-ssa-ccp.h"
> +#include "stringpool.h"
> +#include "attribs.h"
> +#include "tree-ssa-alias.h"
> +#include "tree-ssanames.h"
> +#include "gimple.h"
> +#include "cfg.h"
> +#include "gimple-iterator.h"
> +#include "gimple-ssa.h"
> +#include "gimple-pretty-print.h"
> +
> +#include "ipa-type-escape-analysis.h"
> +
> +// Main function that drives dfe.
> +static unsigned int
> +lto_dfe_execute ();
> +
> +// Partition types into reching record or non reaching record sets.
> +static tpartitions_t
> +partition_types_into_record_reaching_or_non_record_reaching ();
> +
> +// Partition types into escaping or non escaping sets.
> +static tpartitions_t
> +partition_types_into_escaping_nonescaping ();
> +
> +// Perform dead field elimination.
> +static void
> +lto_dead_field_elimination ();
> +
> +// Fixed point calculating to determine escaping types.
> +static void
> +fix_escaping_types_in_set (tpartitions_t &types);
> +
> +// Find which fields are accessed.
> +static record_field_map_t
> +find_fields_accessed ();
> +
> +// Obtain intersection of unaccessed and non escaping types.
> +static record_field_offset_map_t
> +obtain_nonescaping_unaccessed_fields (tpartitions_t casting,
> +                                     record_field_map_t record_field_map);
> +
> +// TODO:
> +// This was copy pasted from tree-ssa-structalias.c
> +// Maybe delete this and make the function visible?
> +static HOST_WIDE_INT
> +bitpos_of_field (const tree fdecl)
> +{
> +  if (!tree_fits_shwi_p (DECL_FIELD_OFFSET (fdecl))
> +      || !tree_fits_shwi_p (DECL_FIELD_BIT_OFFSET (fdecl)))
> +    return -1;
> +
> +  return (tree_to_shwi (DECL_FIELD_OFFSET (fdecl)) * BITS_PER_UNIT
> +         + tree_to_shwi (DECL_FIELD_BIT_OFFSET (fdecl)));
> +}
> +
> +/* There are some cases where I need to change a tree to a tree.
> + * Some of these are part of the way the API is written.  To avoid
> + * warnings, always use this function for casting away const-ness.
> + */
> +inline static tree
> +tree_to_tree (tree t)
> +{
> +  return (tree) t;
> +}
> +
> +namespace {
> +const pass_data pass_data_ipa_type_escape_analysis = {
> +  SIMPLE_IPA_PASS,
> +  "type-escape-analysis",
> +  OPTGROUP_NONE,
> +  TV_NONE,
> +  (PROP_cfg | PROP_ssa),
> +  0,
> +  0,
> +  0,
> +  0,
> +};
> +
> +class pass_ipa_type_escape_analysis : public simple_ipa_opt_pass
> +{
> +public:
> +  pass_ipa_type_escape_analysis (gcc::context *ctx)
> +    : simple_ipa_opt_pass (pass_data_ipa_type_escape_analysis, ctx)
> +  {}
> +
> +  virtual bool gate (function *)
> +  {
> +    return in_lto_p && flag_ipa_type_escape_analysis;
> +  }
> +  virtual unsigned execute (function *)
> +  {
> +    return lto_dfe_execute ();
> +  }
> +};
> +} // namespace
> +
> +/* Top level function.  */
> +static unsigned int
> +lto_dfe_execute ()
> +{
> +  lto_dead_field_elimination ();
> +  log ("finished!\n");
> +  return 0;
> +}
> +
> +/*
> + * Perform dead field elimination at link-time.
> + * This transformation is composed of two main stages:
> + *   * Finding out which fields are non escaping and unaccessed.
> + *   * Creating new types and substituting their mention throughout the
> + *   program.
> + */
> +static void
> +lto_dead_field_elimination ()
> +{
> +  // Analysis.
> +  cgraph_node *cnode = NULL;
> +  FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (cnode)
> +  {
> +    if (cnode->inlined_to) continue;
> +    cnode->get_body();
> +  }
> +  tpartitions_t escaping_nonescaping_sets
> +    = partition_types_into_escaping_nonescaping ();
> +  record_field_map_t record_field_map = find_fields_accessed ();
> +  record_field_offset_map_t record_field_offset_map
> +    = obtain_nonescaping_unaccessed_fields (escaping_nonescaping_sets,
> +                                           record_field_map);
> +  if (record_field_offset_map.empty ())
> +    return;
> +
> +}
> +
> +/* Iterate all gimple bodies and collect trees
> + * which are themselves RECORD_TYPE or which
> + * somehow reach a RECORD_TYPE tree (e.g., via a
> + * pointer, array, reference, union, field, etc...).
> + * Let's call these trees record_reaching_trees.
> + */
> +static tpartitions_t
> +partition_types_into_record_reaching_or_non_record_reaching ()
> +{
> +  gimple_type_collector collector;
> +  collector.walk ();
> +  tpartitions_t partitions = collector.get_record_reaching_trees ();
> +  return partitions;
> +}
> +
> +/* Iterate over all gimple bodies and find out
> + * which types are escaping AND are being casted.
> + */
> +static tpartitions_t
> +partition_types_into_escaping_nonescaping ()
> +{
> +  tpartitions_t partitions
> +    = partition_types_into_record_reaching_or_non_record_reaching ();
> +  gimple_caster caster (partitions);
> +  caster.walk ();
> +  caster.print_reasons ();
> +
> +  partitions = caster.get_sets ();
> +  // Unify results from different trees representing the same type
> +  // until a fixed point is reached.
> +  fix_escaping_types_in_set (partitions);
> +  return partitions;
> +}
> +
> +/* Iterate over all gimple bodies and find out
> + * which fields are accessed for all RECORD_TYPE
> + * types.
> + */
> +static record_field_map_t
> +find_fields_accessed ()
> +{
> +  gimple_accessor accesser;
> +  accesser.walk ();
> +
> +  // This record_field_map holds
> +  // RECORD_TYPE -> (FIELD_DECL -> how field is accessed)
> +  record_field_map_t record_field_map = accesser.get_map ();
> +  return record_field_map;
> +}
> +
> +/* Find equivalent RECORD_TYPE trees to tree r_i.
> + * This equivalence will be used for merging the results of field accesses
> + * across all equivalent RECORD_TYPE trees.
> +
> + * r_i should exists in the points_to_record set
> + * and it is a tree for which this method is going to find the rest of
> + * equivalent trees found in record_field_map.
> + */
> +static std::vector<tree>
> +find_equivalent_trees (tree r_i, record_field_map_t record_field_map,
> +                      tpartitions_t casting)
> +{
> +  type_incomplete_equality equality;
> +  std::vector<tree> equivalence;
> +  bool is_rin_record = casting.in_points_to_record (r_i);
> +  if (!is_rin_record)
> +    return equivalence;
> +
> +  for (std::map<tree, field_access_map_t>::const_iterator j
> +       = record_field_map.begin (),
> +       f = record_field_map.end ();
> +       j != f; j++)
> +    {
> +      tree r_j = j->first;
> +      const bool pointer_equal = r_i == r_j;
> +      if (pointer_equal)
> +       continue;
> +
> +      bool is_p_record = casting.in_points_to_record (r_i)
> +                        && casting.in_points_to_record (r_j);
> +      if (!is_p_record)
> +       continue;
> +
> +      const bool are_equal = equality.equal (r_i, r_j);
> +      if (!are_equal)
> +       continue;
> +
> +      equivalence.push_back (r_j);
> +    }
> +  return equivalence;
> +}
> +
> +/*
> + * FIELD is a FIELD_DECL tree, ACCESSED is a a bitflag that marks
> whether the
> + * field is read, written or neither.  FIELD_OFFSET will hold the
> following map:
> + * tree (RECORD_TYPE) -> unsigned (bitpos_of_field for read fields).
> + */
> +static void
> +add_offset_only_if_read (tree field, unsigned access,
> +                        field_offsets_t &field_offset)
> +{
> +  assert_is_type (field, FIELD_DECL);
> +  const bool is_read = access & Read;
> +  if (!is_read)
> +    return;
> +
> +  tree _field = tree_to_tree (field);
> +  unsigned f_offset = bitpos_of_field (_field);
> +  field_offset.insert (f_offset);
> +}
> +
> +/*
> + * FIELD_MAP holds the following map:
> + * tree (FIELD_DECL) -> access type
> + * FIELD_OFFSET is being built here.
> + * It should hold
> + * tree (RECORD_TYPE) -> bitpos_of_field for read fields).
> + */
> +static void
> +keep_only_read_fields_from_field_map (field_access_map_t &field_map,
> +                                     field_offsets_t &field_offset)
> +{
> +  for (std::map<tree, unsigned>::iterator j = field_map.begin (),
> +                                               f = field_map.end ();
> +       j != f; ++j)
> +    {
> +      add_offset_only_if_read (j->first, j->second, field_offset);
> +    }
> +}
> +
> +/*
> + * EQUIVALENT holds equivalent trees of RECORD_TYPE
> + * Update FIELD_OFFSET as the union of all READ FIELDS for the
> equivalent trees.
> + */
> +static void
> +keep_only_read_fields_from_equivalent_field_maps (
> +  std::vector<tree> equivalent, record_field_map_t &record_field_map,
> +  field_offsets_t &field_offset)
> +{
> +  for (std::vector<tree>::iterator j = equivalent.begin (),
> +                                        f = equivalent.end ();
> +       j != f; j++)
> +    {
> +      tree r_j = *j;
> +      field_access_map_t equivalent_field_map = record_field_map[r_j];
> +      keep_only_read_fields_from_field_map (equivalent_field_map,
> field_offset);
> +    }
> +}
> +
> +/*
> + * Whether RECORDS are escaping or can't be modified,
> + * delete them from the set of candidate RECORDS to be modified.
> + */
> +static void
> +erase_if_no_fields_can_be_deleted (
> +  record_field_offset_map_t &record_field_offset_map,
> +  std::set<tree> &to_keep, std::set<tree> &to_erase)
> +{
> +  for (std::map<tree, field_offsets_t>::iterator i
> +       = record_field_offset_map.begin (),
> +       e = record_field_offset_map.end ();
> +       i != e; ++i)
> +    {
> +      tree record = i->first;
> +      const bool keep = to_keep.find (record) != to_keep.end ();
> +      if (keep)
> +       continue;
> +
> +      to_erase.insert (record);
> +    }
> +
> +  for (std::set<tree>::iterator i = to_erase.begin (),
> +                                     e = to_erase.end ();
> +       i != e; ++i)
> +    {
> +      tree record = *i;
> +      record_field_offset_map.erase (record);
> +    }
> +}
> +
> +/*
> + * Mark escaping RECORD_TYPEs as ready to be deleted from the
> + * set of candidates to be modified.
> + */
> +static void
> +mark_escaping_types_to_be_deleted (
> +  record_field_offset_map_t &record_field_offset_map,
> +  std::set<tree> &to_erase, tpartitions_t casting)
> +{
> +  const tset_t &non_escaping = casting.non_escaping;
> +  for (std::map<tree, field_offsets_t>::iterator i
> +       = record_field_offset_map.begin (),
> +       e = record_field_offset_map.end ();
> +       i != e; ++i)
> +    {
> +      tree record = i->first;
> +      const bool in_set = non_escaping.find (record) !=
> non_escaping.end ();
> +      if (in_set)
> +       continue;
> +
> +      to_erase.insert (record);
> +    }
> +}
> +
> +// Obtain nonescaping unaccessed fields
> +static record_field_offset_map_t
> +obtain_nonescaping_unaccessed_fields (tpartitions_t casting,
> +                                     record_field_map_t record_field_map)
> +{
> +  bool has_fields_that_can_be_deleted = false;
> +  record_field_offset_map_t record_field_offset_map;
> +  for (std::map<tree, field_access_map_t>::iterator i
> +       = record_field_map.begin (),
> +       e = record_field_map.end ();
> +       i != e; ++i)
> +    {
> +      tree r_i = i->first;
> +      std::vector<tree> equivalence
> +       = find_equivalent_trees (r_i, record_field_map, casting);
> +      field_offsets_t field_offset;
> +      field_access_map_t original_field_map = record_field_map[r_i];
> +      keep_only_read_fields_from_field_map (original_field_map,
> field_offset);
> +      keep_only_read_fields_from_equivalent_field_maps (equivalence,
> +                                                       record_field_map,
> +                                                       field_offset);
> +      // These map holds the following:
> +      // RECORD_TYPE -> unsigned (bit_pos_offset which has been read)
> +      record_field_offset_map[r_i] = field_offset;
> +    }
> +
> +  // So now that we only have the FIELDS which are read,
> +  // we need to compute the complement...
> +
> +  // Improve: This is tightly coupled, I need to decouple it...
> +  std::set<tree> to_erase;
> +  std::set<tree> to_keep;
> +  mark_escaping_types_to_be_deleted (record_field_offset_map, to_erase,
> +                                    casting);
> +  for (std::map<tree, field_offsets_t>::iterator i
> +       = record_field_offset_map.begin (),
> +       e = record_field_offset_map.end ();
> +       i != e; ++i)
> +    {
> +      tree record = i->first;
> +      const bool will_be_erased = to_erase.find (record) !=
> to_erase.end ();
> +      // No need to compute which fields can be deleted if type is
> escaping
> +      if (will_be_erased)
> +       continue;
> +
> +      field_offsets_t field_offset = i->second;
> +      for (tree field = TYPE_FIELDS (record); field; field = DECL_CHAIN
> (field))
> +       {
> +         unsigned f_offset = bitpos_of_field (field);
> +         bool in_set2 = field_offset.find (f_offset) != field_offset.end
> ();
> +         if (in_set2)
> +           {
> +             field_offset.erase (f_offset);
> +             continue;
> +           }
> +         to_keep.insert (record);
> +         field_offset.insert (f_offset);
> +         has_fields_that_can_be_deleted = true;
> +         // NOTE: With anonymous fields this might be weird to print.
> +         log ("%s.%s may be deleted\n",
> +              type_stringifier::get_type_identifier (record).c_str (),
> +              type_stringifier::get_field_identifier (field).c_str ());
> +
> +         if (OPT_Wdfa == 0) continue;
> +         // Anonymous fields? (Which the record can be!).
> +           warning (OPT_Wdfa, "RECORD_TYPE %qE has dead field %qE in
> LTO.\n",
> +               record, field);
> +       }
> +      record_field_offset_map[record] = field_offset;
> +    }
> +
> +  // Improve: Make this more elegant.
> +  if (!has_fields_that_can_be_deleted)
> +    {
> +      record_field_offset_map_t empty;
> +      return empty;
> +    }
> +
> +  erase_if_no_fields_can_be_deleted (record_field_offset_map, to_keep,
> +                                    to_erase);
> +
> +  return record_field_offset_map;
> +}
> +
> +// Main interface to TypeWalker
> +// Start recursive walk
> +void
> +type_walker::walk (tree t)
> +{
> +  gcc_assert (t);
> +  this->tset.clear ();
> +  this->_walk (t);
> +}
> +
> +void
> +type_walker::_walk (tree type)
> +{
> +  // Improve, verify that having a type is an invariant.
> +  // I think there was a specific example which didn't
> +  // allow for it
> +  if (!type)
> +    return;
> +
> +  gcc_assert (type);
> +
> +  // This is an optimization.
> +  const bool _is_memoized = is_memoized (type);
> +  if (_is_memoized)
> +    return;
> +
> +  // This is for correctness
> +  // Some types are represented as a graph
> +  // of trees and therefore we need a way to
> +  // avoid loops in this graph.
> +  // Imrpove: Outline finding if it is recursive?
> +  const bool is_recursing = tset.find (type) != tset.end ();
> +  if (is_recursing)
> +    return;
> +
> +  tset.insert (type);
> +  const enum tree_code code = TREE_CODE (type);
> +  switch (code)
> +    {
> +    case VOID_TYPE:
> +      this->walk_VOID_TYPE (type);
> +      break;
> +    case INTEGER_TYPE:
> +      this->walk_INTEGER_TYPE (type);
> +      break;
> +    case REAL_TYPE:
> +      this->walk_REAL_TYPE (type);
> +      break;
> +    case FIXED_POINT_TYPE:
> +      this->walk_FIXED_POINT_TYPE (type);
> +      break;
> +    case COMPLEX_TYPE:
> +      this->walk_COMPLEX_TYPE (type);
> +      break;
> +    case ENUMERAL_TYPE:
> +      this->walk_ENUMERAL_TYPE (type);
> +      break;
> +    case BOOLEAN_TYPE:
> +      this->walk_BOOLEAN_TYPE (type);
> +      break;
> +    case OFFSET_TYPE:
> +      this->walk_OFFSET_TYPE (type);
> +      break;
> +    case RECORD_TYPE:
> +      this->walk_RECORD_TYPE (type);
> +      break;
> +    case POINTER_TYPE:
> +      this->walk_POINTER_TYPE (type);
> +      break;
> +    case REFERENCE_TYPE:
> +      this->walk_REFERENCE_TYPE (type);
> +      break;
> +    case ARRAY_TYPE:
> +      this->walk_ARRAY_TYPE (type);
> +      break;
> +    case UNION_TYPE:
> +      this->walk_UNION_TYPE (type);
> +      break;
> +    case FUNCTION_TYPE:
> +      this->walk_FUNCTION_TYPE (type);
> +      break;
> +    case METHOD_TYPE:
> +      this->walk_METHOD_TYPE (type);
> +      break;
> +    // Since we are dealing only with C at the moment,
> +    // we don't care about QUAL_UNION_TYPE nor LANG_TYPEs
> +    // So fail early.
> +    case QUAL_UNION_TYPE:
> +    case LANG_TYPE:
> +    default:
> +      {
> +       log ("missing %s\n", get_tree_code_name (code));
> +       gcc_unreachable ();
> +      }
> +      break;
> +    }
> +  tset.erase (type);
> +}
> +
> +// This is used to walk over subtrees.
> +// But before walking subtrees, we need to
> +// call the pre-order callback
> +// and after we need to
> +// call the post-order callback.
> +#define TypeWalkerFuncDef(code)
>       \
> +  void type_walker::walk_##code (tree t)                               \
> +  {                                                                    \
> +    assert_is_type (t, code);                                          \
> +    _walk_##code##_pre (t);                                            \
> +    _walk_##code (t);                                                  \
> +    _walk_##code##_post (t);                                           \
> +  }
> +
> +#define TypeWalkerFuncDefInternal(code)
>       \
> +  void type_walker::_walk_##code (__attribute__ ((unused)) tree t) \
> +  {}
> +
> +TypeWalkerFuncDef (VOID_TYPE)
> +TypeWalkerFuncDefInternal (VOID_TYPE)
> +TypeWalkerFuncDef (INTEGER_TYPE)
> +TypeWalkerFuncDefInternal (INTEGER_TYPE)
> +TypeWalkerFuncDef (REAL_TYPE)
> +TypeWalkerFuncDefInternal (REAL_TYPE)
> +TypeWalkerFuncDef (BOOLEAN_TYPE)
> +TypeWalkerFuncDefInternal (BOOLEAN_TYPE)
> +TypeWalkerFuncDef (OFFSET_TYPE)
> +TypeWalkerFuncDefInternal (OFFSET_TYPE)
> +TypeWalkerFuncDef (FIXED_POINT_TYPE)
> +TypeWalkerFuncDefInternal (FIXED_POINT_TYPE)
> +TypeWalkerFuncDef (COMPLEX_TYPE)
> +TypeWalkerFuncDefInternal (COMPLEX_TYPE)
> +TypeWalkerFuncDef (ENUMERAL_TYPE)
> +TypeWalkerFuncDefInternal (ENUMERAL_TYPE)
> +
> +/* walk wrapper is used for unwrapping
> + * REFERENCE_TYPE, POINTER_TYPE, ARRAY_TYPE.
> + */
> +void type_walker::_walk_wrapper (tree t)
> +{
> +  tree inner_type = TREE_TYPE (t);
> +  // I think I encountered this code:
> +  // FIXME: Do we really need this?
> +  if (!inner_type)
> +    return;
> +
> +  gcc_assert (inner_type);
> +  _walk (inner_type);
> +}
> +
> +#define TypeWalkerFuncDefWrapper(code)         \
> +  void type_walker::_walk_##code (tree t)  \
> +  { _walk_wrapper (t); }
> +
> +TypeWalkerFuncDef (POINTER_TYPE)
> +TypeWalkerFuncDefWrapper (POINTER_TYPE)
> +TypeWalkerFuncDefWrapper (REFERENCE_TYPE)
> +TypeWalkerFuncDef (REFERENCE_TYPE)
> +TypeWalkerFuncDef (ARRAY_TYPE)
> +TypeWalkerFuncDefWrapper (ARRAY_TYPE)
> +TypeWalkerFuncDef (RECORD_TYPE)
> +
> +void
> +type_walker::_walk_RECORD_TYPE (tree t)
> +{
> +  _walk_record_or_union (t);
> +}
> +
> +TypeWalkerFuncDef (UNION_TYPE)
> +
> +void
> +type_walker::_walk_UNION_TYPE (tree t)
> +{
> +  _walk_record_or_union (t);
> +}
> +
> +void
> +type_walker::_walk_record_or_union (tree t)
> +{
> +  for (tree field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field))
> +    {
> +      gcc_assert (field);
> +      walk_field (field);
> +    }
> +}
> +
> +void
> +type_walker::walk_field (tree t)
> +{
> +  _walk_field_pre (t);
> +  _walk_field (t);
> +  _walk_field_post (t);
> +}
> +
> +void
> +type_walker::_walk_field (tree t)
> +{
> +  tree inner_type = TREE_TYPE (t);
> +  gcc_assert (inner_type);
> +  _walk (inner_type);
> +}
> +
> +TypeWalkerFuncDef (FUNCTION_TYPE)
> +
> +  void type_walker::_walk_FUNCTION_TYPE (tree t)
> +{
> +  _walk_function_or_method (t);
> +}
> +
> +TypeWalkerFuncDef (METHOD_TYPE)
> +
> +  void type_walker::_walk_METHOD_TYPE (tree t)
> +{
> +  _walk_function_or_method (t);
> +}
> +
> +void
> +type_walker::_walk_function_or_method (tree t)
> +{
> +  tree ret_type = TREE_TYPE (t);
> +  walk_return (ret_type);
> +  walk_args (t);
> +}
> +
> +void
> +type_walker::walk_return (tree t)
> +{
> +  _walk_return_pre (t);
> +  _walk_return (t);
> +  _walk_return_post (t);
> +}
> +
> +void
> +type_walker::_walk_return (tree t)
> +{
> +  _walk (t);
> +}
> +
> +void
> +type_walker::walk_args (tree t)
> +{
> +  _walk_args_pre (t);
> +  _walk_args (t);
> +  _walk_args_post (t);
> +}
> +
> +void
> +type_walker::_walk_args (tree t)
> +{
> +  for (tree arg_node = TYPE_ARG_TYPES (t); NULL_TREE != arg_node;
> +       arg_node = TREE_CHAIN (arg_node))
> +    {
> +      tree arg_node_type = TREE_VALUE (arg_node);
> +      gcc_assert (arg_node_type);
> +      walk_arg (arg_node_type);
> +    }
> +}
> +
> +void
> +type_walker::walk_arg (tree t)
> +{
> +  _walk_arg_pre (t);
> +  _walk_arg (t);
> +  _walk_arg_post (t);
> +}
> +
> +void
> +type_walker::_walk_arg (tree t)
> +{
> +  _walk (t);
> +}
> +
> +/* Main interface for the ExprWalker... */
> +void
> +expr_walker::walk (tree e)
> +{
> +  _walk_pre (e);
> +  _walk (e);
> +  _walk_post (e);
> +}
> +
> +void
> +expr_walker::_walk (tree e)
> +{
> +  gcc_assert (e);
> +  const enum tree_code code = TREE_CODE (e);
> +  switch (code)
> +    {
> +    case INTEGER_CST:
> +      walk_INTEGER_CST (e);
> +      break;
> +    case REAL_CST:
> +      walk_REAL_CST (e);
> +      break;
> +    case STRING_CST:
> +      walk_STRING_CST (e);
> +      break;
> +    case BIT_FIELD_REF:
> +      walk_BIT_FIELD_REF (e);
> +      break;
> +    case ARRAY_REF:
> +      walk_ARRAY_REF (e);
> +      break;
> +    case MEM_REF:
> +      walk_MEM_REF (e);
> +      break;
> +    case COMPONENT_REF:
> +      walk_COMPONENT_REF (e);
> +      break;
> +    case SSA_NAME:
> +      walk_SSA_NAME (e);
> +      break;
> +    case ADDR_EXPR:
> +      walk_ADDR_EXPR (e);
> +      break;
> +    case VIEW_CONVERT_EXPR:
> +      walk_VIEW_CONVERT_EXPR (e);
> +      break;
> +    case IMAGPART_EXPR:
> +      walk_IMAGPART_EXPR (e);
> +      break;
> +    case VAR_DECL:
> +      walk_VAR_DECL (e);
> +      break;
> +    case FIELD_DECL:
> +      walk_FIELD_DECL (e);
> +      break;
> +    case RESULT_DECL:
> +      walk_RESULT_DECL (e);
> +      break;
> +    case PARM_DECL:
> +      walk_PARM_DECL (e);
> +      break;
> +    case FUNCTION_DECL:
> +      walk_FUNCTION_DECL (e);
> +      break;
> +    case CONSTRUCTOR:
> +      walk_CONSTRUCTOR (e);
> +      break;
> +    case LE_EXPR:
> +      walk_LE_EXPR (e);
> +      break;
> +    case LT_EXPR:
> +      walk_LT_EXPR (e);
> +      break;
> +    case EQ_EXPR:
> +      walk_EQ_EXPR (e);
> +      break;
> +    case GT_EXPR:
> +      walk_GT_EXPR (e);
> +      break;
> +    case GE_EXPR:
> +      walk_GE_EXPR (e);
> +      break;
> +    case NE_EXPR:
> +      walk_NE_EXPR (e);
> +      break;
> +    default:
> +      {
> +       log ("missing %s\n", get_tree_code_name (code));
> +       gcc_unreachable ();
> +      }
> +      break;
> +    }
> +}
> +
> +/* call pre-order callback for everything
> + * call pre-order callback for specific code
> + * walk subtrees
> + * call post-order callback for specific code
> + * call post-order callback for everything.
> + */
> +#define ExprWalkerFuncDef(code)                        \
> +  void expr_walker::walk_##code (tree e)               \
> +  {                                                    \
> +    assert_is_type (e, code);                          \
> +    _walk_pre (e);                                     \
> +    _walk_##code##_pre (e);                            \
> +    _walk_##code (e);                                  \
> +    _walk_##code##_post (e);                           \
> +    _walk_post (e);                                    \
> +  }
> +
> +ExprWalkerFuncDef (CONSTRUCTOR)
> +ExprWalkerFuncDef (INTEGER_CST)
> +ExprWalkerFuncDef (REAL_CST)
> +ExprWalkerFuncDef (STRING_CST)
> +ExprWalkerFuncDef (BIT_FIELD_REF)
> +ExprWalkerFuncDef (ARRAY_REF)
> +ExprWalkerFuncDef (MEM_REF)
> +ExprWalkerFuncDef (COMPONENT_REF)
> +ExprWalkerFuncDef (SSA_NAME)
> +ExprWalkerFuncDef (ADDR_EXPR)
> +ExprWalkerFuncDef (VIEW_CONVERT_EXPR)
> +ExprWalkerFuncDef (IMAGPART_EXPR)
> +ExprWalkerFuncDef (FIELD_DECL)
> +ExprWalkerFuncDef (VAR_DECL)
> +ExprWalkerFuncDef (RESULT_DECL)
> +ExprWalkerFuncDef (PARM_DECL)
> +ExprWalkerFuncDef (FUNCTION_DECL)
> +ExprWalkerFuncDef (LE_EXPR)
> +ExprWalkerFuncDef (LT_EXPR)
> +ExprWalkerFuncDef (EQ_EXPR)
> +ExprWalkerFuncDef (GT_EXPR)
> +ExprWalkerFuncDef (GE_EXPR)
> +ExprWalkerFuncDef (NE_EXPR)
> +
> +void expr_walker::_walk_leaf (tree e, const enum tree_code c)
> +{
> +  assert_is_type (e, c);
> +}
> +
> +void
> +expr_walker::_walk_op_n (tree e, unsigned n)
> +{
> +  gcc_assert (e);
> +  tree op_n = TREE_OPERAND (e, n);
> +  gcc_assert (op_n);
> +  walk (op_n);
> +}
> +
> +void
> +expr_walker::_walk_op_0 (tree e, const enum tree_code c)
> +{
> +  assert_is_type (e, c);
> +  _walk_op_n (e, 0);
> +}
> +
> +void
> +expr_walker::_walk_op_1 (tree e, const enum tree_code c)
> +{
> +  assert_is_type (e, c);
> +  _walk_op_n (e, 0);
> +  _walk_op_n (e, 1);
> +}
> +
> +void
> +expr_walker::_walk_CONSTRUCTOR (__attribute__ ((unused)) tree e)
> +{
> +  // Future-work: If we want to support rewriting CONSTRUCTORs
> +  // we will have to walk them
> +}
> +
> +void
> +expr_walker::_walk_LE_EXPR (tree e)
> +{
> +  _walk_op_1 (e, LE_EXPR);
> +}
> +
> +void
> +expr_walker::_walk_LT_EXPR (tree e)
> +{
> +  _walk_op_1 (e, LT_EXPR);
> +}
> +
> +void
> +expr_walker::_walk_EQ_EXPR (tree e)
> +{
> +  _walk_op_1 (e, EQ_EXPR);
> +}
> +
> +void
> +expr_walker::_walk_GT_EXPR (tree e)
> +{
> +  _walk_op_1 (e, GT_EXPR);
> +}
> +
> +void
> +expr_walker::_walk_GE_EXPR (tree e)
> +{
> +  _walk_op_1 (e, GE_EXPR);
> +}
> +
> +void
> +expr_walker::_walk_NE_EXPR (tree e)
> +{
> +  _walk_op_1 (e, NE_EXPR);
> +}
> +
> +void
> +expr_walker::_walk_INTEGER_CST (tree e)
> +{
> +  _walk_leaf (e, INTEGER_CST);
> +}
> +
> +void
> +expr_walker::_walk_REAL_CST (tree e)
> +{
> +  _walk_leaf (e, REAL_CST);
> +}
> +
> +void
> +expr_walker::_walk_STRING_CST (tree e)
> +{
> +  _walk_leaf (e, STRING_CST);
> +}
> +
> +void
> +expr_walker::_walk_BIT_FIELD_REF (__attribute__ ((unused)) tree e)
> +{
> +  // TODO:
> +  // We currently don't support bit_field_ref
> +  // but maybe we need to do something here?
> +}
> +
> +void
> +expr_walker::_walk_ARRAY_REF (tree e)
> +{
> +  _walk_op_1 (e, ARRAY_REF);
> +}
> +
> +void
> +expr_walker::_walk_MEM_REF (tree e)
> +{
> +  _walk_op_1 (e, MEM_REF);
> +}
> +
> +void
> +expr_walker::_walk_COMPONENT_REF (tree e)
> +{
> +  _walk_op_1 (e, COMPONENT_REF);
> +}
> +
> +void
> +expr_walker::_walk_SSA_NAME (tree e)
> +{
> +  _walk_leaf (e, SSA_NAME);
> +}
> +
> +void
> +expr_walker::_walk_ADDR_EXPR (tree e)
> +{
> +  _walk_op_0 (e, ADDR_EXPR);
> +}
> +
> +void
> +expr_walker::_walk_VIEW_CONVERT_EXPR (__attribute__ ((unused)) tree e)
> +{
> +  // TODO: I don't think we need to do anything here
> +}
> +
> +void
> +expr_walker::_walk_IMAGPART_EXPR (__attribute__ ((unused)) tree e)
> +{
> +  // TODO: I don't think we need to do anything here
> +}
> +
> +void
> +expr_walker::_walk_FIELD_DECL (tree e)
> +{
> +  _walk_leaf (e, FIELD_DECL);
> +}
> +
> +void
> +expr_walker::_walk_VAR_DECL (tree e)
> +{
> +  _walk_leaf (e, VAR_DECL);
> +}
> +
> +void
> +expr_walker::_walk_RESULT_DECL (tree e)
> +{
> +  _walk_leaf (e, RESULT_DECL);
> +}
> +
> +void
> +expr_walker::_walk_PARM_DECL (tree e)
> +{
> +  _walk_leaf (e, PARM_DECL);
> +}
> +
> +void
> +expr_walker::_walk_FUNCTION_DECL (tree e)
> +{
> +  _walk_leaf (e, FUNCTION_DECL);
> +  for (tree parm = DECL_ARGUMENTS (e); parm; parm = DECL_CHAIN (parm))
> +    {
> +      walk (parm);
> +    }
> +}
> +
> +/* Main interface for GimpleWalker:
> + * iterate over global variables and then for all functions
> + * with gimple body.
> + */
> +void
> +gimple_walker::walk ()
> +{
> +  _walk_globals ();
> +  std::set<tree> fndecls;
> +  cgraph_node *node = NULL;
> +  FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
> +    {
> +      node->get_untransformed_body ();
> +      tree decl = node->decl;
> +      gcc_assert (decl);
> +      const bool already_in_set = fndecls.find (decl) != fndecls.end ();
> +      // I think it is possible for different nodes to point to the same
> +      // declaration.
> +      if (already_in_set)
> +       continue;
> +
> +      _walk_cnode (node);
> +      fndecls.insert (decl);
> +    }
> +}
> +
> +/* For each global variable.  */
> +void
> +gimple_walker::_walk_globals ()
> +{
> +  varpool_node *vnode = NULL;
> +  FOR_EACH_VARIABLE (vnode)
> +    {
> +      _walk_global (vnode);
> +    }
> +}
> +
> +/* Walk over global variable VNODE.  */
> +void
> +gimple_walker::_walk_global (varpool_node *vnode)
> +{
> +  gcc_assert (vnode);
> +  struct ipa_ref *ref = NULL;
> +  for (unsigned i = 0; vnode->iterate_referring (i, ref); i++)
> +    {
> +      tree var_decl = vnode->decl;
> +      walk_tree2 (var_decl);
> +    }
> +}
> +
> +/* Walk over SSA_NAMEs in CNODE.  */
> +void
> +gimple_walker::_walk_ssa_names (cgraph_node *cnode)
> +{
> +  tree decl = cnode->decl;
> +  gcc_assert (decl);
> +  function *func = DECL_STRUCT_FUNCTION (decl);
> +  gcc_assert (func);
> +  size_t i = 0;
> +  tree ssa_name = NULL;
> +  push_cfun (func);
> +  FOR_EACH_SSA_NAME (i, ssa_name, cfun)
> +  {
> +    gcc_assert (ssa_name);
> +    walk_tree2 (ssa_name);
> +    tree ssa_name_var = SSA_NAME_VAR (ssa_name);
> +    if (!ssa_name_var)
> +      continue;
> +    walk_tree2 (ssa_name_var);
> +  }
> +  pop_cfun ();
> +}
> +
> +/* Walk over declaration, locals, ssa_names, and basic blocks
> + * in CNODE.  */
> +void
> +gimple_walker::_walk_cnode (cgraph_node *cnode)
> +{
> +  gcc_assert (cnode);
> +  _walk_decl (cnode);
> +  _walk_locals (cnode);
> +  _walk_ssa_names (cnode);
> +  _walk_bb (cnode);
> +}
> +
> +/* Walk over each local declaration in CNODE.  */
> +void
> +gimple_walker::_walk_locals (cgraph_node *cnode)
> +{
> +  tree decl = cnode->decl;
> +  gcc_assert (decl);
> +  function *func = DECL_STRUCT_FUNCTION (decl);
> +  gcc_assert (func);
> +  int i = 0;
> +  tree var_decl = NULL;
> +  FOR_EACH_LOCAL_DECL (func, i, var_decl)
> +    {
> +      gcc_assert (var_decl);
> +      walk_tree2 (var_decl);
> +    }
> +}
> +
> +/* Walk over all basic blocks in CNODE.  */
> +void
> +gimple_walker::_walk_bb (cgraph_node *cnode)
> +{
> +  gcc_assert (cnode);
> +  cnode->get_untransformed_body ();
> +  tree decl = cnode->decl;
> +  gcc_assert (decl);
> +  function *func = DECL_STRUCT_FUNCTION (decl);
> +  gcc_assert (func);
> +  basic_block bb = NULL;
> +  push_cfun (func);
> +  FOR_EACH_BB_FN (bb, func)
> +    {
> +      _walk (bb);
> +    }
> +  pop_cfun ();
> +}
> +
> +/* Walk over CNODE->decl.  */
> +void
> +gimple_walker::_walk_decl (cgraph_node *cnode)
> +{
> +  tree decl = cnode->decl;
> +  gcc_assert (decl);
> +  walk_tree2 (decl);
> +}
> +
> +/* Walk over each gimple statement in BB.  */
> +void
> +gimple_walker::_walk (basic_block bb)
> +{
> +  gcc_assert (bb);
> +  gimple_stmt_iterator gsi = gsi_start_bb (bb);
> +  while (!gsi_end_p (gsi))
> +    {
> +      this->_deleted = false;
> +      gimple *stmt = gsi_stmt (gsi);
> +      walk_gimple (stmt);
> +      // If it is not deleted just continue.
> +      if (!this->_deleted)
> +       {
> +         gsi_next (&gsi);
> +         continue;
> +       }
> +
> +      // Otherwise remove statement.
> +      unlink_stmt_vdef (stmt);
> +      gsi_remove (&gsi, true);
> +    }
> +
> +  // TODO: Maybe outline to its own function?
> +  for (gimple_stmt_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
> +       gsi_next (&gsi))
> +    {
> +      gimple *stmt = gsi_stmt (gsi);
> +      walk_gimple (stmt);
> +    }
> +}
> +
> +// call preorder callback
> +// walk subtrees
> +// call postorder callback
> +void
> +gimple_walker::walk_gimple (gimple *stmt)
> +{
> +  _walk_pre_gimple (stmt);
> +  _walk_gimple (stmt);
> +  _walk_post_gimple (stmt);
> +}
> +
> +/* Switch for different gimple instruction types.  */
> +void
> +gimple_walker::_walk_gimple (gimple *stmt)
> +{
> +// Do not use _walk_pre (s)
> +// Subtle but important distinction,
> +// we want to differentiate calling here stamtent from s
> +// TODO: Maybe delete though?
> +// This could also be the source for the double insertion to stack bug?
> +  if (gassign *_gassign = dyn_cast<gassign*> (stmt))
> +  {
> +    _walk_pre_gimple (stmt);
> +    walk_gassign (_gassign);
> +    _walk_post_gimple (stmt);
> +    return;
> +  }
> +
> +  if (greturn *_greturn = dyn_cast<greturn*> (stmt))
> +  {
> +    _walk_pre_gimple (stmt);
> +    walk_greturn (_greturn);
> +    _walk_post_gimple (stmt);
> +    return;
> +  }
> +
> +  if (gcond *_gcond = dyn_cast<gcond*> (stmt))
> +  {
> +    _walk_pre_gimple (stmt);
> +    walk_gcond (_gcond);
> +    _walk_post_gimple (stmt);
> +    return;
> +  }
> +
> +  if (gcall *_gcall = dyn_cast<gcall*> (stmt))
> +  {
> +    _walk_pre_gimple (stmt);
> +    walk_gcall (_gcall);
> +    _walk_post_gimple (stmt);
> +    return;
> +  }
> +
> +  if (glabel *_glabel = dyn_cast<glabel*> (stmt))
> +  {
> +    _walk_pre_gimple (stmt);
> +    walk_glabel (_glabel);
> +    _walk_post_gimple (stmt);
> +    return;
> +  }
> +
> +  if (gswitch *_gswitch = dyn_cast<gswitch*> (stmt))
> +  {
> +    _walk_pre_gimple (stmt);
> +    walk_gswitch (_gswitch);
> +    _walk_post_gimple (stmt);
> +    return;
> +  }
> +
> +
> +  if (gphi *_gphi = dyn_cast<gphi*> (stmt))
> +  {
> +    _walk_pre_gimple (stmt);
> +    walk_gphi (_gphi);
> +    _walk_post_gimple (stmt);
> +    return;
> +  }
> +
> +  const enum gimple_code code = gimple_code (stmt);
> +  switch (code)
> +    {
> +    case GIMPLE_PREDICT:
> +    case GIMPLE_DEBUG:
> +    case GIMPLE_NOP:
> +      // I think it is safe to skip these
> +      // but it would also be nice to walk their sub-trees
> +      return;
> +      break;
> +    default:
> +      break;
> +  }
> +
> +  // Break if something is unexpected.
> +  const char *name = gimple_code_name[code];
> +  log ("gimple code name %s\n", name);
> +  gcc_unreachable ();
> +}
> +
> +void
> +gimple_walker::walk_tree2 (tree t)
> +{
> +  _walk_pre_tree (t);
> +  _walk_tree (t);
> +  _walk_post_tree (t);
> +}
> +
> +void
> +gimple_walker::_walk_tree (__attribute__((unused)) tree t)
> +{}
> +
> +void
> +gimple_walker::walk_gassign (gassign *g)
> +{
> +  _walk_pre_gassign (g);
> +  _walk_gassign (g);
> +  _walk_post_gassign (g);
> +}
> +
> +void
> +gimple_walker::_walk_gassign (__attribute__((unused)) gassign *g)
> +{}
> +
> +void
> +gimple_walker::walk_greturn (greturn *g)
> +{
> +  _walk_pre_greturn (g);
> +  _walk_greturn (g);
> +  _walk_post_greturn (g);
> +}
> +
> +void
> +gimple_walker::_walk_greturn (__attribute__((unused)) greturn *g)
> +{}
> +
> +void
> +gimple_walker::walk_gcond (gcond *g)
> +{
> +  _walk_pre_gcond (g);
> +  _walk_gcond (g);
> +  _walk_post_gcond (g);
> +}
> +
> +void
> +gimple_walker::_walk_gcond (__attribute__((unused)) gcond *g)
> +{}
> +
> +void
> +gimple_walker::walk_gcall (gcall *g)
> +{
> +  _walk_pre_gcall (g);
> +  _walk_gcall (g);
> +  _walk_post_gcall (g);
> +}
> +
> +void
> +gimple_walker::_walk_gcall (__attribute__((unused)) gcall *g)
> +{}
> +
> +void
> +gimple_walker::walk_glabel (glabel *g)
> +{
> +  _walk_pre_glabel (g);
> +  _walk_glabel (g);
> +  _walk_post_glabel (g);
> +}
> +
> +void
> +gimple_walker::_walk_glabel (__attribute__((unused)) glabel *g)
> +{}
> +
> +void
> +gimple_walker::walk_gswitch (gswitch *g)
> +{
> +  _walk_pre_gswitch (g);
> +  _walk_gswitch (g);
> +  _walk_post_gswitch (g);
> +}
> +
> +void
> +gimple_walker::_walk_gswitch (__attribute__((unused)) gswitch *g)
> +{
> +}
> +
> +void
> +gimple_walker::walk_gphi (gphi *g)
> +{
> +  _walk_pre_gphi (g);
> +  _walk_gphi (g);
> +  _walk_post_gphi (g);
> +}
> +
> +void
> +gimple_walker::_walk_gphi (__attribute__((unused)) gphi *g)
> +{
> +}
> +
> +
> +void
> +type_collector::collect (tree t)
> +{
> +  const bool in_set = ptrset.in_universe (t);
> +  // Early memoization...
> +
> +  if (in_set)
> +    return;
> +
> +  // TODO: Can we move this to the beginning
> +  // of the function.
> +  gcc_assert (t);
> +
> +  // This is the map that holds the types
> +  // we will encounter in this walk.
> +  // It should be empty at the beginning.
> +  // It maps from tree -> bool.
> +  // The boolean will be updated to show
> +  // whether a record is reachable from
> +  // the type.
> +  gcc_assert (ptr.empty ());
> +  walk (t);
> +}
> +
> +// Make sure partitions are mutually exclusive.
> +void
> +type_collector::_sanity_check ()
> +{
> +  for (tset_t::iterator i = ptrset.points_to_record.begin (),
> +           e = ptrset.points_to_record.end ();
> +       i != e; ++i)
> +    {
> +      for (tset_t::iterator j = ptrset.complement.begin (),
> +           f = ptrset.complement.end ();
> +          j != f; ++j)
> +       {
> +         tree type_ptr = *i;
> +         gcc_assert (type_ptr);
> +         tree type_com = *j;
> +         gcc_assert (type_com);
> +         const bool valid_sets = type_ptr != type_com;
> +         if (valid_sets)
> +           continue;
> +
> +         // Normally, we want a stronger type comparison
> +         // that is not just the pointer address
> +         // but this is the first sanity check and then we will need to
> +         // determine the stronger type comparison.  But first we will
> need to
> +         // fix the types...
> +         gcc_unreachable ();
> +       }
> +    }
> +}
> +
> +/* Determine if T is already memoized in the TypeCollector.  */
> +bool
> +type_collector::is_memoized (tree t)
> +{
> +  /* If we haven't seen it then no.  */
> +  const bool in_set = ptrset.in_universe (t);
> +  if (!in_set)
> +    return false;
> +
> +  // If the memoized type points to a record
> +  // we must update all types that can refer
> +  // to memoized type.
> +  const bool points_to_record = ptrset.in_points_to_record (t);
> +  for (std::map<tree, bool>::iterator i = ptr.begin (),
> +       e = ptr.end (); i != e; ++i)
> +    {
> +      i->second |= points_to_record;
> +    }
> +  return true;
> +}
> +
> +void
> +type_collector::_walk_VOID_TYPE_pre (tree t)
> +{
> +  ptr[t] = false;
> +}
> +
> +void
> +type_collector::_walk_VOID_TYPE_post (tree t)
> +{
> +  _collect_simple (t);
> +}
> +
> +void
> +type_collector::_walk_INTEGER_TYPE_pre (tree t)
> +{
> +  ptr[t] = false;
> +}
> +
> +void
> +type_collector::_walk_INTEGER_TYPE_post (tree t)
> +{
> +  _collect_simple (t);
> +}
> +
> +void
> +type_collector::_walk_REAL_TYPE_pre (tree t)
> +{
> +  ptr[t] = false;
> +}
> +
> +void
> +type_collector::_walk_REAL_TYPE_post (tree t)
> +{
> +  _collect_simple (t);
> +}
> +
> +void
> +type_collector::_walk_FIXED_POINT_TYPE_pre (tree t)
> +{
> +  ptr[t] = false;
> +}
> +
> +void
> +type_collector::_walk_FIXED_POINT_TYPE_post (tree t)
> +{
> +  _collect_simple (t);
> +}
> +
> +void
> +type_collector::_walk_COMPLEX_TYPE_pre (tree t)
> +{
> +  ptr[t] = false;
> +}
> +
> +void
> +type_collector::_walk_COMPLEX_TYPE_post (tree t)
> +{
> +  _collect_simple (t);
> +}
> +
> +void
> +type_collector::_walk_ENUMERAL_TYPE_pre (tree t)
> +{
> +  ptr[t] = false;
> +}
> +
> +void
> +type_collector::_walk_ENUMERAL_TYPE_post (tree t)
> +{
> +  _collect_simple (t);
> +}
> +
> +void
> +type_collector::_walk_BOOLEAN_TYPE_pre (tree t)
> +{
> +  ptr[t] = false;
> +}
> +
> +void
> +type_collector::_walk_BOOLEAN_TYPE_post (tree t)
> +{
> +  _collect_simple (t);
> +}
> +
> +void
> +type_collector::_collect_simple (tree t)
> +{
> +  // Insert into persistent set.
> +  ptrset.insert (t, ptr[t]);
> +  // erase from current working set.
> +  ptr.erase (t);
> +}
> +
> +void
> +type_collector::_walk_ARRAY_TYPE_pre (tree t)
> +{
> +  ptr[t] = false;
> +}
> +
> +void
> +type_collector::_walk_ARRAY_TYPE_post (tree t)
> +{
> +  _collect_simple (t);
> +}
> +
> +void
> +type_collector::_walk_POINTER_TYPE_pre (tree t)
> +{
> +  ptr[t] = false;
> +}
> +
> +void
> +type_collector::_walk_POINTER_TYPE_post (tree t)
> +{
> +  _collect_simple (t);
> +}
> +
> +void
> +type_collector::_walk_REFERENCE_TYPE_pre (tree t)
> +{
> +  ptr[t] = false;
> +}
> +
> +void
> +type_collector::_walk_REFERENCE_TYPE_post (tree t)
> +{
> +  _collect_simple (t);
> +}
> +
> +void
> +type_collector::_walk_RECORD_TYPE_post (tree t)
> +{
> +  // All in ptr point to record
> +  for (std::map<tree, bool>::iterator i = ptr.begin (),
> +       e = ptr.end (); i != e; ++i)
> +    {
> +      i->second = true;
> +    }
> +  _collect_simple (t);
> +}
> +
> +void
> +type_collector::_walk_RECORD_TYPE_pre (tree t)
> +{
> +  ptr[t] = false;
> +}
> +
> +void
> +type_collector::_walk_UNION_TYPE_pre (tree t)
> +{
> +  ptr[t] = false;
> +}
> +
> +void
> +type_collector::_walk_UNION_TYPE_post (tree t)
> +{
> +  _collect_simple (t);
> +}
> +
> +void
> +type_collector::_walk_FUNCTION_TYPE_post (tree t)
> +{
> +  _collect_simple (t);
> +}
> +
> +void
> +type_collector::_walk_FUNCTION_TYPE_pre (tree t)
> +{
> +  ptr[t] = false;
> +}
> +
> +void
> +type_collector::_walk_METHOD_TYPE_post (tree t)
> +{
> +  _collect_simple (t);
> +}
> +
> +void
> +type_collector::_walk_METHOD_TYPE_pre (tree t)
> +{
> +  ptr[t] = false;
> +}
> +
> +inline void
> +expr_collector::_walk_pre (tree e)
> +{
> +  tree t = TREE_TYPE (e);
> +  gcc_assert (t);
> +  typeCollector.collect (t);
> +}
> +
> +/*
> + * For global variables T, this method will collect
> + * and partition trees corresponding to types
> + * into std::sets.  Concretely speaking, this class
> + * partitions trees into two sets:
> + * * reach a RECORD_TYPE
> + * * does not reach a RECORD_TYPE.
> + */
> +void
> +gimple_type_collector::_walk_pre_tree (tree t)
> +{
> +  _expr_collector.walk (t);
> +}
> +
> +/*
> + * For assignment statements S, this method will collect
> + * and partition trees corresponding to types
> + * into std::sets.  Concretely speaking, this class
> + * partitions trees into two sets:
> + * * reach a RECORD_TYPE
> + * * does not reach a RECORD_TYPE
> + * The types reachable from the lhs and rhs are placed
> + * in these sets.
> + */
> +void
> +gimple_type_collector::_walk_pre_gassign (gassign *s)
> +{
> +  tree lhs = gimple_assign_lhs (s);
> +  _expr_collector.walk (lhs);
> +
> +  const enum gimple_rhs_class gclass = gimple_assign_rhs_class (s);
> +  switch (gclass)
> +    {
> +    case GIMPLE_TERNARY_RHS:
> +      {
> +       tree rhs = gimple_assign_rhs3 (s);
> +       _expr_collector.walk (rhs);
> +      }
> +    /* fall-through */
> +    case GIMPLE_BINARY_RHS:
> +      {
> +       tree rhs = gimple_assign_rhs2 (s);
> +       _expr_collector.walk (rhs);
> +      }
> +    /* fall-through */
> +    case GIMPLE_UNARY_RHS:
> +    case GIMPLE_SINGLE_RHS:
> +      {
> +       tree rhs = gimple_assign_rhs1 (s);
> +       _expr_collector.walk (rhs);
> +      }
> +      break;
> +    default:
> +      gcc_unreachable ();
> +      break;
> +    }
> +}
> +
> +void
> +gimple_type_collector::_walk_pre_greturn (greturn *s)
> +{
> +  tree retval = gimple_return_retval (s);
> +  if (!retval)
> +    return;
> +
> +  _expr_collector.walk (retval);
> +}
> +
> +void
> +gimple_type_collector::_walk_pre_gcall (gcall *s)
> +{
> +  // Walk over the arguments.
> +  unsigned n = gimple_call_num_args (s);
> +  for (unsigned i = 0; i < n; i++)
> +    {
> +      tree a = gimple_call_arg (s, i);
> +      _expr_collector.walk (a);
> +    }
> +
> +  // Walk over the return type if it exists.
> +  tree lhs = gimple_call_lhs (s);
> +  if (!lhs)
> +    return;
> +
> +  _expr_collector.walk (lhs);
> +}
> +
> +// Print working set.
> +void
> +gimple_type_collector::print_collected ()
> +{
> +  tpartitions_t sets = get_record_reaching_trees ();
> +}
> +
> +/* Walk over LHS and RHS of conditions.  */
> +void
> +gimple_type_collector::_walk_pre_gcond (gcond *s)
> +{
> +  tree lhs = gimple_cond_lhs (s);
> +  _expr_collector.walk (lhs);
> +  tree rhs = gimple_cond_rhs (s);
> +  _expr_collector.walk (rhs);
> +}
> +
> +bool
> +type_escaper::is_memoized (__attribute__ ((unused)) tree t)
> +{
> +  // Can't memoize here because
> +  // information is propagated up and down
> +  // the type.
> +  return false;
> +}
> +
> +tpartitions_t
> +type_escaper::get_sets ()
> +{
> +  place_escaping_types_in_set ();
> +  return _ptrset;
> +}
> +
> +/* From a map of TREE -> BOOL, the key represents a tree type
> + * and the value represents whether the tree escapes.
> + * Partition this map into sets.
> + */
> +void
> +type_escaper::place_escaping_types_in_set ()
> +{
> +  type_stringifier stringifier;
> +  for (typemap::iterator i = calc.begin (), e = calc.end (); i != e; ++i)
> +    {
> +      tree type = i->first;
> +
> +      // We should only track interesting types
> +      // Types which are not in points_to_record are the ones
> +      // that are pointed to by records.
> +      // I think it is possible to prune them ahead of time...
> +      if (!_ptrset.in_points_to_record (type))
> +       continue;
> +
> +      const Reason reason = i->second;
> +      reason.is_escaping () ? _ptrset.escaping.insert (type)
> +                           : _ptrset.non_escaping.insert (type);
> +    }
> +}
> +
> +void
> +type_escaper::update (tree t, Reason r)
> +{
> +  gcc_assert (t);
> +  _reason = r;
> +  walk (t);
> +}
> +
> +void
> +type_escaper::_update_single (tree t, Reason r)
> +{
> +  gcc_assert (t);
> +  _reason = r;
> +  _update (t);
> +}
> +
> +void
> +type_escaper::_update (tree t)
> +{
> +  gcc_assert (t);
> +  const bool already_in_typemap = calc.find (t) != calc.end ();
> +  // Do we have to invalidate all types which point to a volatile type?
> +  // Or do we have to invalidate all types pointed to by a volatile type?
> +  // Or do we only invalidate all types which are volatile.
> +  // This is only the third option.
> +  const bool is_volatile = TYPE_VOLATILE (t);
> +  Reason _is_volatile;
> +  _is_volatile.type_is_volatile = is_volatile;
> +  Reason _inner = _reason | _is_volatile;
> +  // always OR
> +  already_in_typemap ? calc[t] |= _inner : calc[t] = _inner;
> +}
> +
> +void
> +type_escaper::_walk_ARRAY_TYPE_pre (tree t)
> +{
> +  _update (t);
> +}
> +
> +void
> +type_escaper::_walk_ARRAY_TYPE_post (tree t)
> +{
> +  _update (t);
> +}
> +
> +void
> +type_escaper::_walk_POINTER_TYPE_pre (tree t)
> +{
> +  _update (t);
> +}
> +
> +void
> +type_escaper::_walk_POINTER_TYPE_post (tree t)
> +{
> +  _update (t);
> +}
> +
> +void
> +type_escaper::_walk_REFERENCE_TYPE_pre (tree t)
> +{
> +  _update (t);
> +}
> +
> +void
> +type_escaper::_walk_RECORD_TYPE_pre (tree t)
> +{
> +  // we are entering a record
> +  _inside_record++;
> +  _update (t);
> +}
> +
> +void
> +type_escaper::_walk_RECORD_TYPE_post (tree t)
> +{
> +  _update (t); // This is in case there was a union
> +  // we are exiting a record
> +  _inside_record--;
> +}
> +
> +/* Mark as escaping because of union
> + * and propagate up and down.
> + */
> +void
> +type_escaper::_walk_UNION_TYPE_pre (tree t)
> +{
> +  _inside_union++;
> +  bool is_escaping = _inside_union > 0;
> +  _reason.type_is_in_union |= is_escaping;
> +  _update (t);
> +}
> +
> +/* Mark bit fields as escaping and propagate up
> + * and down.
> + */
> +void
> +type_escaper::_walk_field_pre (tree t)
> +{
> +  _reason.type_is_in_union |= DECL_BIT_FIELD (t);
> +}
> +
> +void
> +type_escaper::_walk_UNION_TYPE_post (tree t)
> +{
> +  _inside_union--;
> +  _update (t);
> +}
> +
> +/* Mark as escaping because RECORD has a function pointer
> + * propagate up and down.
> + */
> +void
> +type_escaper::_walk_FUNCTION_TYPE_pre (__attribute__ ((unused)) tree t)
> +{
> +  _reason.type_is_in_union |= _inside_record > 0;
> +}
> +
> +/* Mark as escaping because RECORD has a function pointer
> + * propagate up and down.
> + */
> +void
> +type_escaper::_walk_METHOD_TYPE_pre (__attribute__ ((unused)) tree t)
> +{
> +  _reason.type_is_in_union |= _inside_record > 0;
> +}
> +
> +/* Print escaping reasons.  */
> +void
> +type_escaper::print_reasons ()
> +{
> +  type_stringifier stringifier;
> +  for (typemap::iterator i = calc.begin (), e = calc.end (); i != e; ++i)
> +    {
> +      tree t = i->first;
> +      std::string name = stringifier.stringify (t);
> +      Reason r = i->second;
> +      log ("%s reason: ", name.c_str ());
> +      r.print ();
> +    }
> +}
> +
> +tpartitions_t
> +expr_escaper::get_sets ()
> +{
> +  return _type_escaper.get_sets ();
> +}
> +
> +void
> +expr_escaper::print_reasons ()
> +{
> +  _type_escaper.print_reasons ();
> +}
> +
> +/* Propagate reason to subexpressions.  */
> +void
> +expr_escaper::update (tree t, Reason r)
> +{
> +  gcc_assert (t);
> +  _r = r;
> +  walk (t);
> +}
> +
> +/* Propagate reason to type of subexpressions.  */
> +void
> +expr_escaper::_walk_pre (tree e)
> +{
> +  _stack.push (e);
> +  tree t = TREE_TYPE (e);
> +
> +  gcc_assert (t);
> +  _type_escaper.update (t, _r);
> +}
> +
> +void
> +expr_escaper::_walk_post (__attribute__ ((unused)) tree e)
> +{
> +  _stack.pop ();
> +}
> +
> +/* Capture casting on LHS.  */
> +void
> +expr_escaper::_walk_SSA_NAME_pre (tree e)
> +{
> +  tree ssa_type = TREE_TYPE (e);
> +
> +
> +  if (_stack.size () < 4)
> +    return;
> +
> +  tree this_expr = _stack.top ();
> +  _stack.pop ();
> +  tree twice = _stack.top ();
> +  _stack.pop ();
> +  tree prev_expr = _stack.top ();
> +  _stack.push (twice);
> +  _stack.push (this_expr);
> +  if (TREE_CODE (prev_expr) != MEM_REF)
> +    return;
> +
> +  tree op1 = TREE_OPERAND (prev_expr, 1);
> +  gcc_assert (TREE_CODE (op1) == INTEGER_CST);
> +  tree mref_type = TREE_TYPE (op1);
> +
> +  Reason old_reason = _r;
> +  type_incomplete_equality structuralEquality;
> +  // we need to make sure that both of them point to structs?
> +  if (TREE_CODE (TREE_TYPE (mref_type)) == INTEGER_TYPE)
> +    return;
> +
> +  _r.type_is_casted = !structuralEquality.equal (mref_type, ssa_type);
> +  type_stringifier stringifier;
> +  log ("mref_type is casted %s = %s\n",
> stringifier.stringify(mref_type).c_str(), _r.type_is_casted ? "T" : "F");
> +  log ("ssa_type is casted %s = %s\n",
> stringifier.stringify(ssa_type).c_str(), _r.type_is_casted ? "T" : "F");
> +  _type_escaper._update_single (mref_type, _r);
> +  _type_escaper._update_single (ssa_type, _r);
> +  _r = old_reason;
> +}
> +
> +/* Mark constructors as escaping.  */
> +void
> +expr_escaper::_walk_CONSTRUCTOR_pre (tree e)
> +{
> +  if (TREE_CLOBBER_P (e))
> +    return;
> +
> +  // TODO: Instead of overloading global_is_visible field
> +  // with has a constructor, make a field that denotes that
> +  // a this has a constructor.
> +  // Or better yet... modify the constructors!
> +  _r.global_is_visible = true;
> +  tree t = TREE_TYPE (e);
> +  _type_escaper.update (t, _r);
> +}
> +
> +tpartitions_t
> +gimple_escaper::get_sets ()
> +{
> +  _expr_escaper.curr_node = NULL;
> +  return _expr_escaper.get_sets ();
> +}
> +
> +void
> +gimple_escaper::print_reasons ()
> +{
> +  _expr_escaper.curr_node = NULL;
> +  _expr_escaper.print_reasons ();
> +}
> +
> +/* Initialize undefined set of functions.  */
> +void
> +gimple_escaper::_init ()
> +{
> +  cgraph_node *cnode = NULL;
> +  FOR_EACH_FUNCTION (cnode)
> +    {
> +      gcc_assert (cnode);
> +      const bool filter = gimple_escaper::filter_known_function (cnode);
> +      if (filter)
> +       continue;
> +
> +      tree decl = cnode->decl;
> +      gcc_assert (decl);
> +      undefined.insert (decl);
> +    }
> +
> +  FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (cnode)
> +    {
> +      gcc_assert (cnode);
> +      cnode->get_untransformed_body ();
> +      tree decl = cnode->decl;
> +      gcc_assert (decl);
> +      undefined.erase (decl);
> +    }
> +}
> +
> +/* Mark cnode graphs escaping if they are externally visible.  */
> +bool
> +gimple_escaper::is_function_escaping (cgraph_node *cnode)
> +{
> +  const bool filter = gimple_escaper::filter_known_function (cnode);
> +  if (filter)
> +    return false;
> +
> +  return cnode->externally_visible;
> +}
> +
> +/* Mark fndecl as escaping is they are externally visible or
> + * there is no fndecl.  */
> +bool
> +gimple_escaper::is_function_escaping (tree fndecl)
> +{
> +  if (!fndecl)
> +    return true;
> +
> +  if (!TREE_PUBLIC (fndecl) && !DECL_EXTERNAL (fndecl))
> +    return false;
> +
> +  return true;
> +}
> +
> +/* Mark variable as escaping if it is externally visible.  */
> +bool
> +gimple_escaper::is_variable_escaping (varpool_node *vnode)
> +{
> +  gcc_assert (vnode);
> +  const bool retval = vnode->externally_visible;
> +  const bool retval2 = vnode->externally_visible_p ();
> +  log("%s externally_visible = %d %d\n", vnode->name (), retval, retval2);
> +  return retval;
> +}
> +
> +/* Walk global variable VNODE.  */
> +void
> +gimple_escaper::_walk_global (varpool_node *vnode)
> +{
> +  gcc_assert (vnode);
> +  tree var_decl = vnode->decl;
> +  Reason reason;
> +  const bool is_escaping = is_variable_escaping (vnode);
> +  reason.global_is_visible = is_escaping;
> +
> +  // TODO: Instead of overloading the semantic meaning of global is
> visible
> +  // make different fields for CONSTRUCTOR and for CONSTRUCTOR is not
> in linking
> +  // unit
> +  // TODO: Once we are able to rewrite the CONSTRUCTOR we can get rid
> of marking
> +  // types with bracket constructors as illegal.
> +  tree initial = DECL_INITIAL (var_decl);
> +  const bool constructor = initial ? TREE_CODE (initial) == CONSTRUCTOR
> : false;
> +  const bool error_mark = initial ? TREE_CODE (initial) == ERROR_MARK :
> false;
> +  reason.global_is_visible
> +    |= constructor || error_mark; // static initialization...
> +
> +  _expr_escaper.update (var_decl, reason);
> +  gimple_walker::_walk_global (vnode);
> +}
> +
> +/* Return true if FNDECL is a known function.  */
> +bool
> +gimple_escaper::filter_known_function (tree fndecl)
> +{
> +  assert_is_type (fndecl, FUNCTION_DECL);
> +  if (fndecl_built_in_p (fndecl))
> +    {
> +      switch (DECL_FUNCTION_CODE (fndecl))
> +       {
> +       case BUILT_IN_FREE:
> +       case BUILT_IN_MALLOC:
> +       case BUILT_IN_REALLOC:
> +       case BUILT_IN_CALLOC:
> +       case BUILT_IN_MEMSET:
> +         return true;
> +         break;
> +       default:
> +         break;
> +       }
> +    }
> +
> +  return false;
> +}
> +
> +/* Return True if NODE points to a known FUNCTION_DECL.  */
> +bool
> +gimple_escaper::filter_known_function (cgraph_node *node)
> +{
> +  if (!node)
> +    return false;
> +  return filter_known_function (node->decl);
> +}
> +
> +/* Mark Variable declaration of unknown location as escaping.  */
> +void
> +gimple_escaper::_walk_pre_tree (tree t)
> +{
> +  // Is any global variable escaping?
> +  Reason reason;
> +  if (TREE_CODE (t) == VAR_DECL)
> +    {
> +      if (DECL_SOURCE_LOCATION (t) == UNKNOWN_LOCATION)
> +       // Detecting some builtin types
> +       // I think fprofile-generate inserts some builtin types which
> +       // cannot be detected in any other way...
> +       // TODO: Maybe add a new reason instead of overloading is_indirect.
> +       reason.is_indirect = true;
> +    }
> +  _expr_escaper.update (t, reason);
> +}
> +
> +void
> +gimple_escaper::_walk_pre_gassign (gassign *s)
> +{
> +  Reason reason;
> +  const enum gimple_rhs_class code = gimple_assign_rhs_class (s);
> +  switch (code)
> +    {
> +    case GIMPLE_TERNARY_RHS:
> +      {
> +       tree rhs3 = gimple_assign_rhs3 (s);
> +       _expr_escaper.update (rhs3, reason);
> +      }
> +    /* fall-through */
> +    case GIMPLE_BINARY_RHS:
> +      {
> +       tree rhs2 = gimple_assign_rhs2 (s);
> +       _expr_escaper.update (rhs2, reason);
> +      }
> +    /* fall-through */
> +    case GIMPLE_UNARY_RHS:
> +    case GIMPLE_SINGLE_RHS:
> +      {
> +       tree rhs1 = gimple_assign_rhs1 (s);
> +       _expr_escaper.update (rhs1, reason);
> +       tree lhs = gimple_assign_lhs (s);
> +       if (!lhs)
> +         break;
> +       _expr_escaper.update (lhs, reason);
> +      }
> +      break;
> +    default:
> +      gcc_unreachable ();
> +      break;
> +    }
> +}
> +
> +void
> +gimple_escaper::_walk_pre_greturn (greturn *s)
> +{
> +  Reason reason;
> +  tree val = gimple_return_retval (s);
> +  if (!val)
> +    return;
> +  _expr_escaper.update (val, reason);
> +}
> +
> +void
> +gimple_escaper::_walk_pre_gcond (gcond *s)
> +{
> +  Reason reason;
> +  tree lhs = gimple_cond_lhs (s);
> +  tree rhs = gimple_cond_rhs (s);
> +  gcc_assert (lhs && rhs);
> +  _expr_escaper.update (lhs, reason);
> +  _expr_escaper.update (rhs, reason);
> +}
> +
> +void
> +gimple_escaper::_walk_pre_gcall (gcall *s)
> +{
> +  tree fn = gimple_call_fndecl (s);
> +  // gcc_assert (fn);
> +  // The above will not always be true
> +  // It will be false when we have an indirect function
> +  cgraph_node *node = fn ? cgraph_node::get (fn) : NULL;
> +  type_stringifier stringifier;
> +  const bool _is_function_escaping
> +    = node ? is_function_escaping (node) : is_function_escaping (fn);
> +  const bool is_undefined = undefined.find (fn) != undefined.end ();
> +  log ("is undefined %s\n", is_undefined ? "t" : "f");
> +  const bool _is_escaping = is_undefined || _is_function_escaping;
> +
> +  Reason arg_reason;
> +  arg_reason.parameter_is_visible = _is_escaping;
> +  arg_reason.is_indirect = !fn;
> +  unsigned n = gimple_call_num_args (s);
> +  for (unsigned i = 0; i < n; i++)
> +    {
> +      tree a = gimple_call_arg (s, i);
> +      gcc_assert (a);
> +      if (arg_reason.is_escaping ())
> +       {
> +         std::string name = stringifier.stringify (TREE_TYPE (a));
> +         log ("escaping parameter %s\n", name.c_str ());
> +       }
> +      _expr_escaper._type_escaper.update (TREE_TYPE (a), arg_reason);
> +    }
> +
> +  tree lhs = gimple_call_lhs (s);
> +  if (!lhs)
> +    return;
> +  Reason return_reason;
> +  return_reason.return_is_visible = _is_escaping;
> +  return_reason.is_indirect = !fn;
> +  _expr_escaper.update (lhs, return_reason);
> +}
> +
> +/* Determine if cast comes from a known function.
> + * Do this by following the use-def chain.  */
> +bool
> +gimple_caster::follow_def_to_find_if_really_cast (tree rhs)
> +{
> +  gimple *def_for_rhs = SSA_NAME_DEF_STMT (rhs);
> +  gcall *is_call = dyn_cast<gcall *> (def_for_rhs);
> +  if (!is_call)
> +    return true;
> +
> +  tree fn = gimple_call_fndecl (is_call);
> +  if (!fn)
> +    return true;
> +
> +  bool known_function = gimple_escaper::filter_known_function (fn);
> +  return !known_function;
> +}
> +
> +void
> +gimple_caster::_walk_pre_gassign (gassign *s)
> +{
> +  const enum gimple_rhs_class code = gimple_assign_rhs_class (s);
> +  const bool valid_input = GIMPLE_SINGLE_RHS == code;
> +  if (!valid_input)
> +    return;
> +
> +  // I originally was using gimple_assign_cast_p
> +  // but that proved to be insufficient...
> +  // So we have to use our equality comparison...
> +  type_incomplete_equality equality;
> +  tree lhs = gimple_assign_lhs (s);
> +  tree rhs = gimple_assign_rhs1 (s);
> +  gcc_assert (lhs && rhs);
> +  Reason reason;
> +  tree t_lhs = TREE_TYPE (lhs);
> +  tree t_rhs = TREE_TYPE (rhs);
> +  gcc_assert (t_lhs && t_rhs);
> +
> +  type_stringifier stringifier;
> +  bool is_cast = !equality.equal (TYPE_MAIN_VARIANT(t_lhs),
> TYPE_MAIN_VARIANT(t_rhs));
> +  // If it is cast, we might need to look at the definition of rhs
> +  // If the definition comes from a known function... then we are good...
> +  bool is_ssa = TREE_CODE (rhs) == SSA_NAME;
> +  is_cast = is_cast && is_ssa ? follow_def_to_find_if_really_cast (rhs)
> : is_cast;
> +  // we allow casts to pointers...
> +  is_cast = is_cast && !(t_lhs == ptr_type_node);
> +  reason.type_is_casted = is_cast;
> +  _expr_escaper._type_escaper.update (TREE_TYPE (lhs), reason);
> +  _expr_escaper._type_escaper.update (TREE_TYPE (rhs), reason);
> +
> +  gimple_escaper::_walk_pre_gassign (s);
> +}
> +
> +/* Check to see if arguments are casted.  */
> +void
> +gimple_caster::_walk_pre_gcall (gcall *s)
> +{
> +  gimple_escaper::_walk_pre_gcall (s);
> +
> +  tree fn = gimple_call_fndecl (s);
> +  // If there's no function declaration, how do we
> +  // know the argument types?
> +  if (!fn)
> +    return;
> +
> +  cgraph_node *node = cgraph_node::get (fn);
> +  const bool known_function = gimple_escaper::filter_known_function (node)
> +                             || gimple_escaper::filter_known_function
> (fn);
> +  if (known_function)
> +    return;
> +
> +  tree f_t = TREE_TYPE (fn);
> +  type_incomplete_equality equality;
> +
> +  unsigned i = 0;
> +  type_stringifier stringifier;
> +  for (tree a = TYPE_ARG_TYPES (f_t); NULL_TREE != a; a = TREE_CHAIN (a))
> +    {
> +      tree formal_t = TREE_VALUE (a);
> +      // There seems to be a final VOID_TYPE at the end of some functions?
> +      const enum tree_code code = TREE_CODE (formal_t);
> +      const bool is_void = VOID_TYPE == code;
> +      if (is_void)
> +       continue;
> +
> +      tree real = gimple_call_arg (s, i);
> +      tree real_t = TREE_TYPE (real);
> +      bool is_casted = !equality.equal (formal_t, real_t);
> +      is_casted = is_casted && (formal_t != ptr_type_node);
> +      log("arg %s is casted: %s\n",
> stringifier.stringify(real_t).c_str(), is_casted ? "T" : "F");
> +      Reason arg_reason;
> +      arg_reason.type_is_casted = is_casted;
> +      _expr_escaper._type_escaper.update (TREE_TYPE (real), arg_reason);
> +      i++;
> +    }
> +
> +  tree lhs = gimple_call_lhs (s);
> +  if (!lhs)
> +    return;
> +
> +  tree r_t = TREE_TYPE (f_t);
> +  tree l_t TREE_TYPE (lhs);
> +  const bool is_casted = !equality.equal (r_t, l_t);
> +  log ("ret %s is casted: %s\n", stringifier.stringify(l_t).c_str(),
> is_casted ? "T" : "F");
> +  Reason ret_reason;
> +  ret_reason.type_is_casted = is_casted;
> +  _expr_escaper.update (lhs, ret_reason);
> +}
> +
> +bool
> +type_accessor::is_memoized (tree t)
> +{
> +  return memoized_map.find (t) != memoized_map.end ();
> +}
> +
> +/* Add all fields in struct to memoized map.  */
> +void
> +type_accessor::_walk_RECORD_TYPE_pre (tree t)
> +{
> +  add_all_fields_in_struct (t);
> +  memoized_map.insert (t);
> +}
> +
> +/* Initialize all fields as neither read nor written.  */
> +void
> +type_accessor::add_all_fields_in_struct (tree t)
> +{
> +  const enum tree_code c = TREE_CODE (t);
> +  const bool is_record = RECORD_TYPE == c;
> +  if (!is_record)
> +    return;
> +
> +  const bool record_already_in_map = _map.find (t) != _map.end ();
> +  field_access_map_t field_map;
> +  field_map = record_already_in_map ? _map[t] : field_map;
> +
> +  // Let's add all fields to the field map as empty.
> +  for (tree field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field))
> +    {
> +      const bool field_already_in_map_2
> +       = field_map.find (field) != field_map.end ();
> +      if (field_already_in_map_2)
> +       continue;
> +      field_map[field] = Empty;
> +    }
> +
> +  _map[t] = field_map;
> +}
> +
> +record_field_map_t
> +expr_accessor::get_map ()
> +{
> +  return record_field_map;
> +}
> +
> +void
> +expr_accessor::add_all_fields_in_struct (tree t)
> +{
> +  _type_accessor.walk (t);
> +}
> +
> +void
> +expr_accessor::_walk_pre (tree e)
> +{
> +  _stack.push (e);
> +  tree t = TREE_TYPE (e);
> +  add_all_fields_in_struct (t);
> +}
> +
> +void
> +expr_accessor::_walk_post (__attribute__ ((unused)) tree e)
> +{
> +  _stack.pop ();
> +}
> +
> +void
> +expr_accessor::update (tree e, unsigned access)
> +{
> +  _access = access;
> +  walk (e);
> +}
> +
> +/* Check if we are accessing a field
> + * through pointer arithmetic.  If this is happening
> + * it is likely the result of an optimization.
> + * Since we are not modifying these types of expressions yet
> + * we must mark all fields leading to the accessed fields
> + * as possibly READ.
> +
> + * TODO: If we modify this expression later on, we could
> + * make our transformation more powerful and precise by
> + * not marking all fields leading up to this one as possibly
> + * read.
> + */
> +void
> +expr_accessor::_walk_ADDR_EXPR_pre (__attribute__ ((unused)) tree e)
> +{
> +  log ("expr accessor mem ref\n");
> +  log ("stack size = %d\n", _stack.size ());
> +
> +  if (_stack.size () < 4)
> +    return;
> +
> +  // TODO: Fix error with double pushing
> +  tree addr_expr = _stack.top ();
> +  _stack.pop ();
> +  tree twice = _stack.top ();
> +  _stack.pop ();
> +  tree prev_expr = _stack.top ();
> +  _stack.push (addr_expr);
> +  _stack.push (twice);
> +  log ("prev_expr code = %s\n", get_tree_code_name (TREE_CODE
> (prev_expr)));
> +  if (TREE_CODE (prev_expr) != MEM_REF)
> +    return;
> +
> +  tree op_0 = TREE_OPERAND (addr_expr, 0);
> +  tree addr_expr_t = TREE_TYPE (op_0);
> +
> +  type_stringifier stringifier;
> +  std::string name = stringifier.stringify (addr_expr_t);
> +  log ("accessing a field through memref...? %s\n", name.c_str ());
> +  if (TREE_CODE (addr_expr_t) != RECORD_TYPE)
> +    return;
> +
> +  // We are accessing a field of a record through pointer arithmetic...
> +  // So what field offset are we computing...
> +  tree mref_expr = prev_expr;
> +  tree offset = TREE_OPERAND (mref_expr, 1);
> +  gcc_assert (TREE_CODE (offset) == INTEGER_CST);
> +  tree type_size_tree = TYPE_SIZE_UNIT (addr_expr_t);
> +  int type_size_int = tree_to_shwi (type_size_tree);
> +  // TODO: Very recently inserted this assertion so we need to test this
> +  gcc_assert (type_size_int > 0);
> +  unsigned offset_int = tree_to_uhwi (offset) % type_size_int;
> +  // We need to get the field that corresponds to the offset_int
> +  const bool record_already_in_map
> +    = record_field_map.find (addr_expr_t) != record_field_map.end ();
> +  field_access_map_t field_map;
> +  field_map = record_already_in_map ? record_field_map[addr_expr_t] :
> field_map;
> +
> +  tree field = NULL;
> +  for (field = TYPE_FIELDS (addr_expr_t); field; field = DECL_CHAIN
> (field))
> +    {
> +      log ("ever inside?\n");
> +      unsigned f_byte_offset = tree_to_uhwi (DECL_FIELD_OFFSET (field));
> +      unsigned f_offset = f_byte_offset;
> +      log ("offset field %d, offset by pointer %d\n", f_offset,
> offset_int);
> +
> +      // NOTE: ALL FIELDS BEFORE THIS ONE NEED TO EXIST
> +      // Otherwise, this pointer arithmetic is invalid...
> +      // After the transformation
> +      const bool field_already_in_map
> +       = field_map.find (field) != field_map.end ();
> +      unsigned prev_access = field_already_in_map ? field_map[field] :
> Empty;
> +
> +      prev_access |= Read;
> +      field_map[field] = prev_access;
> +      add_all_fields_in_struct (addr_expr_t);
> +      record_field_map[addr_expr_t] = field_map;
> +
> +      if (f_offset == offset_int)
> +       break;
> +    }
> +}
> +
> +/* Find out if we are taking the address of a FIELD_DECL.
> + * If this is the case, it means that all FIELDS in this
> + * RECORD_TYPE should be marked as READ for safety.
> + */
> +void
> +expr_accessor::_walk_COMPONENT_REF_pre (tree e)
> +{
> +  log ("in component_ref pre\n");
> +  assert_is_type (e, COMPONENT_REF);
> +  tree op0 = TREE_OPERAND (e, 0);
> +  gcc_assert (op0);
> +  tree op0_t = TREE_TYPE (op0);
> +  gcc_assert (op0_t);
> +  // op0_t can either be a RECORD_TYPE or a UNION_TYPE.
> +  const enum tree_code code = TREE_CODE (op0_t);
> +  const bool is_record = RECORD_TYPE == code;
> +  const bool is_union = UNION_TYPE == code;
> +  const bool valid = is_record != is_union;
> +  gcc_assert (valid);
> +
> +  tree op1 = TREE_OPERAND (e, 1);
> +  assert_is_type (op1, FIELD_DECL);
> +  log ("%s.%s\n", type_stringifier::get_type_identifier (op0_t).c_str(),
> +       type_stringifier::get_field_identifier (op1).c_str());
> +  const bool record_already_in_map
> +    = record_field_map.find (op0_t) != record_field_map.end ();
> +  field_access_map_t field_map;
> +  field_map = record_already_in_map ? record_field_map[op0_t] : field_map;
> +  const bool field_already_in_map = field_map.find (op1) !=
> field_map.end ();
> +  unsigned prev_access = field_already_in_map ? field_map[op1] : Empty;
> +
> +  prev_access |= _access;
> +  field_map[op1] = prev_access;
> +  add_all_fields_in_struct (op0_t);
> +  record_field_map[op0_t] = field_map;
> +
> +  if (_stack.size () < 4)
> +    return;
> +
> +  tree this_expr = _stack.top ();
> +  _stack.pop ();
> +  tree twice = _stack.top ();
> +  _stack.pop ();
> +  tree prev_expr = _stack.top ();
> +  _stack.push (twice);
> +  _stack.push (this_expr);
> +  if (TREE_CODE (prev_expr) != ADDR_EXPR)
> +    return;
> +
> +  log ("we are taking address of a component?\n");
> +  tree t = op0_t;
> +  if (TREE_CODE (t) != RECORD_TYPE)
> +    return;
> +
> +  /* If we are taking the address of a component, we need to mark the
> whole
> +   * RECORD_TYPE as escaping due to pointer arithmetic.
> +   * TODO: Maybe add a flag to enable and disable this for debugging and
> +   * testing.
> +   */
> +  for (tree field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field))
> +  {
> +      log ("ever inside?\n");
> +      const bool field_already_in_map
> +       = field_map.find (field) != field_map.end ();
> +      unsigned prev_access = field_already_in_map ? field_map[field] :
> Empty;
> +
> +      prev_access |= Read;
> +      field_map[field] = prev_access;
> +      add_all_fields_in_struct (t);
> +      record_field_map[t] = field_map;
> +  }
> +}
> +
> +/* Print results.  */
> +void
> +expr_accessor::print_accesses ()
> +{
> +  for (std::map<tree, field_access_map_t>::const_iterator i
> +       = record_field_map.begin (),
> +       e = record_field_map.end ();
> +       i != e; ++i)
> +    {
> +      tree record = i->first;
> +      field_access_map_t field_map = i->second;
> +      for (std::map<tree, unsigned>::const_iterator j
> +          = field_map.begin (),
> +          f = field_map.end ();
> +          j != f; ++j)
> +       {
> +         tree field = j->first;
> +         const std::string name_r
> +           = type_stringifier::get_type_identifier (record);
> +         const std::string name_f
> +           = type_stringifier::get_field_identifier (field);
> +         unsigned access = j->second;
> +         log ("%s.%s = 0x%04x\n", name_r.c_str (), name_f.c_str (),
> access);
> +       }
> +    }
> +}
> +
> +/* RECORD_TYPE -> (FIELD_DECL -> bitflag)
> + * bitflag specifies if field is read, written or neither.
> + */
> +record_field_map_t
> +gimple_accessor::get_map ()
> +{
> +  return _expr_accessor.get_map ();
> +}
> +
> +void
> +gimple_accessor::print_accesses ()
> +{
> +  _expr_accessor.print_accesses ();
> +}
> +
> +/* Mark RHS as Read and LHS as Write.  */
> +void
> +gimple_accessor::_walk_pre_gassign (gassign *s)
> +{
> +  // There seems to be quite a bit of code duplication here...
> +  const enum gimple_rhs_class code = gimple_assign_rhs_class (s);
> +  switch (code)
> +    {
> +    case GIMPLE_TERNARY_RHS:
> +      {
> +       tree rhs3 = gimple_assign_rhs3 (s);
> +       gcc_assert (rhs3);
> +       _expr_accessor.update (rhs3, Read);
> +      }
> +    /* fall-through */
> +    case GIMPLE_BINARY_RHS:
> +      {
> +       tree rhs2 = gimple_assign_rhs2 (s);
> +       gcc_assert (rhs2);
> +       _expr_accessor.update (rhs2, Read);
> +      }
> +    /* fall-through */
> +    case GIMPLE_UNARY_RHS:
> +    case GIMPLE_SINGLE_RHS:
> +      {
> +       tree rhs1 = gimple_assign_rhs1 (s);
> +       _expr_accessor.update (rhs1, Read);
> +       tree lhs = gimple_assign_lhs (s);
> +       if (!lhs)
> +         break;
> +       _expr_accessor.update (lhs, Write);
> +       break;
> +      }
> +    default:
> +      gcc_unreachable ();
> +      break;
> +    }
> +}
> +
> +/* Mark RHS as Read and LHS as Written.  */
> +void
> +gimple_accessor::_walk_pre_gcall (gcall *s)
> +{
> +  unsigned n = gimple_call_num_args (s);
> +  for (unsigned i = 0; i < n; i++)
> +    {
> +      tree a = gimple_call_arg (s, i);
> +      gcc_assert (a);
> +      _expr_accessor.update (a, Read);
> +    }
> +
> +  tree lhs = gimple_call_lhs (s);
> +  if (!lhs)
> +    return;
> +  _expr_accessor.update (lhs, Write);
> +}
> +
> +/* Mark as Read.  */
> +void
> +gimple_accessor::_walk_pre_greturn (greturn *s)
> +{
> +  tree val = gimple_return_retval (s);
> +  if (!val)
> +    return;
> +  _expr_accessor.update (val, Read);
> +}
> +
> +/* Mark as Read.  */
> +void
> +gimple_accessor::_walk_pre_gcond (gcond *s)
> +{
> +  tree lhs = gimple_cond_lhs (s);
> +  tree rhs = gimple_cond_rhs (s);
> +  gcc_assert (lhs && rhs);
> +  _expr_accessor.update (lhs, Read);
> +  _expr_accessor.update (rhs, Read);
> +}
> +
> +/* Print Reasons why a type might be escaping.  */
> +void
> +Reason::print () const
> +{
> +  log ("e=%d g=%d p=%d r=%d c=%d v=%d u=%d i=%d\n", this->is_escaping (),
> +       this->global_is_visible, this->parameter_is_visible,
> +       this->return_is_visible, this->type_is_casted,
> this->type_is_volatile,
> +       this->type_is_in_union, this->is_indirect);
> +}
> +
> +/* Or an escaping Reason.  */
> +Reason
> +Reason::operator| (const Reason &other)
> +{
> +  Reason retval;
> +  retval.global_is_visible = this->global_is_visible |
> other.global_is_visible;
> +  retval.parameter_is_visible
> +    = this->parameter_is_visible | other.parameter_is_visible;
> +  retval.return_is_visible = this->return_is_visible |
> other.return_is_visible;
> +  retval.type_is_casted = this->type_is_casted | other.type_is_casted;
> +  retval.type_is_volatile = this->type_is_volatile |
> other.type_is_volatile;
> +  retval.type_is_in_union = this->type_is_in_union |
> other.type_is_in_union;
> +  retval.is_indirect = this->is_indirect | other.is_indirect;
> +  return retval;
> +}
> +
> +/* Or an escaping Reason.  */
> +Reason &
> +Reason::operator|= (const Reason &other)
> +{
> +  this->global_is_visible |= other.global_is_visible;
> +  this->parameter_is_visible |= other.parameter_is_visible;
> +  this->return_is_visible |= other.return_is_visible;
> +  this->type_is_casted |= other.type_is_casted;
> +  this->type_is_volatile |= other.type_is_volatile;
> +  this->type_is_in_union |= other.type_is_in_union;
> +  this->is_indirect |= other.is_indirect;
> +  return *this;
> +}
> +
> +/* Insert TYPE into a partition depending on IN_POINTS_TO_RECORD.  */
> +void
> +type_partitions_s::insert (tree type, bool in_points_to_record)
> +{
> +  gcc_assert (type);
> +  this->universe.insert (type);
> +  in_points_to_record ? this->points_to_record.insert (type)
> +                     : this->complement.insert (type);
> +  const bool in_points_to_set = this->in_points_to_record (type);
> +  const bool in_complement = this->in_complement (type);
> +  const bool _xor = in_points_to_set != in_complement;
> +  // sanity check...
> +  gcc_assert (_xor);
> +}
> +
> +/* Find out whether TYPE is already in universe.  */
> +bool
> +type_partitions_s::in_universe (tree type) const
> +{
> +  gcc_assert (type);
> +  const bool seen_before = this->universe.find (type) !=
> this->universe.end ();
> +  return seen_before;
> +}
> +
> +/* Find out whether TYPE is in points_to_record partition.  */
> +bool
> +type_partitions_s::in_points_to_record (tree type) const
> +{
> +  gcc_assert (type);
> +  const bool seen_before
> +    = this->points_to_record.find (type) != this->points_to_record.end ();
> +  return seen_before;
> +}
> +
> +/* Find out whether TYPE is not in points to record partition.  */
> +bool
> +type_partitions_s::in_complement (tree type) const
> +{
> +  gcc_assert (type);
> +  const bool seen_before
> +    = this->complement.find (type) != this->complement.end ();
> +  return seen_before;
> +}
> +
> +/* Stringify a type.  */
> +std::string
> +type_stringifier::stringify (tree t)
> +{
> +  if (!dump_file)
> +    return std::string ("");
> +  _stringification.clear ();
> +  gcc_assert (t);
> +  walk (t);
> +  return _stringification;
> +}
> +
> +void
> +type_stringifier::_walk_VOID_TYPE_pre (tree t)
> +{
> +  _stringify_simple (t);
> +}
> +
> +void
> +type_stringifier::_walk_INTEGER_TYPE_pre (tree t)
> +{
> +  _stringify_simple (t);
> +}
> +
> +void
> +type_stringifier::_walk_REAL_TYPE_pre (tree t)
> +{
> +  _stringify_simple (t);
> +}
> +
> +void
> +type_stringifier::_walk_FIXED_POINT_TYPE_pre (tree t)
> +{
> +  _stringify_simple (t);
> +}
> +
> +void
> +type_stringifier::_walk_COMPLEX_TYPE_pre (tree t)
> +{
> +  _stringify_simple (t);
> +}
> +
> +void
> +type_stringifier::_walk_OFFSET_TYPE_pre (tree t)
> +{
> +  _stringify_simple (t);
> +}
> +
> +void
> +type_stringifier::_walk_BOOLEAN_TYPE_pre (tree t)
> +{
> +  _stringify_simple (t);
> +}
> +
> +void
> +type_stringifier::_stringify_simple (tree t)
> +{
> +  gcc_assert (t);
> +  const enum tree_code code = TREE_CODE (t);
> +  this->_stringification += std::string (get_tree_code_name (code));
> +}
> +
> +void
> +type_stringifier::_walk_POINTER_TYPE_post (__attribute__ ((unused)) tree
> t)
> +{
> +  this->_stringification += std::string ("*");
> +}
> +
> +void
> +type_stringifier::_walk_ARRAY_TYPE_post (__attribute__ ((unused)) tree t)
> +{
> +  this->_stringification += std::string ("[]");
> +}
> +
> +void
> +type_stringifier::_walk_REFERENCE_TYPE_post (__attribute__ ((unused))
> +                                           tree t)
> +{
> +  this->_stringification += std::string ("&");
> +}
> +
> +void
> +type_stringifier::_walk_UNION_TYPE_pre (tree t)
> +{
> +  this->_stringification += std::string (" union ");
> +  _stringify_aggregate_pre (t);
> +}
> +
> +void
> +type_stringifier::_walk_UNION_TYPE_post (tree t)
> +{
> +  _stringify_aggregate_post (t);
> +}
> +
> +void
> +type_stringifier::_walk_RECORD_TYPE_pre (tree t)
> +{
> +  this->_stringification += std::string (" record ");
> +  _stringify_aggregate_pre (t);
> +}
> +
> +void
> +type_stringifier::_walk_RECORD_TYPE_post (tree t)
> +{
> +  _stringify_aggregate_post (t);
> +}
> +
> +void
> +type_stringifier::_stringify_aggregate_pre (tree t)
> +{
> +  this->_stringification
> +    += type_stringifier::get_type_identifier (t) + std::string (" {");
> +}
> +
> +void
> +type_stringifier::_stringify_aggregate_post (__attribute__ ((unused))
> +                                           tree t)
> +{
> +  this->_stringification += std::string ("}");
> +}
> +
> +void
> +type_stringifier::_walk_field_post (tree t)
> +{
> +  this->_stringification += std::string (" ")
> +                           + type_stringifier::get_field_identifier (t)
> +                           + std::string (";");
> +}
> +
> +void
> +type_stringifier::_walk_METHOD_TYPE_pre (tree t)
> +{
> +  _stringify_fm_pre (t);
> +}
> +
> +void
> +type_stringifier::_walk_METHOD_TYPE_post (tree t)
> +{
> +  _stringify_fm_post (t);
> +}
> +
> +void
> +type_stringifier::_walk_FUNCTION_TYPE_pre (tree t)
> +{
> +  _stringify_fm_pre (t);
> +}
> +
> +void
> +type_stringifier::_walk_FUNCTION_TYPE_post (tree t)
> +{
> +  _stringify_fm_post (t);
> +}
> +
> +void
> +type_stringifier::_stringify_fm_pre (__attribute__ ((unused)) tree t)
> +{
> +  this->_stringification += std::string ("function { ");
> +}
> +
> +void
> +type_stringifier::_stringify_fm_post (__attribute__ ((unused)) tree t)
> +{
> +  this->_stringification += std::string ("}");
> +}
> +
> +void
> +type_stringifier::_walk_return_pre (__attribute__ ((unused)) tree t)
> +{
> +  this->_stringification += std::string ("(");
> +}
> +
> +void
> +type_stringifier::_walk_return_post (__attribute__ ((unused)) tree t)
> +{
> +  this->_stringification += std::string (")");
> +}
> +
> +void
> +type_stringifier::_walk_args_pre (__attribute__ ((unused)) tree t)
> +{
> +  this->_stringification += std::string ("(");
> +}
> +
> +void
> +type_stringifier::_walk_args_post (__attribute__ ((unused)) tree t)
> +{
> +  this->_stringification += std::string (")");
> +}
> +
> +void
> +type_stringifier::_walk_arg_post (__attribute__ ((unused)) tree t)
> +{
> +  this->_stringification += std::string (", ");
> +}
> +
> +std::string
> +type_stringifier::get_type_identifier (tree t)
> +{
> +  tree name = TYPE_NAME (t);
> +  const bool no_name = NULL_TREE == name;
> +  if (no_name)
> +    return std::string ("");
> +
> +  const enum tree_code name_code = TREE_CODE (name);
> +  const bool is_name_type_decl = TYPE_DECL == name_code;
> +  name = is_name_type_decl ? DECL_NAME (name) : name;
> +  const char *identifier_ptr = IDENTIFIER_POINTER (name);
> +  gcc_assert (identifier_ptr);
> +  return std::string (identifier_ptr);
> +}
> +
> +std::string
> +type_stringifier::get_field_identifier (tree t)
> +{
> +  assert_is_type (t, FIELD_DECL);
> +  tree decl_name = DECL_NAME (t);
> +  if (!decl_name)
> +    return std::string ("");
> +
> +  const char *identifier = IDENTIFIER_POINTER (decl_name);
> +  return std::string (identifier);
> +}
> +
> +/* Return true if L and R have equal structural equalities.  */
> +bool
> +type_structural_equality::equal (tree l, tree r)
> +{
> +  return _equal (l, r);
> +}
> +
> +bool
> +type_structural_equality::_equal (tree l, tree r)
> +{
> +  bool valid_inputs = l && r;
> +  if (!valid_inputs)
> +    return l == r;
> +
> +  bool equal_codes = _equal_code (l, r);
> +  if (!equal_codes)
> +    return equal_codes;
> +
> +  bool recurse_l = set_l.find (l) != set_l.end ();
> +  bool recurse_r = set_r.find (r) != set_r.end ();
> +  // Verify that this the case every time.
> +  bool recurse = recurse_l || recurse_r;
> +  if (recurse)
> +    return recurse;
> +
> +  set_l.insert (l);
> +  set_r.insert (r);
> +  const enum tree_code code = TREE_CODE (l);
> +  bool equal_children = false;
> +  switch (code)
> +    {
> +#define TSE_CASE(code)                         \
> +  case code:                                   \
> +    equal_children = _walk_##code (l, r);      \
> +    break
> +
> +      TSE_CASE (VOID_TYPE);
> +      TSE_CASE (INTEGER_TYPE);
> +      TSE_CASE (REAL_TYPE);
> +      TSE_CASE (FIXED_POINT_TYPE);
> +      TSE_CASE (COMPLEX_TYPE);
> +      TSE_CASE (ENUMERAL_TYPE);
> +      TSE_CASE (BOOLEAN_TYPE);
> +      TSE_CASE (OFFSET_TYPE);
> +      TSE_CASE (RECORD_TYPE);
> +      TSE_CASE (POINTER_TYPE);
> +      TSE_CASE (REFERENCE_TYPE);
> +      TSE_CASE (ARRAY_TYPE);
> +      TSE_CASE (UNION_TYPE);
> +      TSE_CASE (FUNCTION_TYPE);
> +      TSE_CASE (METHOD_TYPE);
> +    default:
> +      gcc_unreachable ();
> +      break;
> +    }
> +
> +  set_l.erase (l);
> +  set_r.erase (r);
> +  return equal_children;
> +}
> +
> +bool
> +type_structural_equality::_equal_code (tree l, tree r)
> +{
> +  const enum tree_code code_l = TREE_CODE (l);
> +  const enum tree_code code_r = TREE_CODE (r);
> +  const bool equal = code_l == code_r;
> +  return equal;
> +}
> +
> +#define TSE_FUNC_DEF_SIMPLE(code)                                        \
> +  bool type_structural_equality::_walk_##code (tree l, tree r)  \
> +  {                                                                      \
> +    return _equal_code (l, r);                                           \
> +  }
> +
> +TSE_FUNC_DEF_SIMPLE (VOID_TYPE)
> +TSE_FUNC_DEF_SIMPLE (INTEGER_TYPE)
> +TSE_FUNC_DEF_SIMPLE (REAL_TYPE)
> +TSE_FUNC_DEF_SIMPLE (FIXED_POINT_TYPE)
> +TSE_FUNC_DEF_SIMPLE (ENUMERAL_TYPE)
> +TSE_FUNC_DEF_SIMPLE (BOOLEAN_TYPE)
> +TSE_FUNC_DEF_SIMPLE (OFFSET_TYPE)
> +TSE_FUNC_DEF_SIMPLE (COMPLEX_TYPE)
> +
> +bool
> +type_structural_equality::_equal_wrapper (tree l, tree r)
> +{
> +  tree inner_l = TREE_TYPE (l);
> +  tree inner_r = TREE_TYPE (r);
> +  return _equal (inner_l, inner_r);
> +}
> +
> +#define TSE_FUNC_DEF_WRAPPER(code)                                      \
> +  bool type_structural_equality::_walk_##code (tree l, tree r) \
> +  {                                                                     \
> +    return _equal_wrapper (l, r);                                       \
> +  }
> +
> +TSE_FUNC_DEF_WRAPPER (REFERENCE_TYPE)
> +TSE_FUNC_DEF_WRAPPER (ARRAY_TYPE)
> +TSE_FUNC_DEF_WRAPPER (POINTER_TYPE)
> +
> +#define TSE_FUNC_DEF_CONTAINER(code)                                    \
> +  bool type_structural_equality::_walk_##code (tree l, tree r) \
> +  {                                                                     \
> +    tree field_l = TYPE_FIELDS (l);                             \
> +    tree field_r = TYPE_FIELDS (r);                             \
> +    bool efield_l = field_l;                                            \
> +    bool efield_r = field_r;                                            \
> +    bool still_equal = efield_l == efield_r;                            \
> +    if (!still_equal)                                                   \
> +      return still_equal;                                               \
> +                                                                        \
> +    while (field_l && field_r && still_equal)                           \
> +      {
>        \
> +       tree tfield_l = TREE_TYPE (field_l);                     \
> +       tree tfield_r = TREE_TYPE (field_r);                     \
> +       still_equal &= _equal (tfield_l, tfield_r);                      \
> +       field_l = DECL_CHAIN (field_l);                                  \
> +       field_r = DECL_CHAIN (field_r);                                  \
> +       efield_l = field_l;                                              \
> +       efield_r = field_r;                                              \
> +       still_equal &= efield_l == efield_r;                             \
> +      }
>        \
> +    return still_equal;
>        \
> +  }
> +
> +TSE_FUNC_DEF_CONTAINER (RECORD_TYPE)
> +TSE_FUNC_DEF_CONTAINER (UNION_TYPE)
> +
> +#define TSE_FUNC_DEF_FUNC(code)
>        \
> +  bool type_structural_equality::_walk_##code (tree l, tree r) \
> +  {                                                                     \
> +    tree tret_l = TREE_TYPE (l);                                        \
> +    tree tret_r = TREE_TYPE (r);                                        \
> +    bool still_equal = _equal (tret_l, tret_r);
>        \
> +    if (!still_equal)                                                   \
> +      return still_equal;                                               \
> +                                                                        \
> +    tree arg_l = TYPE_ARG_TYPES (l);                            \
> +    tree arg_r = TYPE_ARG_TYPES (r);                            \
> +    bool earg_l = arg_l;                                                \
> +    bool earg_r = arg_r;                                                \
> +    still_equal &= earg_l == earg_r;                                    \
> +    while (arg_l && arg_r && still_equal)                               \
> +      {
>        \
> +       tree targ_l = TREE_VALUE (arg_l);                                \
> +       tree targ_r = TREE_VALUE (arg_r);                                \
> +       still_equal &= _equal (targ_l, targ_r);                          \
> +       arg_l = TREE_CHAIN (arg_l);                                      \
> +       arg_r = TREE_CHAIN (arg_r);                                      \
> +       earg_l = arg_l;                                                  \
> +       earg_r = arg_r;                                                  \
> +       still_equal &= earg_l == earg_r;                                 \
> +      }
>        \
> +    return still_equal;
>        \
> +  }
> +
> +TSE_FUNC_DEF_FUNC (FUNCTION_TYPE)
> +TSE_FUNC_DEF_FUNC (METHOD_TYPE)
> +
> +/* Used for comparing incomplete types.  */
> +bool
> +type_incomplete_equality::_equal (tree l, tree r)
> +{
> +  bool valid_inputs = l && r;
> +  if (!valid_inputs)
> +    return l == r;
> +
> +  // If any of these are incomplete, then we can only compare using
> +  // identifiers...
> +  const bool complete_l = is_complete (l);
> +  const bool complete_r = is_complete (r);
> +  bool can_compare_structurally = complete_l && complete_r;
> +  if (can_compare_structurally)
> +    return type_structural_equality::_equal (l, r);
> +
> +  // Before comparing with identifiers
> +  // make last attempt to compare using main variants.
> +  tree m_l = TYPE_MAIN_VARIANT (l);
> +  tree m_r = TYPE_MAIN_VARIANT (r);
> +  gcc_assert (m_l && m_r);
> +  can_compare_structurally = m_l == m_r;
> +  if (can_compare_structurally)
> +    return true;
> +
> +  const std::string n_l = type_stringifier::get_type_identifier (m_l);
> +  const std::string n_r = type_stringifier::get_type_identifier (m_r);
> +  return n_l.compare (n_r) == 0;
> +}
> +
> +/* Remove non-escaping types and place in escaping types if
> + * there is a tree in escaping partition which is equivalent to
> + * another tree in non-escaping partition.
> + * Perform this until a fixed point is reached.
> + */
> +static void
> +fix_escaping_types_in_set (tpartitions_t &types)
> +{
> +  bool fixed_point_reached = false;
> +  type_incomplete_equality structuralEquality;
> +  do
> +    {
> +      std::vector<tree> fixes;
> +      fixed_point_reached = true;
> +      for (std::set<tree>::const_iterator i = types.escaping.begin (),
> +                                               e = types.escaping.end ();
> +          i != e; ++i)
> +       {
> +         for (std::set<tree>::const_iterator j
> +              = types.non_escaping.begin (),
> +              f = types.non_escaping.end ();
> +              j != f; ++j)
> +           {
> +             tree type_esc = *i;
> +             gcc_assert (type_esc);
> +             tree type_non = *j;
> +             gcc_assert (type_non);
> +             // There can be cases where incomplete types are marked as
> +             // non-escaping and complete types counter parts are marked
> as
> +             // escaping.
> +             const bool equal = structuralEquality.equal (type_esc,
> type_non);
> +             if (!equal)
> +               continue;
> +
> +             fixed_point_reached = false;
> +             // Add incomplete to escaping
> +             // delete incomplete from non_escaping
> +             // We shouldn't do that inside our iteration loop.
> +             fixes.push_back (type_non);
> +           }
> +       }
> +
> +      for (std::vector<tree>::const_iterator i = fixes.begin (),
> +                                                  e = fixes.end ();
> +          i != e; ++i)
> +       {
> +         tree escaping_type = *i;
> +         types.escaping.insert (escaping_type);
> +         types.non_escaping.erase (escaping_type);
> +       }
> +    }
> +  while (!fixed_point_reached);
> +}
> +
> +simple_ipa_opt_pass *
> +make_pass_ipa_type_escape_analysis (gcc::context *ctx)
> +{
> +  return new pass_ipa_type_escape_analysis (ctx);
> +}
> diff --git a/gcc/ipa-type-escape-analysis.h
> b/gcc/ipa-type-escape-analysis.h
> new file mode 100644
> index 00000000000..7641529bb39
> --- /dev/null
> +++ b/gcc/ipa-type-escape-analysis.h
> @@ -0,0 +1,1152 @@
> +/* IPA Type Escape Analysis and Dead Field Elimination
> +   Copyright (C) 2019-2020 Free Software Foundation, Inc.
> +
> +  Contributed by Erick Ochoa <erick.oc...@theobroma-systems.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/>.  */
> +
> +#ifndef GCC_IPA_TYPE_ESCAPE_ANALYSIS_H
> +#define GCC_IPA_TYPE_ESCAPE_ANALYSIS_H
> +
> +/* Logging function, useful for debugging.  */
> +void log (const char *const fmt, ...) __attribute__((format(printf, 1,
> 0)));
> +inline void
> +log (const char *const fmt, ...) +{
> +  if (!dump_file)
> +    return;
> +
> +  va_list args;
> +  va_start (args, fmt);
> +  vfprintf (dump_file, fmt, args);
> +  fflush (dump_file);
> +  va_end (args);
> +}
> +
> +/* Asserts expected gimple code is observed gimple code.  */
> +inline void
> +is_gimple_code (const gimple *stmt, const enum gimple_code ex_code)
> +{
> +  gcc_assert (stmt);
> +  const enum gimple_code ob_code = gimple_code (stmt);
> +  const bool succeeds = ex_code == ob_code;
> +  gcc_assert (succeeds);
> +}
> +
> +/* Determine if type A is complete.  */
> +inline bool
> +is_complete (tree a)
> +{
> +  gcc_assert (a);
> +  tree type_size = TYPE_SIZE (a);
> +  const bool _is_complete = NULL_TREE != type_size;
> +  return _is_complete;
> +}
> +
> +/* Asserts type A is complete.  */
> +inline void
> +assert_is_complete (tree a)
> +{
> +  const bool _is_complete = is_complete (a);
> +  gcc_assert (_is_complete);
> +}
> +
> +/* Determine if type A is incomplete.  */
> +inline bool
> +is_incomplete (tree a)
> +{
> +  return !is_complete (a);
> +}
> +
> +/* Assert type A has is EXPECTED_CODE.  */
> +inline void
> +assert_is_type (tree a, const enum tree_code expected_code)
> +{
> +  gcc_assert (a);
> +  const enum tree_code observed_code = TREE_CODE (a);
> +  const bool eq_codes = observed_code == expected_code;
> +  gcc_assert (eq_codes);
> +}
> +
> +/* Assert STMT is of EX_CLASS enum gimple_rhs_class.  */
> +inline void
> +assert_is_gimple_rhs_class (const gimple *stmt,
> +                           const enum gimple_rhs_class ex_class)
> +{
> +  gcc_assert (stmt);
> +  is_gimple_code (stmt, GIMPLE_ASSIGN);
> +  const enum gimple_rhs_class ob_class = gimple_assign_rhs_class (stmt);
> +  const bool succeeds = ex_class == ob_class;
> +  gcc_assert (succeeds);
> +}
> +
> +// TODO: Rename?
> +// TSET_T stands for type set.
> +typedef std::set<tree> tset_t;
> +
> +/* Base class used for visiting tree nodes starting with root T.
> + * It can handle recursive cases in the tree graph by holding
> + * a set of previously seen nodes and checking before walking
> + * a node.
> +
> + * Unlike walk_tree, TypeWalker allows users to create post-order
> + * callbacks for each type of tree.
> + */
> +class type_walker
> +{
> +public:
> +  type_walker ()
> +  {};
> +
> +  /* Main interface to type walker.
> +   * Walk type T.
> +   */
> +  void walk (tree t);
> +
> +protected:
> +
> +  /* Typeset holds previously visited nodes.  */
> +  tset_t tset;
> +
> +  /* Inner walking method, used to recurse.  */
> +  void _walk (tree t);
> +
> +  /* Common walking method for REFERENCE_TYPE, ARRAY_TYPE, and
> POINTER_TYPE.  */
> +  void _walk_wrapper (tree t);
> +
> +  /* Common walking method for RECORD_TYPE and UNION_TYPE.  */
> +  void _walk_record_or_union (tree t);
> +
> +  /* Common walking method for FUNCTION_TYPE and METHOD_TYPE.  */
> +  virtual void _walk_function_or_method (tree t);
> +
> +  /* If the type is memoized and we don't need to walk further down.  */
> +  virtual bool is_memoized (__attribute__ ((unused)) tree t)
> +  {
> +    return false;
> +  }
> +
> +  /* Function definitions for different TYPEs callbacks.
> +     _pre is the pre-order callback.
> +     _post is the post-order callback.
> +     If you want to find a specific type in a specific order,
> +     (e.g. RECORD_TYPE and preorder)
> +     you can create a derived class and implement the function
> +     void _walk_RECORD_TYPE_pre (tree).
> +
> +     walk_##code is the function that calls
> +     the preorder callback
> +     walking subtrees
> +     and the postorder callback.
> +     This is for each specific tree code.
> +
> +     _walk_##code is the function that walks subtrees for that
> +     specific tree code.
> +   */
> +#define TypeWalkerFuncDecl(code) \
> +  virtual void _walk_##code##_pre (__attribute__((unused)) tree t) \
> +  {}; \
> +  virtual void _walk_##code (tree t); \
> +  virtual void _walk_##code##_post (__attribute__((unused)) tree t) \
> +  {}; \
> +  virtual void walk_##code (tree t)
> +
> +// NOTE the lack of semicolon here.
> +// This is so that when using the macro we can use a semi-colon
> +// and formatting doesn't break.
> +
> +  /* These are the types for which we can define a pre-order
> +   * and post-order functions.  */
> +  TypeWalkerFuncDecl (VOID_TYPE);
> +  TypeWalkerFuncDecl (INTEGER_TYPE);
> +  TypeWalkerFuncDecl (REAL_TYPE);
> +  TypeWalkerFuncDecl (FIXED_POINT_TYPE);
> +  TypeWalkerFuncDecl (COMPLEX_TYPE);
> +  TypeWalkerFuncDecl (ENUMERAL_TYPE);
> +  TypeWalkerFuncDecl (BOOLEAN_TYPE);
> +  TypeWalkerFuncDecl (OFFSET_TYPE);
> +  TypeWalkerFuncDecl (RECORD_TYPE);
> +  TypeWalkerFuncDecl (POINTER_TYPE);
> +  TypeWalkerFuncDecl (REFERENCE_TYPE);
> +  TypeWalkerFuncDecl (ARRAY_TYPE);
> +  TypeWalkerFuncDecl (UNION_TYPE);
> +  TypeWalkerFuncDecl (FUNCTION_TYPE);
> +  TypeWalkerFuncDecl (METHOD_TYPE);
> +
> +  /* These are not types, but are still trees that
> +   * can be reached from a tree type.  Therefore, these
> +   * trees also need to be walked.
> +   */
> +  TypeWalkerFuncDecl (field);
> +  TypeWalkerFuncDecl (return);
> +  TypeWalkerFuncDecl (args);
> +  TypeWalkerFuncDecl (arg);
> +};
> +
> +/* Base class for the implementation of the visitor pattern for
> + * trees which are "expressions".  This might be a misnomer.
> + * What it means is that it walks whatever can be the result of
> + * the trees returned by gimple_assign_rhs{1,2,3}, gimple_return,
> + * gimple_call...
> + * TODO: The expressions visited here might not be the whole set
> + * but it is what was found while experimentally running some C
> + * programs.
> + */
> +class expr_walker
> +{
> +public:
> +  expr_walker ()
> +  {};
> +
> +  /* Walk tree E.  */
> +  void walk (tree e);
> +
> +private:
> +
> +  /* Virtual function to be implemented.  Callback for all E in
> preorder.  */
> +  virtual void _walk_pre (__attribute__ ((unused)) tree e)
> +  {};
> +
> +  /* Inner method that will recurse for walking subtrees in E.  */
> +  void _walk (tree e);
> +
> +  /* Virtual function to be implemented.  Callback for all E in
> postorder.  */
> +  virtual void _walk_post (__attribute__ ((unused)) tree e)
> +  {};
> +
> +  /* Walking subtrees generically.  Either it is a leaf node,
> +     (i.e., it does not have subtrees), or it has some operands.
> +     TODO: This can probably be changed to be more general
> +     by finding out how many operands an expression has.
> +
> +     tree_code C is used to assert that we are visiting an operand
> +     of a specific tree code.
> +   */
> +  inline void _walk_leaf (tree e, const enum tree_code c);
> +  inline void _walk_op_n (tree e, unsigned n);
> +  inline void _walk_op_0 (tree e, const enum tree_code c);
> +  inline void _walk_op_1 (tree e, const enum tree_code c);
> +
> +  /* Virtual function declarations for the pre-order and post-order
> callbacks.
> +   * _walk_##code##_pre is the preorder callback
> +   * walk_##code will call the preorder, subtree walker, and postorder
> +   * _walk_##code is the subtree walker
> +   * _walk_##code##_post is the post-order callback.
> +   */
> +#define ExprWalkerFuncDecl(code)
> \
> +  virtual void _walk_##code##_pre (__attribute__ ((unused)) tree e)  \
> +  {};
>  \
> +  void walk_##code (tree e);                                      \
> +  void _walk_##code (tree e);                                     \
> +  virtual void _walk_##code##_post (__attribute__ ((unused)) tree e) \
> +  {}
> +
> +  // Some of these are not "EXPR" codes, but they are reachable
> +  // from gimple_assign_rhs{1,2,3} and others.
> +  ExprWalkerFuncDecl (CONSTRUCTOR);
> +  ExprWalkerFuncDecl (INTEGER_CST);
> +  ExprWalkerFuncDecl (REAL_CST);
> +  ExprWalkerFuncDecl (STRING_CST);
> +  ExprWalkerFuncDecl (BIT_FIELD_REF);
> +  ExprWalkerFuncDecl (ARRAY_REF);
> +  ExprWalkerFuncDecl (MEM_REF);
> +  ExprWalkerFuncDecl (COMPONENT_REF);
> +  ExprWalkerFuncDecl (SSA_NAME);
> +  ExprWalkerFuncDecl (ADDR_EXPR);
> +  ExprWalkerFuncDecl (VIEW_CONVERT_EXPR);
> +  ExprWalkerFuncDecl (IMAGPART_EXPR);
> +  ExprWalkerFuncDecl (FIELD_DECL);
> +  ExprWalkerFuncDecl (VAR_DECL);
> +  ExprWalkerFuncDecl (RESULT_DECL);
> +  ExprWalkerFuncDecl (PARM_DECL);
> +  ExprWalkerFuncDecl (FUNCTION_DECL);
> +  ExprWalkerFuncDecl (LE_EXPR);
> +  ExprWalkerFuncDecl (LT_EXPR);
> +  ExprWalkerFuncDecl (EQ_EXPR);
> +  ExprWalkerFuncDecl (GT_EXPR);
> +  ExprWalkerFuncDecl (GE_EXPR);
> +  ExprWalkerFuncDecl (NE_EXPR);
> +};
> +
> +/* Base class for applying the visitor pattern to gimple_stmts.
> + * This class visits everything it cans during LTO.
> + * That includes global variables, and all function declarations that
> + * are in the current partition.
> + */
> +class gimple_walker
> +{
> +public:
> +  gimple_walker () : _deleted (false)
> +  {};
> +
> +  /* Walk the entire code, therefore no input is needed.  */
> +  void walk ();
> +
> +protected:
> +  /* _DELETED is set by overwritten functions that
> +   * delete a specific gimple stmt.  This tells the
> +   * gimple walker to remove the gimple stmt.
> +   */
> +  bool _deleted;
> +
> +  /* Walk global variables.  */
> +  void _walk_globals ();
> +
> +  /* Walk individual global variable V.  */
> +  virtual void _walk_global (varpool_node *v);
> +
> +  /* Will walk declarations, locals, ssa names, and basic blocks.  */
> +  void _walk_cnode (cgraph_node *cnode);
> +
> +  /* This will walk the CNODE->decl.  */
> +  void _walk_decl (cgraph_node *cnode);
> +
> +  /* Walk ssa_names in CNODE.  */
> +  void _walk_ssa_names (cgraph_node *cnode);
> +
> +  /* Walk local variables in CNODE.  */
> +  void _walk_locals (cgraph_node *cnode);
> +
> +  /* Iterate over all basic blocks in CNODE.  */
> +  void _walk_bb (cgraph_node *cnode);
> +
> +  /* Iterate over all gimple_stmt in BB.  */
> +  void _walk (basic_block bb);
> +
> +  /* Function declarations for virtual functions.
> +   * These include the pre-order callbacks, walk subtrees,
> +   * and post-order callbacks.
> +   */
> +  virtual void _walk_pre_tree (__attribute__((unused)) tree t)
> +  {};
> +  void walk_tree2 (tree t);
> +  void _walk_tree (tree t);
> +  virtual void _walk_post_tree (__attribute__((unused)) tree t)
> +  {};
> +
> +  virtual void _walk_pre_gimple (__attribute__((unused)) gimple* g)
> +  {};
> +  void walk_gimple (gimple* g);
> +  void _walk_gimple (gimple* g);
> +  virtual void _walk_post_gimple (__attribute__((unused)) gimple* g)
> +  {};
> +
> +  virtual void _walk_pre_gassign (__attribute__((unused)) gassign* g)
> +  {};
> +  void walk_gassign (gassign* g);
> +  void _walk_gassign (gassign* g);
> +  virtual void _walk_post_gassign (__attribute__((unused)) gassign* g)
> +  {};
> +
> +  virtual void _walk_pre_greturn (__attribute__((unused)) greturn* g)
> +  {};
> +  void walk_greturn (greturn* g);
> +  void _walk_greturn (greturn* g);
> +  virtual void _walk_post_greturn (__attribute__((unused)) greturn* g)
> +  {};
> +
> +  virtual void _walk_pre_gcond (__attribute__((unused)) gcond* g)
> +  {};
> +  void walk_gcond (gcond* g);
> +  void _walk_gcond (gcond* g);
> +  virtual void _walk_post_gcond (__attribute__((unused)) gcond* g)
> +  {};
> +
> +  virtual void _walk_pre_glabel (__attribute__((unused)) glabel* g)
> +  {};
> +  void walk_glabel (glabel* g);
> +  void _walk_glabel (glabel* g);
> +  virtual void _walk_post_glabel (__attribute__((unused)) glabel* g)
> +  {};
> +
> +  virtual void _walk_pre_gcall (__attribute__((unused)) gcall *g)
> +  {};
> +  void walk_gcall (gcall *g);
> +  void _walk_gcall (gcall *g);
> +  virtual void _walk_post_gcall (__attribute__((unused)) gcall *g)
> +  {};
> +
> +  virtual void _walk_pre_gswitch (__attribute__((unused)) gswitch* g)
> +  {};
> +  void walk_gswitch (gswitch* g);
> +  void _walk_gswitch (gswitch* g);
> +  virtual void _walk_post_gswitch (__attribute__((unused)) gswitch* g)
> +  {};
> +
> +  virtual void _walk_pre_gphi (__attribute__((unused)) gphi* g)
> +  {};
> +  void walk_gphi (gphi* g);
> +  void _walk_gphi (gphi* g);
> +  virtual void _walk_post_gphi (__attribute__((unused)) gphi* g)
> +  {};
> +
> +};
> +
> +/* TYPE_PARTITIONS_S is a structure that is shared
> + * across most of the type escape analysis.  It holds
> + * 4 different partitions.
> +
> + * 1. points to record
> + * 2. complement of points to record
> + * 3. escaping trees
> + * 4. non escaping trees
> +
> + * It also has a set of all types seen so far called universe.
> +
> + * Ideally 1 union 2 should be universe and 3 union 4 should be universe.
> + */
> +struct type_partitions_s
> +{
> +  /* The set of all types which have been seen.  */
> +  tset_t universe;
> +
> +  /* The set of all types which somehow refer to a RECORD_TYPE.  */
> +  tset_t points_to_record;
> +
> +  /* The complement of points_to_record.  */
> +  tset_t complement;
> +
> +  /* The set of all escaping types.  */
> +  tset_t escaping;
> +
> +  /* The set of all non escaping types.  */
> +  tset_t non_escaping;
> +
> +  /* Determine if we have seen this type before.  */
> +  bool in_universe (tree) const;
> +
> +  /* Determine if tree points to a record.  */
> +  bool in_points_to_record (tree) const;
> +
> +  /* Determine if tree does not point to a record.  */
> +  bool in_complement (tree) const;
> +
> +  /* Insert either in points to record or complement.  */
> +  void insert (tree, bool);
> +};
> +
> +typedef struct type_partitions_s tpartitions_t;
> +
> +/* TypeCollector is a derived class from TypeWalker
> + * that collects all types reachable from T into the partitions
> + * points_to_record or not points to record.
> + */
> +class type_collector : public type_walker
> +{
> +public:
> +  type_collector ()
> +  {};
> +
> +  /* Main interface.  */
> +  void collect (tree t);
> +
> +  /* Collect the result after walking all trees.  */
> +  tpartitions_t get_record_reaching_trees ()
> +  {
> +    _sanity_check ();
> +    return ptrset;
> +  }
> +
> +private:
> +  /* PTR stands for points to record.  Before walking into a RECORD_TYPE
> +   * tree, the value is always false.  Once a RECORD_TYPE is visited,
> +   * update all values on map to be true.  At post-order keys
> +   * will be erased.
> +   * Invariants:
> +   * before pre-order of root T map is empty
> +   * after post-order of root T map is empty
> +
> +   * In other words, the contents are reset after every
> +   * call to collect.
> +   */
> +  std::map<tree, bool> ptr;
> +
> +  /* The type partition set that will hold partitions for
> +   * points to record or does not point to record.
> +   * Will be updated during post-order with the keys and values
> +   * from PTR.
> +   * This datastructure persists across calls to collect.
> +   */
> +  tpartitions_t ptrset;
> +
> +  /* Sanity check determines that the partitions are mutually
> +   * exclusive.
> +   */
> +  void _sanity_check ();
> +
> +  /* Store T into partition depending on PTR.  */
> +  void _collect_simple (tree t);
> +
> +  /* If the value is in PTRSET, no need to visit the lower nodes.  */
> +  virtual bool is_memoized (tree t);
> +
> +  /* These functions insert and erase elements in PTR.
> +
> +   * We probably don't need to create a _pre and _post
> +   * function for all of them.  We could probably substitute
> +   * one for a general *_pre and *_post method that triggers
> +   * for all different type T.  However, we want to avoid
> +   * collecting FIELD_DECL, ARGS, and some other none-types.
> +   */
> +  virtual void _walk_VOID_TYPE_pre (tree t);
> +  virtual void _walk_VOID_TYPE_post (tree t);
> +  virtual void _walk_INTEGER_TYPE_pre (tree t);
> +  virtual void _walk_INTEGER_TYPE_post (tree t);
> +  virtual void _walk_REAL_TYPE_pre (tree t);
> +  virtual void _walk_REAL_TYPE_post (tree t);
> +  virtual void _walk_FIXED_POINT_TYPE_pre (tree t);
> +  virtual void _walk_FIXED_POINT_TYPE_post (tree t);
> +  virtual void _walk_COMPLEX_TYPE_pre (tree t);
> +  virtual void _walk_COMPLEX_TYPE_post (tree t);
> +  virtual void _walk_ENUMERAL_TYPE_pre (tree t);
> +  virtual void _walk_ENUMERAL_TYPE_post (tree t);
> +  virtual void _walk_BOOLEAN_TYPE_pre (tree t);
> +  virtual void _walk_BOOLEAN_TYPE_post (tree t);
> +  virtual void _walk_ARRAY_TYPE_pre (tree t);
> +  virtual void _walk_ARRAY_TYPE_post (tree t);
> +  virtual void _walk_POINTER_TYPE_pre (tree t);
> +  virtual void _walk_POINTER_TYPE_post (tree t);
> +  virtual void _walk_REFERENCE_TYPE_pre (tree t);
> +  virtual void _walk_REFERENCE_TYPE_post (tree t);
> +  virtual void _walk_UNION_TYPE_pre (tree t);
> +  virtual void _walk_UNION_TYPE_post (tree t);
> +  virtual void _walk_FUNCTION_TYPE_pre (tree t);
> +  virtual void _walk_FUNCTION_TYPE_post (tree t);
> +  virtual void _walk_METHOD_TYPE_pre (tree t);
> +  virtual void _walk_METHOD_TYPE_post (tree t);
> +
> +  /* When a RECORD_TYPE is found, update all values in PTR to true.  */
> +  virtual void _walk_RECORD_TYPE_pre (tree t);
> +  virtual void _walk_RECORD_TYPE_post (tree t);
> +};
> +
> +/* Derived class from TypeWalker.  This class
> + * will recursively print all type trees unlike just printing
> + * the identifier.
> + * TODO: Is this already implemented with debug_tree / print_tree?
> + * If so, we can probably delete this...
> + */
> +class type_stringifier : public type_walker
> +{
> +public:
> +  type_stringifier ()
> +  {};
> +
> +  /* Main method, returns a stringified version of T.  */
> +  std::string stringify (tree t);
> +
> +  /* Only get type identifier.  */
> +  static std::string get_type_identifier (tree t);
> +
> +  /* If field is not anonymous, return field identifier.  */
> +  static std::string get_field_identifier (tree t);
> +
> +private:
> +  /* Working string... will hold result for stringify.  */
> +  std::string _stringification;
> +
> +  /* Append get_tree_code_name.  */
> +  void _stringify_simple (tree t);
> +
> +  /* Append identifier and "{".  */
> +  void _stringify_aggregate_pre (tree t);
> +
> +  /* Append "}".  */
> +  void _stringify_aggregate_post (tree t);
> +
> +  /* Append "function {".  */
> +  // TODO: For C++ we will need to change this for methods.
> +  void _stringify_fm_pre (tree t);
> +  virtual void _walk_METHOD_TYPE_pre (tree t);
> +  virtual void _walk_METHOD_TYPE_post (tree t);
> +  virtual void _walk_FUNCTION_TYPE_pre (tree t);
> +  virtual void _walk_FUNCTION_TYPE_post (tree t);
> +
> +  /* Append "}".  */
> +  void _stringify_fm_post (tree t);
> +
> +  /* Most of the pre-order walk can probably be replaced by
> +   * a catch all pre-order call back.
> +   * TODO: implement that...
> +   */
> +  virtual void _walk_VOID_TYPE_pre (tree t);
> +  virtual void _walk_INTEGER_TYPE_pre (tree t);
> +  virtual void _walk_REAL_TYPE_pre (tree t);
> +  virtual void _walk_FIXED_POINT_TYPE_pre (tree t);
> +  virtual void _walk_COMPLEX_TYPE_pre (tree t);
> +  virtual void _walk_BOOLEAN_TYPE_pre (tree t);
> +  virtual void _walk_OFFSET_TYPE_pre (tree t);
> +  virtual void _walk_return_pre (tree t);
> +  virtual void _walk_args_pre (tree t);
> +
> +  /* Append "*".  */
> +  virtual void _walk_POINTER_TYPE_post (tree t);
> +
> +  /* Append "&".  */
> +  virtual void _walk_REFERENCE_TYPE_post (tree t);
> +
> +  /* Append "[]".  */
> +  virtual void _walk_ARRAY_TYPE_post (tree t);
> +
> +  /* Append "record" */
> +  virtual void _walk_RECORD_TYPE_pre (tree t);
> +  virtual void _walk_RECORD_TYPE_post (tree t);
> +
> +  /* Append "union" */
> +  virtual void _walk_UNION_TYPE_pre (tree t);
> +  virtual void _walk_UNION_TYPE_post (tree t);
> +
> +  /* Append "," */
> +  virtual void _walk_field_post (tree t);
> +  virtual void _walk_return_post (tree t);
> +
> +  /* Append "," */
> +  virtual void _walk_args_post (tree t);
> +  virtual void _walk_arg_post (tree t);
> +};
> +
> +/* ExprCollector is an implementation of ExprWalker.  It walks
> + * all trees in an expression and calls type collector on
> + * the types for all types of nested expressions.
> + */
> +class expr_collector : public expr_walker
> +{
> +public:
> +  expr_collector ()
> +  {};
> +
> +  /* Holds the result after collecting from all trees.  */
> +  tpartitions_t get_record_reaching_trees ()
> +  {
> +    return typeCollector.get_record_reaching_trees ();
> +  }
> +
> +private:
> +  type_collector typeCollector;
> +
> +  /* Catch all callback for all nested expressions E.  */
> +  virtual void _walk_pre (tree e);
> +};
> +
> +/* Derived from GimpleWalker.  Its purpose is to walk all gimple
> + * possible and call expression collector to collect types
> + * on global variables, assign statement, return statement,
> + * condition statement, and call statements.
> + */
> +class gimple_type_collector : public gimple_walker
> +{
> +public:
> +  gimple_type_collector ()
> +  {};
> +
> +  /* This holds the result after walking the whole program.  */
> +  tpartitions_t get_record_reaching_trees ()
> +  {
> +    return _expr_collector.get_record_reaching_trees ();
> +  }
> +
> +  // Print final results.
> +  // TODO: I believe this could be made const.
> +  void print_collected ();
> +
> +private:
> +  expr_collector _expr_collector;
> +
> +  /* Call back for global variables.  */
> +  virtual void _walk_pre_tree (tree);
> +
> +  /* Call back for gassign.  */
> +  virtual void _walk_pre_gassign (gassign *s);
> +
> +  /* Call back for greturn.  */
> +  virtual void _walk_pre_greturn (greturn *s);
> +
> +  /* Call back for gcond.  */
> +  virtual void _walk_pre_gcond (gcond *s);
> +
> +  /* Call back for gcall.  */
> +  virtual void _walk_pre_gcall (gcall *s);
> +};
> +
> +// Reason for why a type is escaping
> +// Used in a map with corresponding trees as keys.
> +// TODO: Add bit_field
> +// TODO: Add has function pointer
> +// TODO: Add has constructor
> +struct Reason
> +{
> +  // Determines whether a type is escaping.
> +  inline bool is_escaping () const
> +  {
> +    return this->global_is_visible || this->parameter_is_visible
> +          || this->return_is_visible || this->type_is_casted
> +          || this->type_is_volatile || this->type_is_in_union
> +          || this->is_indirect;
> +  }
> +
> +  // Escapes because a global variable is visible.
> +  bool global_is_visible : 1;
> +
> +  // Escapes because a parameter is used in an
> +  // externally visible function.
> +  bool parameter_is_visible : 1;
> +
> +  // Escapes because return value is from
> +  // an externally visible function.
> +  bool return_is_visible : 1;
> +
> +  // Escapes because of casting.
> +  bool type_is_casted : 1;
> +
> +  // Escapes because it is volatile.
> +  bool type_is_volatile : 1;
> +
> +  // Escapes because it is in union.
> +  bool type_is_in_union : 1;
> +
> +  // Escapes because is in indirect function call.
> +  bool is_indirect : 1;
> +
> +  // Merge two reason.
> +  Reason operator| (const Reason &);
> +  Reason &operator|= (const Reason &);
> +
> +  // Print reasons a type is escaping.
> +  void print () const;
> +
> +  // Initialize as non-escaping by default.
> +  Reason ()
> +    : global_is_visible (0), parameter_is_visible (0),
> return_is_visible (0),
> +      type_is_casted (0), type_is_volatile (0), type_is_in_union (0),
> +      is_indirect (0)
> +{};
> +};
> +
> +typedef std::map<tree, Reason> typemap;
> +
> +/* Type Escaper propagates information on whether a type escapes
> + * to all types reachable by a root type.  It also propagates
> + * information up if a union is found.  At the moment
> + * we don't transform types which point to unions.
> + * We also don't transform RECORD_TYPEs which have function pointers.
> + * This can possible be removed.  But it is future work.
> + * Do not also modify types with bit fields.
> + */
> +class type_escaper : public type_walker
> +{
> +public:
> +  type_escaper (tpartitions_t &p)
> +    : _ptrset (p), _inside_union (0), _inside_record (0)
> +  {};
> +
> +  // Hold the partitions for escaping non escaping.
> +  tpartitions_t &_ptrset;
> +
> +  // Have information that matches a tree type with
> +  // why a type is escaping.
> +  typemap calc;
> +
> +  // Get partitions after calculating escaping types.
> +  tpartitions_t get_sets ();
> +
> +  // Print reasons why a type is escaping.
> +  void print_reasons ();
> +
> +  // Update type T with escaping reason R.
> +  void update (tree t, Reason r);
> +
> +  // Update type T with escaping reason R.
> +  void _update_single (tree t, Reason r);
> +
> +
> +private:
> +  // TODO: we can probably reduce the amount of functions
> +  // by adding a catch all pre-order callback...
> +  virtual void _walk_POINTER_TYPE_pre (tree t);
> +  virtual void _walk_POINTER_TYPE_post (tree t);
> +  virtual void _walk_REFERENCE_TYPE_pre (tree t);
> +  virtual void _walk_ARRAY_TYPE_pre (tree t);
> +  virtual void _walk_ARRAY_TYPE_post (tree t);
> +  virtual void _walk_RECORD_TYPE_pre (tree t);
> +  virtual void _walk_RECORD_TYPE_post (tree t);
> +  virtual void _walk_field_pre (tree t);
> +  virtual bool is_memoized (tree t);
> +
> +  /* Mark escaping reason as having a function pointer in a structure,
> +   * propagate up and down.  */
> +  virtual void _walk_METHOD_TYPE_pre (tree t);
> +  virtual void _walk_FUNCTION_TYPE_pre (tree t);
> +
> +  /* Mark escaping reason as having a union and propagate up and down.  */
> +  virtual void _walk_UNION_TYPE_pre (tree t);
> +  virtual void _walk_UNION_TYPE_post (tree t);
> +
> +  // Record how many nested unions the current context is in.
> +  unsigned _inside_union;
> +
> +  // Record how many nested records the current context is in.
> +  unsigned _inside_record;
> +
> +  // Recursive inner function.
> +  void _update (tree t);
> +
> +  // Reason to be propagated to all trees reachable by root T
> +  // Can be updated during the walk.
> +  Reason _reason;
> +
> +
> +  // Final method that places types from calc to partitions.
> +  void place_escaping_types_in_set ();
> +};
> +
> +/* Visit all expressions and update reasons why they might be deleted.  */
> +class expr_escaper : public expr_walker
> +{
> +public:
> +  expr_escaper (tpartitions_t &types) : _type_escaper (types)
> +  {};
> +
> +  /* Main interface: T escapes because R.  */
> +  void update (tree t, Reason r);
> +
> +  /* Will be used to propagate escaping reasons to Types.  */
> +  type_escaper _type_escaper;
> +
> +  /* Holds the end result.  */
> +  tpartitions_t get_sets ();
> +
> +  /* Print end result.  */
> +  void print_reasons ();
> +
> +  cgraph_node *curr_node;
> +
> +private:
> +  // Keep track of the current expressions.  The top of the stack
> +  // is the subexpression being examined.
> +  // The bottom of the stack is the expression called on the update
> +  // function.
> +  std::stack<tree> _stack;
> +
> +  // Reason to propagate across all subexpressions.
> +  Reason _r;
> +
> +  // push to stack.
> +  virtual void _walk_pre (tree e);
> +
> +  // pop to stack.
> +  virtual void _walk_post (tree e);
> +
> +  // Check if there is a cast between the
> +  // expression (MEM_REF (SSA_NAME))
> +  // SSA_NAME is the subexpression of MEM_REF.
> +  virtual void _walk_SSA_NAME_pre (tree e);
> +
> +  // If the expression E is a constructor then we need
> +  // to mark these types as escaping because we cannot
> +  // deal with constructors at the moment.
> +  virtual void _walk_CONSTRUCTOR_pre (tree e);
> +};
> +
> +// Do a type structural equality for two types.
> +class type_structural_equality
> +{
> +public:
> +  type_structural_equality ()
> +  {};
> +
> +  // Return TRUE if A and B have equal structures
> +  bool equal (tree a, tree b);
> +
> +protected:
> +  // Recursive _equal
> +  virtual bool _equal (tree a, tree b);
> +
> +private:
> +  // Use to limit recursion if we are revisiting a node
> +  typedef std::set<tree> tset_t;
> +
> +  // Limit recursion for LHS
> +  tset_t set_l;
> +
> +  // Limit recursion for RHS
> +  tset_t set_r;
> +
> +  // Determine if the code is equal
> +  bool _equal_code (tree a, tree b);
> +
> +  // Wrapper around POINTER_TYPE, ARRAY_TYPE and REFERENCE_TYPE
> +  bool _equal_wrapper (tree a, tree b);
> +
> +  // Different types we are comparing
> +#define TSE_FUNC_DECL(code)                                    \
> +  virtual bool _walk_##code (tree l, tree r)
> +
> +  // Current types that can be compared.
> +  TSE_FUNC_DECL (VOID_TYPE);
> +  TSE_FUNC_DECL (COMPLEX_TYPE);
> +  TSE_FUNC_DECL (INTEGER_TYPE);
> +  TSE_FUNC_DECL (REAL_TYPE);
> +  TSE_FUNC_DECL (FIXED_POINT_TYPE);
> +  TSE_FUNC_DECL (POINTER_TYPE);
> +  TSE_FUNC_DECL (ENUMERAL_TYPE);
> +  TSE_FUNC_DECL (BOOLEAN_TYPE);
> +  TSE_FUNC_DECL (OFFSET_TYPE);
> +  TSE_FUNC_DECL (RECORD_TYPE);
> +  TSE_FUNC_DECL (REFERENCE_TYPE);
> +  TSE_FUNC_DECL (ARRAY_TYPE);
> +  TSE_FUNC_DECL (UNION_TYPE);
> +  TSE_FUNC_DECL (FUNCTION_TYPE);
> +  TSE_FUNC_DECL (METHOD_TYPE);
> +};
> +
> +// Check for equality even when a type is incomplete.
> +// When one type is incomplete and MAIN_VARIANTS are different
> +// compare only with identifiers.
> +// Unsound but it is as sound as it can be.
> +class type_incomplete_equality : public type_structural_equality
> +{
> +public:
> +  type_incomplete_equality ()
> +  {};
> +
> +protected:
> +  virtual bool _equal (tree l, tree r);
> +};
> +
> +/* Inspect gimple code and find reasons why types might escape given a
> gimple
> + * stmt.  */
> +class gimple_escaper : public gimple_walker
> +{
> +public:
> +  gimple_escaper (tpartitions_t &types) : _expr_escaper (types)
> +  {
> +    _init ();
> +  };
> +
> +  /* Propagate escaping reason to subexpressions.  */
> +  expr_escaper _expr_escaper;
> +
> +  /* Obtain final result.  */
> +  tpartitions_t get_sets ();
> +
> +  /* Print final result.  */
> +  void print_reasons ();
> +
> +protected:
> +  /* Set of undefined functions, this set is filled with
> +   * functions obtained via FOR_EACH_FUNCTION_WITH_GIMPLE_BODY.  */
> +  typedef std::set<tree> undefset;
> +  undefset undefined;
> +
> +  /* Initializes undefined.  */
> +  void _init ();
> +
> +  /* Return true if it is a known builtin function.  */
> +  static bool filter_known_function (cgraph_node *);
> +  static bool filter_known_function (tree);
> +
> +  /* Return true if function is externally visible.  */
> +  static bool is_function_escaping (cgraph_node *);
> +  static bool is_function_escaping (tree);
> +
> +  /* Return true if variable is externally visible.  */
> +  static bool is_variable_escaping (varpool_node *);
> +
> +  /* Marks global variables with CONSTRUCTORS and ERROR_MARKs as
> escaping.  */
> +  virtual void _walk_global (varpool_node *);
> +
> +  /* Do not escape on assignments.  */
> +  virtual void _walk_pre_gassign (gassign *s);
> +
> +  /* Do not escape return values.  */
> +  virtual void _walk_pre_greturn (greturn *s);
> +
> +  /* Do not escape gcond.  */
> +  virtual void _walk_pre_gcond (gcond *s);
> +
> +  /* Mark arguments and return type as escaping
> +   * if callsite is undefined, indirect or externally visible.  */
> +  virtual void _walk_pre_gcall (gcall *s);
> +
> +  /* Mark T as escaping if is in UNKNOWN_LOCATION.
> +   * This is a way of finding
> +   * types introduced by profiling and mark them as escaping.
> +   * TODO: Improve this.
> +   */
> +  virtual void _walk_pre_tree (tree t);
> +};
> +
> +/*
> + * GimpleCaster is intended to walk gimple
> + * and update a map that will hold information
> + * on whether a type was casted or not.
> + */
> +class gimple_caster : public gimple_escaper
> +{
> +public:
> +  gimple_caster (tpartitions_t &types) : gimple_escaper (types)
> +{};
> +
> +private:
> +  /* Determine if cast comes from a known function.  */
> +  static bool follow_def_to_find_if_really_cast (tree);
> +
> +  /* If arguments are casted, mark them as escaping.
> +   * Assignments from malloc and other known functions
> +   * are allowed.
> +   * */
> +  virtual void _walk_pre_gcall (gcall *s);
> +
> +  /* If assignment is casted, mark them as escaping.
> +   * Assignments from malloc and other known functions
> +   * are allowed.
> +   */
> +  virtual void _walk_pre_gassign (gassign *s);
> +};
> +
> +// Bitflags used for determining if a field is
> +// never accessed, read or written.
> +// TODO: Place on their own namespace?
> +const unsigned Empty = 0x0u;
> +const unsigned Read = 0x01u;
> +const unsigned Write = 0x02u;
> +
> +// maps FIELD_DECL -> bitflag.
> +typedef std::map<tree, unsigned> field_access_map_t;
> +
> +// maps RECORD_TYPE -> (FIELD_DECL -> bitflag).
> +typedef std::map<tree, field_access_map_t> record_field_map_t;
> +
> +// Class used to determine if a FIELD is read, written or never accessed.
> +class type_accessor : public type_walker
> +{
> +public:
> +  type_accessor (record_field_map_t &map) : _map (map)
> +  {};
> +
> +private:
> +  // maps RECORD -> (FIELD_DECL -> bitflag).
> +  record_field_map_t &_map;
> +
> +  // set of trees which are memoized and we don't need to look into them.
> +  std::set<tree> memoized_map;
> +
> +  // If a RECORD_TYPE is walked into, add all fields in struct to
> +  // record_field_map.
> +  virtual void _walk_RECORD_TYPE_pre (tree t);
> +  void add_all_fields_in_struct (tree t);
> +
> +  bool is_memoized (tree t);
> +};
> +
> +// Determine if a FIELD is read, written or never accessed from
> +// an expression.
> +class expr_accessor : public expr_walker
> +{
> +public:
> +  expr_accessor () : _type_accessor (record_field_map)
> +  {};
> +
> +  // Expr E is accessed in A manner.
> +  void update (tree e, unsigned a);
> +
> +  // Print results.
> +  void print_accesses ();
> +
> +  // Add all fields to map.  Initialize with empty.
> +  void add_all_fields_in_struct (tree t);
> +
> +  // Get final results.
> +  record_field_map_t get_map ();
> +
> +private:
> +  // Access {"Read", "Write", "Neither"} to propagate to all
> subexpressions.
> +  unsigned _access;
> +
> +  // Stack to keep track of how current subexpression was reached.
> +  std::stack<tree> _stack;
> +
> +  // Holds main results.
> +  record_field_map_t record_field_map;
> +
> +  // Aids expr-accessor in updating types.
> +  type_accessor _type_accessor;
> +
> +  // Mark FIELD_DECL as read.
> +  // If ADDR_EXPR is parent expression that means
> +  // The address of a field is taken.  Mark
> +  // all fields as possibly read.
> +  virtual void _walk_COMPONENT_REF_pre (tree e);
> +
> +  // Check if parent expression is MEM_REF.
> +  // This means that an optimization was made
> +  // and a FIELD_DECL is accessed via pointer
> +  // arithmetic.  Mark all fields from start to the one
> +  // accessed as read.
> +  // TODO: We don't necessarily need to mark them as
> +  // possibly read if we update these expressions to
> +  // point to the correct address in the future.
> +  virtual void _walk_ADDR_EXPR_pre (tree e);
> +
> +  // Push to stack.
> +  virtual void _walk_pre (tree t);
> +
> +  // Pop from stack.
> +  virtual void _walk_post (tree t);
> +};
> +
> +/* Walk all gimple and determine if fields were accessed.  */
> +class gimple_accessor : public gimple_walker
> +{
> +public:
> +  gimple_accessor ()
> +  {};
> +
> +  /* Print final results.  */
> +  void print_accesses ();
> +
> +  /* Get final results.  */
> +  record_field_map_t get_map ();
> +
> +private:
> +  /* Navigate expressions in gimple statements.  */
> +  expr_accessor _expr_accessor;
> +
> +  /* Mark all RHS expressions reachable from S as Read.
> +     all all LHS expressions reachable from S as Written.  */
> +  virtual void _walk_pre_gcall (gcall *s);
> +
> +  /* Mark all RHS expressions reachable from S as Read.
> +     Mark all LHS expressions reachable from S as Written.  */
> +  virtual void _walk_pre_gassign (gassign *s);
> +
> +  /* Mark all all expressions reachable from S as read.  */
> +  virtual void _walk_pre_greturn (greturn *s);
> +
> +  /* Mark all expressions reachable from S as read.  */
> +  virtual void _walk_pre_gcond (gcond *s);
> +
> +  // Do we need a glabel? I don't think so...
> +  // But we might need a gswitch.
> +};
> +
> +typedef std::set<unsigned> field_offsets_t;
> +
> +typedef std::map<tree, field_offsets_t> record_field_offset_map_t;
> +
> +
> +#endif /* GCC_IPA_TYPE_ESCAPE_ANALYSIS_H */
> diff --git a/gcc/passes.def b/gcc/passes.def
> index c68231287b6..a1cf09229d6 100644
> --- a/gcc/passes.def
> +++ b/gcc/passes.def
> @@ -172,6 +172,7 @@ along with GCC; see the file COPYING3.  If not see
>        passes are executed after partitioning and thus see just parts of
> the
>        compiled unit.  */
>     INSERT_PASSES_AFTER (all_late_ipa_passes)
> +  NEXT_PASS (pass_ipa_type_escape_analysis);
>     NEXT_PASS (pass_ipa_pta);
>     NEXT_PASS (pass_omp_simd_clone);
>     TERMINATE_PASS_LIST (all_late_ipa_passes)
> diff --git a/gcc/timevar.def b/gcc/timevar.def
> index a3031799700..5bda34d8efe 100644
> --- a/gcc/timevar.def
> +++ b/gcc/timevar.def
> @@ -81,6 +81,7 @@ DEFTIMEVAR (TV_IPA_INLINING          , "ipa inlining
> heuristics")
>   DEFTIMEVAR (TV_IPA_FNSPLIT           , "ipa function splitting")
>   DEFTIMEVAR (TV_IPA_COMDATS         , "ipa comdats")
>   DEFTIMEVAR (TV_IPA_OPT                     , "ipa various optimizations")
> +DEFTIMEVAR (TV_IPA_STRUCTURE_REORG   , "ipa structure reorg")
>   DEFTIMEVAR (TV_IPA_LTO_DECOMPRESS    , "lto stream decompression")
>   DEFTIMEVAR (TV_IPA_LTO_COMPRESS      , "lto stream compression")
>   DEFTIMEVAR (TV_IPA_LTO_OUTPUT        , "lto stream output")
> diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
> index 9cb22acc243..f1a7dc6758e 100644
> --- a/gcc/tree-pass.h
> +++ b/gcc/tree-pass.h
> @@ -515,6 +515,8 @@ extern ipa_opt_pass_d *make_pass_ipa_devirt
> (gcc::context *ctxt);
>   extern ipa_opt_pass_d *make_pass_ipa_odr (gcc::context *ctxt);
>   extern ipa_opt_pass_d *make_pass_ipa_reference (gcc::context *ctxt);
>   extern ipa_opt_pass_d *make_pass_ipa_pure_const (gcc::context *ctxt);
> +extern simple_ipa_opt_pass *
> +make_pass_ipa_type_escape_analysis (gcc::context *ctxt);
>   extern simple_ipa_opt_pass *make_pass_ipa_pta (gcc::context *ctxt);
>   extern simple_ipa_opt_pass *make_pass_ipa_tm (gcc::context *ctxt);
>   extern simple_ipa_opt_pass *make_pass_target_clone (gcc::context *ctxt);
> --
> 2.18.1
>
>

Reply via email to