[1/7] LTO Dead field elimination and field reordering

Erick Ochoa erick.ochoa@theobroma-systems.com
Wed Nov 4 13:27:46 GMT 2020


 From c287a2deb5b578f2d984f6ef2e7a6f66f5dd88a4 Mon Sep 17 00:00:00 2001
From: Erick Ochoa <erick.ochoa@theobroma-systems.com>
Date: Wed, 22 Jul 2020 15:11:24 +0200
Subject: [PATCH 1/7] Dead-field warning in structs at LTO-time

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.ochoa@theobroma-systems.com>

	* gcc/Makefile.in: add file to list of sources
	* gcc/common.opt: add new flags
	* gcc/ipa-type-escape-analysis.c: New

	* gcc/testsuite/ChangeLog:
             ipa-access-counter-00-simple-read-0.c: New
             ipa-access-counter-01-simple-write-0.c: Same
             ipa-access-counter-02-pointer-read-0.c: Same
             ipa-access-counter-03-pointer-write-0.c: Same
             ipa-access-counter-04-gimple-cond-0.c: Same
             ipa-ea-00-collect-global-record-0.c: Same
             ipa-01-collect-global-pointers-to-record-0.c: Same
             ipa-ea-02-collect-global-array-to-record-0.c: Same
             ipa-ea-03-collect-nested-record-0.c: Same
             ipa-ea-04-collect-parameters-0.c: Same
             ipa-ea-05-global-escapes-0.c: Same
             ipa-ea-06-global-type-escapes-0.c: Same
             ipa-ea-08-parameter-escapes-0.c: Same
             ipa-ea-10-return-type-escapes-0.c: Same
             ipa-ea-11-cast-to-void-ptr-0.c: Same
             ipa-ea-12-cast-to-void-ptr-0.c: Same
             ipa-ea-13-calling-printf-0.c: Same
             ipa-ea-14-volatile-0.c: Same
             ipa-ea-15-union-0.c: Same
             ipa-ea-16-parameter-cast-0.c: Same
             ipa-ea-17-malloc-0.c: Same
             ipa-structreorg-03-new-type-0.c: Same
             ipa-structreorg-04-heterogeneous-struct-0.c: Same
             ipa-structreorg-04-layout-compile-0.c: Same
             ipa-structreorg-05-field-reads-0.c: Same
             ipa-structreorg-05-nested-struct-0.c: Same
             ipa-structreorg-05-rewrite-local-decl-0.c: Same
             ipa-structreorg-06-field-writes-0.c: Same
             ipa-structreorg-06-pointer-struct-0.c: Same
             ipa-structreorg-07-delete-first-field-0.c: Same
             ipa-structreorg-08-modify-double-struct-0.c: Same
             ipa-structreorg-09-modify-int-struct-0.c: Same
             ipa-structreorg-1-prints-structs-0.c: Same
             ipa-structreorg-10-array-0.c: Same
             ipa-structreorg-11-rewrites-minus-expr-0.c: Same
             ipa-structreorg-12-delete-last-field-0.c: Same
             ipa-structreorg-13-modify-size-four-0.c: Same
             ipa-structreorg-14-rewrite-plus-expr-0.c: Same
             ipa-structreorg-15-rewrite-mult-expr-0.c: Same
             ipa-structreorg-16-rewrite-field-reads-ptr-0.c: Same
             ipa-structreorg-17-rewrite-field-write-ptr-0.c: Same
             ipa-structreorg-18-field-writes-deref-0.c: Same
             ipa-structreorg-19-middle-pointer-equal-0.c: Same
             ipa-structreorg-2-modifies-0.c: Same
             ipa-structreorg-20-array-offset-0.c: Same
             ipa-structreorg-22-rewrites-addr-expr-read-0.c: Same
             ipa-structreorg-23-array-cast-0.c: Same
             ipa-structreorg-25-array-cast-0.c: Same
             ipa-structreorg-26-array-cast-0.c: Same
             ipa-structreorg-27-array-cast-0.c: Same
             ipa-structreorg-29-heterogeneous-struct.c: Same
             ipa-structreorg-30-heterogenous-struct-0.c: Same
             ipa-structreorg-31-heterogenous-struct-0.c: Same
             ipa-structreorg-33-nested-struct-0.c : Same
             ipa-structreorg-33-pointer-indirection-level-0.c: Same
             ipa-structreorg-34-array-cast-0.c: Same
             ipa-structreorg-36-arguments-0.c : Same
             ipa-structreorg-37-arguments-0.c: Same
             ipa-structreorg-38-return-values-0.c: Same
             ipa-structreorg-39-typedef-0.c: Same
             ipa-structreorg-40-typedef-0.c: Same
             ipa-structreorg-41-deref-0.c: Same
             ipa-structreorg-42-mem-ref-0.c: Same
             ipa-structreorg-43-args-0.c: Same
             ipa-structreorg-44-cond-0.c: Same
             ipa-structreorg-45-phis-0.c: Same
             ipa-structreorg-46-static-0.c: Same
             ipa-structreorg-47-constructor-0.c: Same
             ipa-structreorg-48-function-ptr-0.c: Same
             ipa-structreorg-50-field-write-delete-0.c: Same
             ipa-structreorg-51-creduce-0.c: Same
             ipa-structreorg-52-creduce-1.c: Same
             ipa-structreorg-53-csmith-2.c : Same
             ipa-structreorg-54-csmith-3.c: Same
             ipa-structreorg-55-csmith-4.c: Same
             ipa-structreorg-56-csmith-5.c: Same
             ipa-structreorg-57-csmith-6.c: Same
             ipa-structreorg-58-csmith-7.c: Same
             ipa-structreorg-59-csmith-8.c: Same
             ipa-structreorg-60-csmith-9.c: Same

---
  gcc/Makefile.in                               |    1 +
  gcc/common.opt                                |   24 +
  gcc/ipa-type-escape-analysis.c                | 3414 +++++++++++++++++
  gcc/ipa-type-escape-analysis.h                | 1148 ++++++
  gcc/passes.def                                |    1 +
  .../ipa/ipa-access-counter-00-simple-read-0.c |   22 +
  .../ipa-access-counter-01-simple-write-0.c    |   22 +
  .../ipa-access-counter-02-pointer-read-0.c    |   22 +
  .../ipa-access-counter-03-pointer-write-0.c   |   22 +
  .../ipa/ipa-access-counter-04-gimple-cond-0.c |   24 +
  .../ipa/ipa-ea-00-collect-global-record-0.c   |   20 +
  ...a-01-collect-global-pointers-to-record-0.c |   23 +
  ...a-ea-02-collect-global-array-to-record-0.c |   23 +
  .../ipa/ipa-ea-03-collect-nested-record-0.c   |   26 +
  .../ipa/ipa-ea-04-collect-parameters-0.c      |   40 +
  .../gcc.dg/ipa/ipa-ea-05-global-escapes-0.c   |   37 +
  .../ipa/ipa-ea-06-global-type-escapes-0.c     |   42 +
  .../ipa/ipa-ea-08-parameter-escapes-0.c       |   37 +
  .../ipa/ipa-ea-10-return-type-escapes-0.c     |   42 +
  .../gcc.dg/ipa/ipa-ea-11-cast-to-void-ptr-0.c |   44 +
  .../gcc.dg/ipa/ipa-ea-12-cast-to-void-ptr-0.c |   38 +
  .../gcc.dg/ipa/ipa-ea-13-calling-printf-0.c   |   27 +
  .../gcc.dg/ipa/ipa-ea-14-volatile-0.c         |   20 +
  gcc/testsuite/gcc.dg/ipa/ipa-ea-15-union-0.c  |   25 +
  .../gcc.dg/ipa/ipa-ea-16-parameter-cast-0.c   |   33 +
  gcc/testsuite/gcc.dg/ipa/ipa-ea-17-malloc-0.c |   24 +
  .../ipa/ipa-structreorg-03-new-type-0.c       |   21 +
  ...pa-structreorg-04-heterogeneous-struct-0.c |   21 +
  .../ipa/ipa-structreorg-04-layout-compile-0.c |   21 +
  .../ipa/ipa-structreorg-05-field-reads-0.c    |   20 +
  .../ipa/ipa-structreorg-05-nested-struct-0.c  |   30 +
  .../ipa-structreorg-05-rewrite-local-decl-0.c |   23 +
  .../ipa/ipa-structreorg-06-field-writes-0.c   |   24 +
  .../ipa/ipa-structreorg-06-pointer-struct-0.c |   31 +
  .../ipa-structreorg-07-delete-first-field-0.c |   23 +
  ...pa-structreorg-08-modify-double-struct-0.c |   33 +
  .../ipa-structreorg-09-modify-int-struct-0.c  |   22 +
  .../ipa/ipa-structreorg-1-prints-structs-0.c  |   19 +
  .../gcc.dg/ipa/ipa-structreorg-10-array-0.c   |   23 +
  ...ipa-structreorg-11-rewrites-minus-expr-0.c |   22 +
  .../ipa-structreorg-12-delete-last-field-0.c  |   23 +
  .../ipa-structreorg-13-modify-size-four-0.c   |   25 +
  .../ipa-structreorg-14-rewrite-plus-expr-0.c  |   25 +
  .../ipa-structreorg-15-rewrite-mult-expr-0.c  |   25 +
  ...structreorg-16-rewrite-field-reads-ptr-0.c |   24 +
  ...structreorg-17-rewrite-field-write-ptr-0.c |   23 +
  .../ipa-structreorg-18-field-writes-deref-0.c |   26 +
  ...pa-structreorg-19-middle-pointer-equal-0.c |   26 +
  .../gcc.dg/ipa/ipa-structreorg-2-modifies-0.c |   20 +
  .../ipa/ipa-structreorg-20-array-offset-0.c   |   24 +
  ...structreorg-22-rewrites-addr-expr-read-0.c |   23 +
  .../ipa/ipa-structreorg-23-array-cast-0.c     |   31 +
  .../ipa/ipa-structreorg-25-array-cast-0.c     |   31 +
  .../ipa/ipa-structreorg-26-array-cast-0.c     |   24 +
  .../ipa/ipa-structreorg-27-array-cast-0.c     |   21 +
  .../ipa-structreorg-29-heterogeneous-struct.c |   22 +
  ...ipa-structreorg-30-heterogenous-struct-0.c |   27 +
  ...ipa-structreorg-31-heterogenous-struct-0.c |   30 +
  .../ipa/ipa-structreorg-33-nested-struct-0.c  |   39 +
  ...ructreorg-33-pointer-indirection-level-0.c |   26 +
  .../ipa/ipa-structreorg-34-array-cast-0.c     |   26 +
  .../ipa/ipa-structreorg-36-arguments-0.c      |   42 +
  .../ipa/ipa-structreorg-37-arguments-0.c      |   43 +
  .../ipa/ipa-structreorg-38-return-values-0.c  |   39 +
  .../gcc.dg/ipa/ipa-structreorg-39-typedef-0.c |   21 +
  .../gcc.dg/ipa/ipa-structreorg-40-typedef-0.c |   22 +
  .../gcc.dg/ipa/ipa-structreorg-41-deref-0.c   |   30 +
  .../gcc.dg/ipa/ipa-structreorg-42-mem-ref-0.c |   32 +
  .../gcc.dg/ipa/ipa-structreorg-43-args-0.c    |   39 +
  .../gcc.dg/ipa/ipa-structreorg-44-cond-0.c    |   16 +
  .../gcc.dg/ipa/ipa-structreorg-45-phis-0.c    |   17 +
  .../gcc.dg/ipa/ipa-structreorg-46-static-0.c  |   23 +
  .../ipa/ipa-structreorg-47-constructor-0.c    |   27 +
  .../ipa/ipa-structreorg-48-function-ptr-0.c   |   44 +
  .../ipa-structreorg-50-field-write-delete-0.c |   24 +
  .../gcc.dg/ipa/ipa-structreorg-51-creduce-0.c |    6 +
  .../gcc.dg/ipa/ipa-structreorg-52-creduce-1.c |   13 +
  .../gcc.dg/ipa/ipa-structreorg-53-csmith-2.c  |    6 +
  .../gcc.dg/ipa/ipa-structreorg-54-csmith-3.c  |   24 +
  .../gcc.dg/ipa/ipa-structreorg-55-csmith-4.c  |    9 +
  .../gcc.dg/ipa/ipa-structreorg-56-csmith-5.c  |   25 +
  .../gcc.dg/ipa/ipa-structreorg-57-csmith-6.c  |    8 +
  .../gcc.dg/ipa/ipa-structreorg-58-csmith-7.c  |   15 +
  .../gcc.dg/ipa/ipa-structreorg-59-csmith-8.c  |   14 +
  .../gcc.dg/ipa/ipa-structreorg-60-csmith-9.c  |   26 +
  gcc/timevar.def                               |    1 +
  gcc/tree-pass.h                               |    2 +
  87 files changed, 6643 insertions(+)
  create mode 100644 gcc/ipa-type-escape-analysis.c
  create mode 100644 gcc/ipa-type-escape-analysis.h
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-access-counter-00-simple-read-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-access-counter-01-simple-write-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-access-counter-02-pointer-read-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-access-counter-03-pointer-write-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-access-counter-04-gimple-cond-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-ea-00-collect-global-record-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-ea-01-collect-global-pointers-to-record-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-ea-02-collect-global-array-to-record-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-ea-03-collect-nested-record-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-ea-04-collect-parameters-0.c
  create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-ea-05-global-escapes-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-ea-06-global-type-escapes-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-ea-08-parameter-escapes-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-ea-10-return-type-escapes-0.c
  create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-ea-11-cast-to-void-ptr-0.c
  create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-ea-12-cast-to-void-ptr-0.c
  create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-ea-13-calling-printf-0.c
  create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-ea-14-volatile-0.c
  create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-ea-15-union-0.c
  create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-ea-16-parameter-cast-0.c
  create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-ea-17-malloc-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-structreorg-03-new-type-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-structreorg-04-heterogeneous-struct-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-structreorg-04-layout-compile-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-structreorg-05-field-reads-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-structreorg-05-nested-struct-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-structreorg-05-rewrite-local-decl-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-structreorg-06-field-writes-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-structreorg-06-pointer-struct-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-structreorg-07-delete-first-field-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-structreorg-08-modify-double-struct-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-structreorg-09-modify-int-struct-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-structreorg-1-prints-structs-0.c
  create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-structreorg-10-array-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-structreorg-11-rewrites-minus-expr-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-structreorg-12-delete-last-field-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-structreorg-13-modify-size-four-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-structreorg-14-rewrite-plus-expr-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-structreorg-15-rewrite-mult-expr-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-structreorg-16-rewrite-field-reads-ptr-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-structreorg-17-rewrite-field-write-ptr-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-structreorg-18-field-writes-deref-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-structreorg-19-middle-pointer-equal-0.c
  create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-structreorg-2-modifies-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-structreorg-20-array-offset-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-structreorg-22-rewrites-addr-expr-read-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-structreorg-23-array-cast-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-structreorg-25-array-cast-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-structreorg-26-array-cast-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-structreorg-27-array-cast-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-structreorg-29-heterogeneous-struct.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-structreorg-30-heterogenous-struct-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-structreorg-31-heterogenous-struct-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-structreorg-33-nested-struct-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-structreorg-33-pointer-indirection-level-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-structreorg-34-array-cast-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-structreorg-36-arguments-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-structreorg-37-arguments-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-structreorg-38-return-values-0.c
  create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-structreorg-39-typedef-0.c
  create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-structreorg-40-typedef-0.c
  create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-structreorg-41-deref-0.c
  create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-structreorg-42-mem-ref-0.c
  create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-structreorg-43-args-0.c
  create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-structreorg-44-cond-0.c
  create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-structreorg-45-phis-0.c
  create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-structreorg-46-static-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-structreorg-47-constructor-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-structreorg-48-function-ptr-0.c
  create mode 100644 
gcc/testsuite/gcc.dg/ipa/ipa-structreorg-50-field-write-delete-0.c
  create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-structreorg-51-creduce-0.c
  create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-structreorg-52-creduce-1.c
  create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-structreorg-53-csmith-2.c
  create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-structreorg-54-csmith-3.c
  create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-structreorg-55-csmith-4.c
  create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-structreorg-56-csmith-5.c
  create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-structreorg-57-csmith-6.c
  create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-structreorg-58-csmith-7.c
  create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-structreorg-59-csmith-8.c
  create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-structreorg-60-csmith-9.c

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..39bb6e100c3 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -3460,4 +3460,28 @@ 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.
+
+fipa-type-escape-analysis-keep-casts
+Common Report Var(flag_ipa_type_escape_analysis_keep_casts) Init(0)
+This flag is used to ignore casting in the legality analysis of dead 
field elimination.
+
+fprint-escape-analysis
+Common Report Var(flag_print_escape_analysis) Optimization
+This flag is used to print the escape analysis proper.  It does not 
include type casting.
+
+fprint-cast-analysis
+Common Report Var(flag_print_cast_analysis) Optimization
+This flag is used to print the escape analysis including type casting.
+
+fprint-access-analysis
+Common Report Var(flag_print_access_analysis) Optimization
+This flag is used to print the access analysis (if field is read or 
written to).
+
  ; 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..17d8d799d16
--- /dev/null
+++ b/gcc/ipa-type-escape-analysis.c
@@ -0,0 +1,3414 @@
+/* IPA Type Escape Analysis and Dead Field Elimination
+   Copyright (C) 2019-2020 Free Software Foundation, Inc.
+
+  Contributed by Erick Ochoa <erick.ochoa@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 "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 <vector>
+#include <set>
+#include <map>
+#include <stack>
+
+#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 const_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
+const_tree_to_tree (const_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.
+  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 ()
+{
+  GimpleTypeCollector 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 ();
+  GimpleCaster caster (partitions);
+  caster.walk ();
+
+  // Dump for debugging.
+  if (flag_print_cast_analysis)
+    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 ()
+{
+  GimpleAccesser accesser;
+  accesser.walk ();
+
+  // Dump for debugging.
+  if (flag_print_access_analysis)
+    accesser.print_accesses ();
+
+  // 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 const_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<const_tree>
+find_equivalent_trees (const_tree r_i, record_field_map_t record_field_map,
+		       tpartitions_t casting)
+{
+  TypeIncompleteEquality equality;
+  std::vector<const_tree> equivalence;
+  bool is_rin_record = casting.in_points_to_record (r_i);
+  if (!is_rin_record)
+    return equivalence;
+
+  for (std::map<const_tree, field_access_map_t>::const_iterator j
+       = record_field_map.begin (),
+       f = record_field_map.end ();
+       j != f; j++)
+    {
+      const_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 (const_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 = const_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<const_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<const_tree> equivalent, record_field_map_t &record_field_map,
+  field_offsets_t &field_offset)
+{
+  for (std::vector<const_tree>::iterator j = equivalent.begin (),
+					 f = equivalent.end ();
+       j != f; j++)
+    {
+      const_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<const_tree> &to_keep, std::set<const_tree> &to_erase)
+{
+  for (std::map<const_tree, field_offsets_t>::iterator i
+       = record_field_offset_map.begin (),
+       e = record_field_offset_map.end ();
+       i != e; ++i)
+    {
+      const_tree record = i->first;
+      const bool keep = to_keep.find (record) != to_keep.end ();
+      if (keep)
+	continue;
+
+      to_erase.insert (record);
+    }
+
+  for (std::set<const_tree>::iterator i = to_erase.begin (),
+				      e = to_erase.end ();
+       i != e; ++i)
+    {
+      const_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<const_tree> &to_erase, tpartitions_t casting)
+{
+  const tset_t &non_escaping = casting.non_escaping;
+  for (std::map<const_tree, field_offsets_t>::iterator i
+       = record_field_offset_map.begin (),
+       e = record_field_offset_map.end ();
+       i != e; ++i)
+    {
+      const_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<const_tree, field_access_map_t>::iterator i
+       = record_field_map.begin (),
+       e = record_field_map.end ();
+       i != e; ++i)
+    {
+      const_tree r_i = i->first;
+      std::vector<const_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<const_tree> to_erase;
+  std::set<const_tree> to_keep;
+  mark_escaping_types_to_be_deleted (record_field_offset_map, to_erase,
+				     casting);
+  for (std::map<const_tree, field_offsets_t>::iterator i
+       = record_field_offset_map.begin (),
+       e = record_field_offset_map.end ();
+       i != e; ++i)
+    {
+      const_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",
+	       TypeStringifier::get_type_identifier (record).c_str (),
+	       TypeStringifier::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
+TypeWalker::walk (const_tree t)
+{
+  gcc_assert (t);
+  this->tset.clear ();
+  this->_walk (t);
+}
+
+void
+TypeWalker::_walk (const_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 TypeWalker::walk_##code (const_tree t)				\
+  {									\
+    assert_is_type (t, code);						\
+    _walk_##code##_pre (t);						\
+    _walk_##code (t);							\
+    _walk_##code##_post (t);						\
+  }
+
+#define TypeWalkerFuncDefInternal(code)					\
+  void TypeWalker::_walk_##code (__attribute__ ((unused)) const_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 TypeWalker::_walk_wrapper (const_tree t)
+{
+  const_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 TypeWalker::_walk_##code (const_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
+TypeWalker::_walk_RECORD_TYPE (const_tree t)
+{
+  _walk_record_or_union (t);
+}
+
+TypeWalkerFuncDef (UNION_TYPE)
+
+void
+TypeWalker::_walk_UNION_TYPE (const_tree t)
+{
+  _walk_record_or_union (t);
+}
+
+void
+TypeWalker::_walk_record_or_union (const_tree t)
+{
+  for (tree field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field))
+    {
+      gcc_assert (field);
+      walk_field (field);
+    }
+}
+
+void
+TypeWalker::walk_field (const_tree t)
+{
+  _walk_field_pre (t);
+  _walk_field (t);
+  _walk_field_post (t);
+}
+
+void
+TypeWalker::_walk_field (const_tree t)
+{
+  const_tree inner_type = TREE_TYPE (t);
+  gcc_assert (inner_type);
+  _walk (inner_type);
+}
+
+TypeWalkerFuncDef (FUNCTION_TYPE)
+
+  void TypeWalker::_walk_FUNCTION_TYPE (const_tree t)
+{
+  _walk_function_or_method (t);
+}
+
+TypeWalkerFuncDef (METHOD_TYPE)
+
+  void TypeWalker::_walk_METHOD_TYPE (const_tree t)
+{
+  _walk_function_or_method (t);
+}
+
+void
+TypeWalker::_walk_function_or_method (const_tree t)
+{
+  const_tree ret_type = TREE_TYPE (t);
+  walk_return (ret_type);
+  walk_args (t);
+}
+
+void
+TypeWalker::walk_return (const_tree t)
+{
+  _walk_return_pre (t);
+  _walk_return (t);
+  _walk_return_post (t);
+}
+
+void
+TypeWalker::_walk_return (const_tree t)
+{
+  _walk (t);
+}
+
+void
+TypeWalker::walk_args (const_tree t)
+{
+  _walk_args_pre (t);
+  _walk_args (t);
+  _walk_args_post (t);
+}
+
+void
+TypeWalker::_walk_args (const_tree t)
+{
+  for (tree arg_node = TYPE_ARG_TYPES (t); NULL_TREE != arg_node;
+       arg_node = TREE_CHAIN (arg_node))
+    {
+      const_tree arg_node_type = TREE_VALUE (arg_node);
+      gcc_assert (arg_node_type);
+      walk_arg (arg_node_type);
+    }
+}
+
+void
+TypeWalker::walk_arg (const_tree t)
+{
+  _walk_arg_pre (t);
+  _walk_arg (t);
+  _walk_arg_post (t);
+}
+
+void
+TypeWalker::_walk_arg (const_tree t)
+{
+  _walk (t);
+}
+
+/* Main interface for the ExprWalker... */
+void
+ExprWalker::walk (const_tree e)
+{
+  _walk_pre (e);
+  _walk (e);
+  _walk_post (e);
+}
+
+void
+ExprWalker::_walk (const_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 ExprWalker::walk_##code (const_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 ExprWalker::_walk_leaf (const_tree e, const enum tree_code c)
+{
+  assert_is_type (e, c);
+}
+
+void
+ExprWalker::_walk_op_n (const_tree e, unsigned n)
+{
+  gcc_assert (e);
+  const_tree op_n = TREE_OPERAND (e, n);
+  gcc_assert (op_n);
+  walk (op_n);
+}
+
+void
+ExprWalker::_walk_op_0 (const_tree e, const enum tree_code c)
+{
+  assert_is_type (e, c);
+  _walk_op_n (e, 0);
+}
+
+void
+ExprWalker::_walk_op_1 (const_tree e, const enum tree_code c)
+{
+  assert_is_type (e, c);
+  _walk_op_n (e, 0);
+  _walk_op_n (e, 1);
+}
+
+void
+ExprWalker::_walk_CONSTRUCTOR (__attribute__ ((unused)) const_tree e)
+{
+  // Future-work: If we want to support rewriting CONSTRUCTORs
+  // we will have to walk them
+}
+
+void
+ExprWalker::_walk_LE_EXPR (const_tree e)
+{
+  _walk_op_1 (e, LE_EXPR);
+}
+
+void
+ExprWalker::_walk_LT_EXPR (const_tree e)
+{
+  _walk_op_1 (e, LT_EXPR);
+}
+
+void
+ExprWalker::_walk_EQ_EXPR (const_tree e)
+{
+  _walk_op_1 (e, EQ_EXPR);
+}
+
+void
+ExprWalker::_walk_GT_EXPR (const_tree e)
+{
+  _walk_op_1 (e, GT_EXPR);
+}
+
+void
+ExprWalker::_walk_GE_EXPR (const_tree e)
+{
+  _walk_op_1 (e, GE_EXPR);
+}
+
+void
+ExprWalker::_walk_NE_EXPR (const_tree e)
+{
+  _walk_op_1 (e, NE_EXPR);
+}
+
+void
+ExprWalker::_walk_INTEGER_CST (const_tree e)
+{
+  _walk_leaf (e, INTEGER_CST);
+}
+
+void
+ExprWalker::_walk_REAL_CST (const_tree e)
+{
+  _walk_leaf (e, REAL_CST);
+}
+
+void
+ExprWalker::_walk_STRING_CST (const_tree e)
+{
+  _walk_leaf (e, STRING_CST);
+}
+
+void
+ExprWalker::_walk_BIT_FIELD_REF (__attribute__ ((unused)) const_tree e)
+{
+  // TODO:
+  // We currently don't support bit_field_ref
+  // but maybe we need to do something here?
+}
+
+void
+ExprWalker::_walk_ARRAY_REF (const_tree e)
+{
+  _walk_op_1 (e, ARRAY_REF);
+}
+
+void
+ExprWalker::_walk_MEM_REF (const_tree e)
+{
+  _walk_op_1 (e, MEM_REF);
+}
+
+void
+ExprWalker::_walk_COMPONENT_REF (const_tree e)
+{
+  _walk_op_1 (e, COMPONENT_REF);
+}
+
+void
+ExprWalker::_walk_SSA_NAME (const_tree e)
+{
+  _walk_leaf (e, SSA_NAME);
+}
+
+void
+ExprWalker::_walk_ADDR_EXPR (const_tree e)
+{
+  _walk_op_0 (e, ADDR_EXPR);
+}
+
+void
+ExprWalker::_walk_VIEW_CONVERT_EXPR (__attribute__ ((unused)) const_tree e)
+{
+  // TODO: I don't think we need to do anything here
+}
+
+void
+ExprWalker::_walk_IMAGPART_EXPR (__attribute__ ((unused)) const_tree e)
+{
+  // TODO: I don't think we need to do anything here
+}
+
+void
+ExprWalker::_walk_FIELD_DECL (const_tree e)
+{
+  _walk_leaf (e, FIELD_DECL);
+}
+
+void
+ExprWalker::_walk_VAR_DECL (const_tree e)
+{
+  _walk_leaf (e, VAR_DECL);
+}
+
+void
+ExprWalker::_walk_RESULT_DECL (const_tree e)
+{
+  _walk_leaf (e, RESULT_DECL);
+}
+
+void
+ExprWalker::_walk_PARM_DECL (const_tree e)
+{
+  _walk_leaf (e, PARM_DECL);
+}
+
+void
+ExprWalker::_walk_FUNCTION_DECL (const_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
+GimpleWalker::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
+GimpleWalker::_walk_globals ()
+{
+  varpool_node *vnode = NULL;
+  FOR_EACH_VARIABLE (vnode)
+    {
+      _walk_global (vnode);
+    }
+}
+
+/* Walk over global variable VNODE.  */
+void
+GimpleWalker::_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
+GimpleWalker::_walk_ssa_names (cgraph_node *cnode)
+{
+  const_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
+GimpleWalker::_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
+GimpleWalker::_walk_locals (cgraph_node *cnode)
+{
+  const_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
+GimpleWalker::_walk_bb (cgraph_node *cnode)
+{
+  gcc_assert (cnode);
+  cnode->get_untransformed_body ();
+  const_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
+GimpleWalker::_walk_decl (cgraph_node *cnode)
+{
+  const_tree decl = cnode->decl;
+  gcc_assert (decl);
+  walk_tree2 (decl);
+}
+
+/* Walk over each gimple statement in BB.  */
+void
+GimpleWalker::_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
+GimpleWalker::walk_gimple (gimple *stmt)
+{
+  _walk_pre_gimple (stmt);
+  _walk_gimple (stmt);
+  _walk_post_gimple (stmt);
+}
+
+/* Switch for different gimple instruction types.  */
+void
+GimpleWalker::_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
+GimpleWalker::walk_tree2 (const_tree t)
+{
+  _walk_pre_tree (t);
+  _walk_tree (t);
+  _walk_post_tree (t);
+}
+
+void
+GimpleWalker::_walk_tree (const_tree t)
+{}
+
+void
+GimpleWalker::walk_gassign (gassign *g)
+{
+  _walk_pre_gassign (g);
+  _walk_gassign (g);
+  _walk_post_gassign (g);
+}
+
+void
+GimpleWalker::_walk_gassign (gassign *g)
+{}
+
+void
+GimpleWalker::walk_greturn (greturn *g)
+{
+  _walk_pre_greturn (g);
+  _walk_greturn (g);
+  _walk_post_greturn (g);
+}
+
+void
+GimpleWalker::_walk_greturn (greturn *g)
+{}
+
+void
+GimpleWalker::walk_gcond (gcond *g)
+{
+  _walk_pre_gcond (g);
+  _walk_gcond (g);
+  _walk_post_gcond (g);
+}
+
+void
+GimpleWalker::_walk_gcond (gcond *g)
+{}
+
+void
+GimpleWalker::walk_gcall (gcall *g)
+{
+  _walk_pre_gcall (g);
+  _walk_gcall (g);
+  _walk_post_gcall (g);
+}
+
+void
+GimpleWalker::_walk_gcall (gcall *g)
+{}
+
+void
+GimpleWalker::walk_glabel (glabel *g)
+{
+  _walk_pre_glabel (g);
+  _walk_glabel (g);
+  _walk_post_glabel (g);
+}
+
+void
+GimpleWalker::_walk_glabel (glabel *g)
+{}
+
+void
+GimpleWalker::walk_gswitch (gswitch *g)
+{
+  _walk_pre_gswitch (g);
+  _walk_gswitch (g);
+  _walk_post_gswitch (g);
+}
+
+void
+GimpleWalker::_walk_gswitch (gswitch *g)
+{
+}
+
+void
+GimpleWalker::walk_gphi (gphi *g)
+{
+  _walk_pre_gphi (g);
+  _walk_gphi (g);
+  _walk_post_gphi (g);
+}
+
+void
+GimpleWalker::_walk_gphi (gphi *g)
+{
+}
+
+
+void
+TypeCollector::collect (const_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
+TypeCollector::_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)
+	{
+	  const_tree type_ptr = *i;
+	  gcc_assert (type_ptr);
+	  const_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
+TypeCollector::is_memoized (const_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<const_tree, bool>::iterator i = ptr.begin (),
+	e = ptr.end (); i != e; ++i)
+    {
+      i->second |= points_to_record;
+    }
+  return true;
+}
+
+void
+TypeCollector::_walk_VOID_TYPE_pre (const_tree t)
+{
+  ptr[t] = false;
+}
+
+void
+TypeCollector::_walk_VOID_TYPE_post (const_tree t)
+{
+  _collect_simple (t);
+}
+
+void
+TypeCollector::_walk_INTEGER_TYPE_pre (const_tree t)
+{
+  ptr[t] = false;
+}
+
+void
+TypeCollector::_walk_INTEGER_TYPE_post (const_tree t)
+{
+  _collect_simple (t);
+}
+
+void
+TypeCollector::_walk_REAL_TYPE_pre (const_tree t)
+{
+  ptr[t] = false;
+}
+
+void
+TypeCollector::_walk_REAL_TYPE_post (const_tree t)
+{
+  _collect_simple (t);
+}
+
+void
+TypeCollector::_walk_FIXED_POINT_TYPE_pre (const_tree t)
+{
+  ptr[t] = false;
+}
+
+void
+TypeCollector::_walk_FIXED_POINT_TYPE_post (const_tree t)
+{
+  _collect_simple (t);
+}
+
+void
+TypeCollector::_walk_COMPLEX_TYPE_pre (const_tree t)
+{
+  ptr[t] = false;
+}
+
+void
+TypeCollector::_walk_COMPLEX_TYPE_post (const_tree t)
+{
+  _collect_simple (t);
+}
+
+void
+TypeCollector::_walk_ENUMERAL_TYPE_pre (const_tree t)
+{
+  ptr[t] = false;
+}
+
+void
+TypeCollector::_walk_ENUMERAL_TYPE_post (const_tree t)
+{
+  _collect_simple (t);
+}
+
+void
+TypeCollector::_walk_BOOLEAN_TYPE_pre (const_tree t)
+{
+  ptr[t] = false;
+}
+
+void
+TypeCollector::_walk_BOOLEAN_TYPE_post (const_tree t)
+{
+  _collect_simple (t);
+}
+
+void
+TypeCollector::_collect_simple (const_tree t)
+{
+  // Insert into persistent set.
+  ptrset.insert (t, ptr[t]);
+  // erase from current working set.
+  ptr.erase (t);
+}
+
+void
+TypeCollector::_walk_ARRAY_TYPE_pre (const_tree t)
+{
+  ptr[t] = false;
+}
+
+void
+TypeCollector::_walk_ARRAY_TYPE_post (const_tree t)
+{
+  _collect_simple (t);
+}
+
+void
+TypeCollector::_walk_POINTER_TYPE_pre (const_tree t)
+{
+  ptr[t] = false;
+}
+
+void
+TypeCollector::_walk_POINTER_TYPE_post (const_tree t)
+{
+  _collect_simple (t);
+}
+
+void
+TypeCollector::_walk_REFERENCE_TYPE_pre (const_tree t)
+{
+  ptr[t] = false;
+}
+
+void
+TypeCollector::_walk_REFERENCE_TYPE_post (const_tree t)
+{
+  _collect_simple (t);
+}
+
+void
+TypeCollector::_walk_RECORD_TYPE_post (const_tree t)
+{
+  // All in ptr point to record
+  for (std::map<const_tree, bool>::iterator i = ptr.begin (),
+	e = ptr.end (); i != e; ++i)
+    {
+      i->second = true;
+    }
+  _collect_simple (t);
+}
+
+void
+TypeCollector::_walk_RECORD_TYPE_pre (const_tree t)
+{
+  ptr[t] = false;
+}
+
+void
+TypeCollector::_walk_UNION_TYPE_pre (const_tree t)
+{
+  ptr[t] = false;
+}
+
+void
+TypeCollector::_walk_UNION_TYPE_post (const_tree t)
+{
+  _collect_simple (t);
+}
+
+void
+TypeCollector::_walk_FUNCTION_TYPE_post (const_tree t)
+{
+  _collect_simple (t);
+}
+
+void
+TypeCollector::_walk_FUNCTION_TYPE_pre (const_tree t)
+{
+  ptr[t] = false;
+}
+
+void
+TypeCollector::_walk_METHOD_TYPE_post (const_tree t)
+{
+  _collect_simple (t);
+}
+
+void
+TypeCollector::_walk_METHOD_TYPE_pre (const_tree t)
+{
+  ptr[t] = false;
+}
+
+inline void
+ExprCollector::_walk_pre (const_tree e)
+{
+  const_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
+GimpleTypeCollector::_walk_pre_tree (const_tree t)
+{
+  exprCollector.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
+GimpleTypeCollector::_walk_pre_gassign (gassign *s)
+{
+  const_tree lhs = gimple_assign_lhs (s);
+  exprCollector.walk (lhs);
+
+  const enum gimple_rhs_class gclass = gimple_assign_rhs_class (s);
+  switch (gclass)
+    {
+    case GIMPLE_TERNARY_RHS:
+      {
+	const_tree rhs = gimple_assign_rhs3 (s);
+	exprCollector.walk (rhs);
+      }
+    /* fall-through */
+    case GIMPLE_BINARY_RHS:
+      {
+	const_tree rhs = gimple_assign_rhs2 (s);
+	exprCollector.walk (rhs);
+      }
+    /* fall-through */
+    case GIMPLE_UNARY_RHS:
+    case GIMPLE_SINGLE_RHS:
+      {
+	const_tree rhs = gimple_assign_rhs1 (s);
+	exprCollector.walk (rhs);
+      }
+      break;
+    default:
+      gcc_unreachable ();
+      break;
+    }
+}
+
+void
+GimpleTypeCollector::_walk_pre_greturn (greturn *s)
+{
+  const_tree retval = gimple_return_retval (s);
+  if (!retval)
+    return;
+
+  exprCollector.walk (retval);
+}
+
+void
+GimpleTypeCollector::_walk_pre_gcall (gcall *s)
+{
+  // Walk over the arguments.
+  unsigned n = gimple_call_num_args (s);
+  for (unsigned i = 0; i < n; i++)
+    {
+      const_tree a = gimple_call_arg (s, i);
+      exprCollector.walk (a);
+    }
+
+  // Walk over the return type if it exists.
+  const_tree lhs = gimple_call_lhs (s);
+  if (!lhs)
+    return;
+
+  exprCollector.walk (lhs);
+}
+
+// Print working set.
+void
+GimpleTypeCollector::print_collected ()
+{
+  tpartitions_t sets = get_record_reaching_trees ();
+}
+
+/* Walk over LHS and RHS of conditions.  */
+void
+GimpleTypeCollector::_walk_pre_gcond (gcond *s)
+{
+  const_tree lhs = gimple_cond_lhs (s);
+  exprCollector.walk (lhs);
+  const_tree rhs = gimple_cond_rhs (s);
+  exprCollector.walk (rhs);
+}
+
+bool
+TypeEscaper::is_memoized (__attribute__ ((unused)) const_tree t)
+{
+  // Can't memoize here because
+  // information is propagated up and down
+  // the type.
+  return false;
+}
+
+tpartitions_t
+TypeEscaper::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
+TypeEscaper::place_escaping_types_in_set ()
+{
+  TypeStringifier stringifier;
+  for (typemap::iterator i = calc.begin (), e = calc.end (); i != e; ++i)
+    {
+      const_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
+TypeEscaper::update (const_tree t, Reason r)
+{
+  gcc_assert (t);
+  _reason = r;
+  walk (t);
+}
+
+void
+TypeEscaper::_update (const_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
+TypeEscaper::_walk_ARRAY_TYPE_pre (const_tree t)
+{
+  _update (t);
+}
+
+void
+TypeEscaper::_walk_ARRAY_TYPE_post (const_tree t)
+{
+  _update (t);
+}
+
+void
+TypeEscaper::_walk_POINTER_TYPE_pre (const_tree t)
+{
+  _update (t);
+}
+
+void
+TypeEscaper::_walk_POINTER_TYPE_post (const_tree t)
+{
+  _update (t);
+}
+
+void
+TypeEscaper::_walk_REFERENCE_TYPE_pre (const_tree t)
+{
+  _update (t);
+}
+
+void
+TypeEscaper::_walk_RECORD_TYPE_pre (const_tree t)
+{
+  // we are entering a record
+  _inside_record++;
+  _update (t);
+}
+
+void
+TypeEscaper::_walk_RECORD_TYPE_post (const_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
+TypeEscaper::_walk_UNION_TYPE_pre (const_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
+TypeEscaper::_walk_field_pre (const_tree t)
+{
+  _reason.type_is_in_union |= DECL_BIT_FIELD (t);
+}
+
+void
+TypeEscaper::_walk_UNION_TYPE_post (const_tree t)
+{
+  _inside_union--;
+  _update (t);
+}
+
+/* Mark as escaping because RECORD has a function pointer
+ * propagate up and down.
+ */
+void
+TypeEscaper::_walk_FUNCTION_TYPE_pre (__attribute__ ((unused)) 
const_tree t)
+{
+  _reason.type_is_in_union |= _inside_record > 0;
+}
+
+/* Mark as escaping because RECORD has a function pointer
+ * propagate up and down.
+ */
+void
+TypeEscaper::_walk_METHOD_TYPE_pre (__attribute__ ((unused)) const_tree t)
+{
+  _reason.type_is_in_union |= _inside_record > 0;
+}
+
+/* Print escaping reasons.  */
+void
+TypeEscaper::print_reasons ()
+{
+  TypeStringifier stringifier;
+  for (typemap::iterator i = calc.begin (), e = calc.end (); i != e; ++i)
+    {
+      const_tree t = i->first;
+      std::string name = stringifier.stringify (t);
+      Reason r = i->second;
+      log ("%s reason: ", name.c_str ());
+      r.print ();
+    }
+}
+
+tpartitions_t
+ExprEscaper::get_sets ()
+{
+  return typeEscaper.get_sets ();
+}
+
+void
+ExprEscaper::print_reasons ()
+{
+  typeEscaper.print_reasons ();
+}
+
+/* Propagate reason to subexpressions.  */
+void
+ExprEscaper::update (const_tree t, Reason r)
+{
+  gcc_assert (t);
+  _r = r;
+  walk (t);
+}
+
+/* Propagate reason to type of subexpressions.  */
+void
+ExprEscaper::_walk_pre (const_tree e)
+{
+  _stack.push (e);
+  const_tree t = TREE_TYPE (e);
+
+  gcc_assert (t);
+  typeEscaper.update (t, _r);
+}
+
+void
+ExprEscaper::_walk_post (__attribute__ ((unused)) const_tree e)
+{
+  _stack.pop ();
+}
+
+/* Capture casting on LHS.  */
+void
+ExprEscaper::_walk_SSA_NAME_pre (const_tree e)
+{
+  const_tree ssa_type = TREE_TYPE (e);
+
+  if (_stack.size () < 4)
+    return;
+
+  // TODO:
+  // It appears that we have a bug, where we are
+  // storing expressions twice on the stack
+  const_tree this_expr = _stack.top ();
+  _stack.pop ();
+  const_tree twice = _stack.top ();
+  _stack.pop ();
+  const_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);
+  const_tree mref_type = TREE_TYPE (op1);
+
+  Reason old_reason = _r;
+  TypeIncompleteEquality 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);
+  typeEscaper.update (mref_type, _r);
+  typeEscaper.update (ssa_type, _r);
+  _r = old_reason;
+}
+
+/* Mark constructors as escaping.  */
+void
+ExprEscaper::_walk_CONSTRUCTOR_pre (const_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;
+  const_tree t = TREE_TYPE (e);
+  typeEscaper.update (t, _r);
+}
+
+tpartitions_t
+GimpleEscaper::get_sets ()
+{
+  return exprEscaper.get_sets ();
+}
+
+void
+GimpleEscaper::print_reasons ()
+{
+  exprEscaper.print_reasons ();
+}
+
+/* Initialize undefined set of functions.  */
+void
+GimpleEscaper::_init ()
+{
+  cgraph_node *cnode = NULL;
+  FOR_EACH_FUNCTION (cnode)
+    {
+      gcc_assert (cnode);
+      const bool filter = GimpleEscaper::filter_known_function (cnode);
+      if (filter)
+	continue;
+
+      const_tree decl = cnode->decl;
+      gcc_assert (decl);
+      undefined.insert (decl);
+    }
+
+  FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (cnode)
+    {
+      gcc_assert (cnode);
+      cnode->get_untransformed_body ();
+      const_tree decl = cnode->decl;
+      gcc_assert (decl);
+      undefined.erase (decl);
+    }
+}
+
+/* Mark cnode graphs escaping if they are externally visible.  */
+bool
+GimpleEscaper::is_function_escaping (cgraph_node *cnode)
+{
+  const bool filter = GimpleEscaper::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
+GimpleEscaper::is_function_escaping (const_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
+GimpleEscaper::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
+GimpleEscaper::_walk_global (varpool_node *vnode)
+{
+  gcc_assert (vnode);
+  const_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...
+
+  exprEscaper.update (var_decl, reason);
+  GimpleWalker::_walk_global (vnode);
+}
+
+/* Return true if FNDECL is a known function.  */
+bool
+GimpleEscaper::filter_known_function (const_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
+GimpleEscaper::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
+GimpleEscaper::_walk_pre_tree (const_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;
+    }
+  exprEscaper.update (t, reason);
+}
+
+void
+GimpleEscaper::_walk_pre_gassign (gassign *s)
+{
+  Reason reason;
+  const enum gimple_rhs_class code = gimple_assign_rhs_class (s);
+  switch (code)
+    {
+    case GIMPLE_TERNARY_RHS:
+      {
+	const_tree rhs3 = gimple_assign_rhs3 (s);
+	exprEscaper.update (rhs3, reason);
+      }
+    /* fall-through */
+    case GIMPLE_BINARY_RHS:
+      {
+	const_tree rhs2 = gimple_assign_rhs2 (s);
+	exprEscaper.update (rhs2, reason);
+      }
+    /* fall-through */
+    case GIMPLE_UNARY_RHS:
+    case GIMPLE_SINGLE_RHS:
+      {
+	const_tree rhs1 = gimple_assign_rhs1 (s);
+	exprEscaper.update (rhs1, reason);
+	const_tree lhs = gimple_assign_lhs (s);
+	if (!lhs)
+	  break;
+	exprEscaper.update (lhs, reason);
+      }
+      break;
+    default:
+      gcc_unreachable ();
+      break;
+    }
+}
+
+void
+GimpleEscaper::_walk_pre_greturn (greturn *s)
+{
+  Reason reason;
+  const_tree val = gimple_return_retval (s);
+  if (!val)
+    return;
+  exprEscaper.update (val, reason);
+}
+
+void
+GimpleEscaper::_walk_pre_gcond (gcond *s)
+{
+  Reason reason;
+  const_tree lhs = gimple_cond_lhs (s);
+  const_tree rhs = gimple_cond_rhs (s);
+  gcc_assert (lhs && rhs);
+  exprEscaper.update (lhs, reason);
+  exprEscaper.update (rhs, reason);
+}
+
+void
+GimpleEscaper::_walk_pre_gcall (gcall *s)
+{
+  const_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;
+  TypeStringifier 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++)
+    {
+      const_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 ());
+	}
+      exprEscaper.typeEscaper.update (TREE_TYPE (a), arg_reason);
+    }
+
+  const_tree lhs = gimple_call_lhs (s);
+  if (!lhs)
+    return;
+  Reason return_reason;
+  return_reason.return_is_visible = _is_escaping;
+  return_reason.is_indirect = !fn;
+  exprEscaper.update (lhs, return_reason);
+}
+
+/* Determine if cast comes from a known function.
+ * Do this by following the use-def chain.  */
+bool
+GimpleCaster::follow_def_to_find_if_really_cast (const_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;
+
+  const_tree fn = gimple_call_fndecl (is_call);
+  if (!fn)
+    return true;
+
+  bool known_function = GimpleEscaper::filter_known_function (fn);
+  return !known_function;
+}
+
+void
+GimpleCaster::_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...
+  TypeIncompleteEquality equality;
+  const_tree lhs = gimple_assign_lhs (s);
+  const_tree rhs = gimple_assign_rhs1 (s);
+  gcc_assert (lhs && rhs);
+  Reason reason;
+  const_tree t_lhs = TREE_TYPE (lhs);
+  const_tree t_rhs = TREE_TYPE (rhs);
+  gcc_assert (t_lhs && t_rhs);
+  bool is_cast = !equality.equal (t_lhs, 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_ssa ? follow_def_to_find_if_really_cast (rhs) : is_cast;
+
+  reason.type_is_casted = is_cast;
+  if (!flag_ipa_type_escape_analysis_keep_casts)
+    exprEscaper.typeEscaper.update (TREE_TYPE (lhs), reason);
+  if (!flag_ipa_type_escape_analysis_keep_casts)
+    exprEscaper.typeEscaper.update (TREE_TYPE (rhs), reason);
+
+  GimpleEscaper::_walk_pre_gassign (s);
+}
+
+/* Check to see if arguments are casted.  */
+void
+GimpleCaster::_walk_pre_gcall (gcall *s)
+{
+  GimpleEscaper::_walk_pre_gcall (s);
+  if (flag_ipa_type_escape_analysis_keep_casts)
+    return;
+
+  const_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 = GimpleEscaper::filter_known_function (node)
+			      || GimpleEscaper::filter_known_function (fn);
+  if (known_function)
+    return;
+
+  const_tree f_t = TREE_TYPE (fn);
+  TypeIncompleteEquality equality;
+
+  unsigned i = 0;
+  for (tree a = TYPE_ARG_TYPES (f_t); NULL_TREE != a; a = TREE_CHAIN (a))
+    {
+      const_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;
+
+      const_tree real = gimple_call_arg (s, i);
+      const_tree real_t = TREE_TYPE (real);
+      const bool is_casted = !equality.equal (formal_t, real_t);
+      Reason arg_reason;
+      arg_reason.type_is_casted = is_casted;
+      exprEscaper.typeEscaper.update (TREE_TYPE (real), arg_reason);
+      i++;
+    }
+
+  const_tree lhs = gimple_call_lhs (s);
+  if (!lhs)
+    return;
+
+  const_tree r_t = TREE_TYPE (f_t);
+  const_tree l_t TREE_TYPE (lhs);
+  const bool is_casted = !equality.equal (r_t, l_t);
+  Reason ret_reason;
+  ret_reason.type_is_casted = is_casted;
+  exprEscaper.update (lhs, ret_reason);
+}
+
+bool
+TypeAccessor::is_memoized (const_tree t)
+{
+  return memoized_map.find (t) != memoized_map.end ();
+}
+
+/* Add all fields in struct to memoized map.  */
+void
+TypeAccessor::_walk_RECORD_TYPE_pre (const_tree t)
+{
+  add_all_fields_in_struct (t);
+  memoized_map.insert (t);
+}
+
+/* Initialize all fields as neither read nor written.  */
+void
+TypeAccessor::add_all_fields_in_struct (const_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
+ExprAccessor::get_map ()
+{
+  return record_field_map;
+}
+
+void
+ExprAccessor::add_all_fields_in_struct (const_tree t)
+{
+  _typeAccessor.walk (t);
+}
+
+void
+ExprAccessor::_walk_pre (const_tree e)
+{
+  _stack.push (e);
+  const_tree t = TREE_TYPE (e);
+  add_all_fields_in_struct (t);
+}
+
+void
+ExprAccessor::_walk_post (__attribute__ ((unused)) const_tree e)
+{
+  _stack.pop ();
+}
+
+void
+ExprAccessor::update (const_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
+ExprAccessor::_walk_ADDR_EXPR_pre (__attribute__ ((unused)) const_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
+  const_tree addr_expr = _stack.top ();
+  _stack.pop ();
+  const_tree twice = _stack.top ();
+  _stack.pop ();
+  const_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);
+  const_tree addr_expr_t = TREE_TYPE (op_0);
+
+  TypeStringifier 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...
+  const_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
+ExprAccessor::_walk_COMPONENT_REF_pre (const_tree e)
+{
+  log ("in component_ref pre\n");
+  assert_is_type (e, COMPONENT_REF);
+  const_tree op0 = TREE_OPERAND (e, 0);
+  gcc_assert (op0);
+  const_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);
+
+  const_tree op1 = TREE_OPERAND (e, 1);
+  assert_is_type (op1, FIELD_DECL);
+  log ("%s.%s\n", TypeStringifier::get_type_identifier (op0_t),
+       TypeStringifier::get_field_identifier (op1));
+  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;
+
+  const_tree this_expr = _stack.top ();
+  _stack.pop ();
+  const_tree twice = _stack.top ();
+  _stack.pop ();
+  const_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");
+  const_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
+ExprAccessor::print_accesses ()
+{
+  for (std::map<const_tree, field_access_map_t>::const_iterator i
+       = record_field_map.begin (),
+       e = record_field_map.end ();
+       i != e; ++i)
+    {
+      const_tree record = i->first;
+      field_access_map_t field_map = i->second;
+      for (std::map<const_tree, unsigned>::const_iterator j
+	   = field_map.begin (),
+	   f = field_map.end ();
+	   j != f; ++j)
+	{
+	  const_tree field = j->first;
+	  const std::string name_r
+	    = TypeStringifier::get_type_identifier (record);
+	  const std::string name_f
+	    = TypeStringifier::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
+GimpleAccesser::get_map ()
+{
+  return exprAccessor.get_map ();
+}
+
+void
+GimpleAccesser::print_accesses ()
+{
+  exprAccessor.print_accesses ();
+}
+
+/* Mark RHS as Read and LHS as Write.  */
+void
+GimpleAccesser::_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:
+      {
+	const_tree rhs3 = gimple_assign_rhs3 (s);
+	gcc_assert (rhs3);
+	exprAccessor.update (rhs3, Read);
+      }
+    /* fall-through */
+    case GIMPLE_BINARY_RHS:
+      {
+	const_tree rhs2 = gimple_assign_rhs2 (s);
+	gcc_assert (rhs2);
+	exprAccessor.update (rhs2, Read);
+      }
+    /* fall-through */
+    case GIMPLE_UNARY_RHS:
+    case GIMPLE_SINGLE_RHS:
+      {
+	const_tree rhs1 = gimple_assign_rhs1 (s);
+	exprAccessor.update (rhs1, Read);
+	const_tree lhs = gimple_assign_lhs (s);
+	if (!lhs)
+	  break;
+	exprAccessor.update (lhs, Write);
+	break;
+      }
+    default:
+      gcc_unreachable ();
+      break;
+    }
+}
+
+/* Mark RHS as Read and LHS as Written.  */
+void
+GimpleAccesser::_walk_pre_gcall (gcall *s)
+{
+  unsigned n = gimple_call_num_args (s);
+  for (unsigned i = 0; i < n; i++)
+    {
+      const_tree a = gimple_call_arg (s, i);
+      gcc_assert (a);
+      exprAccessor.update (a, Read);
+    }
+
+  const_tree lhs = gimple_call_lhs (s);
+  if (!lhs)
+    return;
+  exprAccessor.update (lhs, Write);
+}
+
+/* Mark as Read.  */
+void
+GimpleAccesser::_walk_pre_greturn (greturn *s)
+{
+  const_tree val = gimple_return_retval (s);
+  if (!val)
+    return;
+  exprAccessor.update (val, Read);
+}
+
+/* Mark as Read.  */
+void
+GimpleAccesser::_walk_pre_gcond (gcond *s)
+{
+  const_tree lhs = gimple_cond_lhs (s);
+  const_tree rhs = gimple_cond_rhs (s);
+  gcc_assert (lhs && rhs);
+  exprAccessor.update (lhs, Read);
+  exprAccessor.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 (const_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 (const_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 (const_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 (const_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
+TypeStringifier::stringify (const_tree t)
+{
+  if (!dump_file)
+    return std::string ("");
+  _stringification.clear ();
+  gcc_assert (t);
+  walk (t);
+  return _stringification;
+}
+
+void
+TypeStringifier::_walk_VOID_TYPE_pre (const_tree t)
+{
+  _stringify_simple (t);
+}
+
+void
+TypeStringifier::_walk_INTEGER_TYPE_pre (const_tree t)
+{
+  _stringify_simple (t);
+}
+
+void
+TypeStringifier::_walk_REAL_TYPE_pre (const_tree t)
+{
+  _stringify_simple (t);
+}
+
+void
+TypeStringifier::_walk_FIXED_POINT_TYPE_pre (const_tree t)
+{
+  _stringify_simple (t);
+}
+
+void
+TypeStringifier::_walk_COMPLEX_TYPE_pre (const_tree t)
+{
+  _stringify_simple (t);
+}
+
+void
+TypeStringifier::_walk_OFFSET_TYPE_pre (const_tree t)
+{
+  _stringify_simple (t);
+}
+
+void
+TypeStringifier::_walk_BOOLEAN_TYPE_pre (const_tree t)
+{
+  _stringify_simple (t);
+}
+
+void
+TypeStringifier::_stringify_simple (const_tree t)
+{
+  gcc_assert (t);
+  const enum tree_code code = TREE_CODE (t);
+  this->_stringification += std::string (get_tree_code_name (code));
+}
+
+void
+TypeStringifier::_walk_POINTER_TYPE_post (__attribute__ ((unused)) 
const_tree t)
+{
+  this->_stringification += std::string ("*");
+}
+
+void
+TypeStringifier::_walk_ARRAY_TYPE_post (__attribute__ ((unused)) 
const_tree t)
+{
+  this->_stringification += std::string ("[]");
+}
+
+void
+TypeStringifier::_walk_REFERENCE_TYPE_post (__attribute__ ((unused))
+					    const_tree t)
+{
+  this->_stringification += std::string ("&");
+}
+
+void
+TypeStringifier::_walk_UNION_TYPE_pre (const_tree t)
+{
+  this->_stringification += std::string (" union ");
+  _stringify_aggregate_pre (t);
+}
+
+void
+TypeStringifier::_walk_UNION_TYPE_post (const_tree t)
+{
+  _stringify_aggregate_post (t);
+}
+
+void
+TypeStringifier::_walk_RECORD_TYPE_pre (const_tree t)
+{
+  this->_stringification += std::string (" record ");
+  _stringify_aggregate_pre (t);
+}
+
+void
+TypeStringifier::_walk_RECORD_TYPE_post (const_tree t)
+{
+  _stringify_aggregate_post (t);
+}
+
+void
+TypeStringifier::_stringify_aggregate_pre (const_tree t)
+{
+  this->_stringification
+    += TypeStringifier::get_type_identifier (t) + std::string (" {");
+}
+
+void
+TypeStringifier::_stringify_aggregate_post (__attribute__ ((unused))
+					    const_tree t)
+{
+  this->_stringification += std::string ("}");
+}
+
+void
+TypeStringifier::_walk_field_post (const_tree t)
+{
+  this->_stringification += std::string (" ")
+			    + TypeStringifier::get_field_identifier (t)
+			    + std::string (";");
+}
+
+void
+TypeStringifier::_walk_METHOD_TYPE_pre (const_tree t)
+{
+  _stringify_fm_pre (t);
+}
+
+void
+TypeStringifier::_walk_METHOD_TYPE_post (const_tree t)
+{
+  _stringify_fm_post (t);
+}
+
+void
+TypeStringifier::_walk_FUNCTION_TYPE_pre (const_tree t)
+{
+  _stringify_fm_pre (t);
+}
+
+void
+TypeStringifier::_walk_FUNCTION_TYPE_post (const_tree t)
+{
+  _stringify_fm_post (t);
+}
+
+void
+TypeStringifier::_stringify_fm_pre (__attribute__ ((unused)) const_tree t)
+{
+  this->_stringification += std::string ("function { ");
+}
+
+void
+TypeStringifier::_stringify_fm_post (__attribute__ ((unused)) const_tree t)
+{
+  this->_stringification += std::string ("}");
+}
+
+void
+TypeStringifier::_walk_return_pre (__attribute__ ((unused)) const_tree t)
+{
+  this->_stringification += std::string ("(");
+}
+
+void
+TypeStringifier::_walk_return_post (__attribute__ ((unused)) const_tree t)
+{
+  this->_stringification += std::string (")");
+}
+
+void
+TypeStringifier::_walk_args_pre (__attribute__ ((unused)) const_tree t)
+{
+  this->_stringification += std::string ("(");
+}
+
+void
+TypeStringifier::_walk_args_post (__attribute__ ((unused)) const_tree t)
+{
+  this->_stringification += std::string (")");
+}
+
+void
+TypeStringifier::_walk_arg_post (__attribute__ ((unused)) const_tree t)
+{
+  this->_stringification += std::string (", ");
+}
+
+std::string
+TypeStringifier::get_type_identifier (const_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
+TypeStringifier::get_field_identifier (const_tree t)
+{
+  assert_is_type (t, FIELD_DECL);
+  const_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
+TypeStructuralEquality::equal (const_tree l, const_tree r)
+{
+  return _equal (l, r);
+}
+
+bool
+TypeStructuralEquality::_equal (const_tree l, const_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
+TypeStructuralEquality::_equal_code (const_tree l, const_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 TypeStructuralEquality::_walk_##code (const_tree l, const_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
+TypeStructuralEquality::_equal_wrapper (const_tree l, const_tree r)
+{
+  const_tree inner_l = TREE_TYPE (l);
+  const_tree inner_r = TREE_TYPE (r);
+  return _equal (inner_l, inner_r);
+}
+
+#define TSE_FUNC_DEF_WRAPPER(code)					 \
+  bool TypeStructuralEquality::_walk_##code (const_tree l, const_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 TypeStructuralEquality::_walk_##code (const_tree l, const_tree r) \
+  {									 \
+    const_tree field_l = TYPE_FIELDS (l);				 \
+    const_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) 				 \
+      {									 \
+	const_tree tfield_l = TREE_TYPE (field_l);			 \
+	const_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 TypeStructuralEquality::_walk_##code (const_tree l, const_tree r) \
+  {									 \
+    const_tree tret_l = TREE_TYPE (l);					 \
+    const_tree tret_r = TREE_TYPE (r);					 \
+    bool still_equal = _equal (tret_l, tret_r);				 \
+    if (!still_equal)							 \
+      return still_equal;						 \
+									 \
+    const_tree arg_l = TYPE_ARG_TYPES (l);				 \
+    const_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)				 \
+      {									 \
+	const_tree targ_l = TREE_VALUE (arg_l);				 \
+	const_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
+TypeIncompleteEquality::_equal (const_tree l, const_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 TypeStructuralEquality::_equal (l, r);
+
+  // Before comparing with identifiers
+  // make last attempt to compare using main variants.
+  const_tree m_l = TYPE_MAIN_VARIANT (l);
+  const_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 = TypeStringifier::get_type_identifier (m_l);
+  const std::string n_r = TypeStringifier::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;
+  TypeIncompleteEquality structuralEquality;
+  do
+    {
+      std::vector<const_tree> fixes;
+      fixed_point_reached = true;
+      for (std::set<const_tree>::const_iterator i = 
types.escaping.begin (),
+						e = types.escaping.end ();
+	   i != e; ++i)
+	{
+	  for (std::set<const_tree>::const_iterator j
+	       = types.non_escaping.begin (),
+	       f = types.non_escaping.end ();
+	       j != f; ++j)
+	    {
+	      const_tree type_esc = *i;
+	      gcc_assert (type_esc);
+	      const_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<const_tree>::const_iterator i = fixes.begin (),
+						   e = fixes.end ();
+	   i != e; ++i)
+	{
+	  const_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..d6a6b13d3c4
--- /dev/null
+++ b/gcc/ipa-type-escape-analysis.h
@@ -0,0 +1,1148 @@
+/* IPA Type Escape Analysis and Dead Field Elimination
+   Copyright (C) 2019-2020 Free Software Foundation, Inc.
+
+  Contributed by Erick Ochoa <erick.ochoa@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
+
+#include <string>
+#include <map>
+#include <set>
+
+/* Logging function, useful for debugging.  */
+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 (const_tree a)
+{
+  gcc_assert (a);
+  const_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 (const_tree a)
+{
+  const bool _is_complete = is_complete (a);
+  gcc_assert (_is_complete);
+}
+
+/* Determine if type A is incomplete.  */
+inline bool
+is_incomplete (const_tree a)
+{
+  return !is_complete (a);
+}
+
+/* Assert type A has is EXPECTED_CODE.  */
+inline void
+assert_is_type (const_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<const_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 TypeWalker
+{
+public:
+  TypeWalker ()
+  {};
+
+  /* Main interface to type walker.
+   * Walk type T.
+   */
+  void walk (const_tree t);
+
+protected:
+
+  /* Typeset holds previously visited nodes.  */
+  tset_t tset;
+
+  /* Inner walking method, used to recurse.  */
+  void _walk (const_tree t);
+
+  /* Common walking method for REFERENCE_TYPE, ARRAY_TYPE, and 
POINTER_TYPE.  */
+  void _walk_wrapper (const_tree t);
+
+  /* Common walking method for RECORD_TYPE and UNION_TYPE.  */
+  void _walk_record_or_union (const_tree t);
+
+  /* Common walking method for FUNCTION_TYPE and METHOD_TYPE.  */
+  virtual void _walk_function_or_method (const_tree t);
+
+  /* If the type is memoized and we don't need to walk further down.  */
+  virtual bool is_memoized (__attribute__ ((unused)) const_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 (const_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)) const_tree t) \
+  {}; \
+  virtual void _walk_##code (const_tree t); \
+  virtual void _walk_##code##_post (__attribute__((unused)) const_tree t) \
+  {}; \
+  virtual void walk_##code (const_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 ExprWalker
+{
+public:
+  ExprWalker ()
+  {};
+
+  /* Walk tree E.  */
+  void walk (const_tree e);
+
+private:
+
+  /* Virtual function to be implemented.  Callback for all E in 
preorder.  */
+  virtual void _walk_pre (__attribute__ ((unused)) const_tree e)
+  {};
+
+  /* Inner method that will recurse for walking subtrees in E.  */
+  void _walk (const_tree e);
+
+  /* Virtual function to be implemented.  Callback for all E in 
postorder.  */
+  virtual void _walk_post (__attribute__ ((unused)) const_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 (const_tree e, const enum tree_code c);
+  inline void _walk_op_n (const_tree e, unsigned n);
+  inline void _walk_op_0 (const_tree e, const enum tree_code c);
+  inline void _walk_op_1 (const_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)) const_tree 
e)  \
+  {};									   \
+  void walk_##code (const_tree e);					   \
+  void _walk_##code (const_tree e);					   \
+  virtual void _walk_##code##_post (__attribute__ ((unused)) const_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 GimpleWalker
+{
+public:
+  GimpleWalker () : _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)) const_tree t)
+  {};
+  void walk_tree2 (const_tree t);
+  void _walk_tree (const_tree t);
+  virtual void _walk_post_tree (__attribute__((unused)) const_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 (const_tree) const;
+
+  /* Determine if tree points to a record.  */
+  bool in_points_to_record (const_tree) const;
+
+  /* Determine if tree does not point to a record.  */
+  bool in_complement (const_tree) const;
+
+  /* Insert either in points to record or complement.  */
+  void insert (const_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 TypeCollector : public TypeWalker
+{
+public:
+  TypeCollector ()
+  {};
+
+  /* Main interface.  */
+  void collect (const_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<const_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 (const_tree t);
+
+  /* If the value is in PTRSET, no need to visit the lower nodes.  */
+  virtual bool is_memoized (const_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 (const_tree t);
+  virtual void _walk_VOID_TYPE_post (const_tree t);
+  virtual void _walk_INTEGER_TYPE_pre (const_tree t);
+  virtual void _walk_INTEGER_TYPE_post (const_tree t);
+  virtual void _walk_REAL_TYPE_pre (const_tree t);
+  virtual void _walk_REAL_TYPE_post (const_tree t);
+  virtual void _walk_FIXED_POINT_TYPE_pre (const_tree t);
+  virtual void _walk_FIXED_POINT_TYPE_post (const_tree t);
+  virtual void _walk_COMPLEX_TYPE_pre (const_tree t);
+  virtual void _walk_COMPLEX_TYPE_post (const_tree t);
+  virtual void _walk_ENUMERAL_TYPE_pre (const_tree t);
+  virtual void _walk_ENUMERAL_TYPE_post (const_tree t);
+  virtual void _walk_BOOLEAN_TYPE_pre (const_tree t);
+  virtual void _walk_BOOLEAN_TYPE_post (const_tree t);
+  virtual void _walk_ARRAY_TYPE_pre (const_tree t);
+  virtual void _walk_ARRAY_TYPE_post (const_tree t);
+  virtual void _walk_POINTER_TYPE_pre (const_tree t);
+  virtual void _walk_POINTER_TYPE_post (const_tree t);
+  virtual void _walk_REFERENCE_TYPE_pre (const_tree t);
+  virtual void _walk_REFERENCE_TYPE_post (const_tree t);
+  virtual void _walk_UNION_TYPE_pre (const_tree t);
+  virtual void _walk_UNION_TYPE_post (const_tree t);
+  virtual void _walk_FUNCTION_TYPE_pre (const_tree t);
+  virtual void _walk_FUNCTION_TYPE_post (const_tree t);
+  virtual void _walk_METHOD_TYPE_pre (const_tree t);
+  virtual void _walk_METHOD_TYPE_post (const_tree t);
+
+  /* When a RECORD_TYPE is found, update all values in PTR to true.  */
+  virtual void _walk_RECORD_TYPE_pre (const_tree t);
+  virtual void _walk_RECORD_TYPE_post (const_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 TypeStringifier : public TypeWalker
+{
+public:
+  TypeStringifier ()
+  {};
+
+  /* Main method, returns a stringified version of T.  */
+  std::string stringify (const_tree t);
+
+  /* Only get type identifier.  */
+  static std::string get_type_identifier (const_tree t);
+
+  /* If field is not anonymous, return field identifier.  */
+  static std::string get_field_identifier (const_tree t);
+
+private:
+  /* Working string... will hold result for stringify.  */
+  std::string _stringification;
+
+  /* Append get_tree_code_name.  */
+  void _stringify_simple (const_tree t);
+
+  /* Append identifier and "{".  */
+  void _stringify_aggregate_pre (const_tree t);
+
+  /* Append "}".  */
+  void _stringify_aggregate_post (const_tree t);
+
+  /* Append "function {".  */
+  // TODO: For C++ we will need to change this for methods.
+  void _stringify_fm_pre (const_tree t);
+  virtual void _walk_METHOD_TYPE_pre (const_tree t);
+  virtual void _walk_METHOD_TYPE_post (const_tree t);
+  virtual void _walk_FUNCTION_TYPE_pre (const_tree t);
+  virtual void _walk_FUNCTION_TYPE_post (const_tree t);
+
+  /* Append "}".  */
+  void _stringify_fm_post (const_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 (const_tree t);
+  virtual void _walk_INTEGER_TYPE_pre (const_tree t);
+  virtual void _walk_REAL_TYPE_pre (const_tree t);
+  virtual void _walk_FIXED_POINT_TYPE_pre (const_tree t);
+  virtual void _walk_COMPLEX_TYPE_pre (const_tree t);
+  virtual void _walk_BOOLEAN_TYPE_pre (const_tree t);
+  virtual void _walk_OFFSET_TYPE_pre (const_tree t);
+  virtual void _walk_return_pre (const_tree t);
+  virtual void _walk_args_pre (const_tree t);
+
+  /* Append "*".  */
+  virtual void _walk_POINTER_TYPE_post (const_tree t);
+
+  /* Append "&".  */
+  virtual void _walk_REFERENCE_TYPE_post (const_tree t);
+
+  /* Append "[]".  */
+  virtual void _walk_ARRAY_TYPE_post (const_tree t);
+
+  /* Append "record" */
+  virtual void _walk_RECORD_TYPE_pre (const_tree t);
+  virtual void _walk_RECORD_TYPE_post (const_tree t);
+
+  /* Append "union" */
+  virtual void _walk_UNION_TYPE_pre (const_tree t);
+  virtual void _walk_UNION_TYPE_post (const_tree t);
+
+  /* Append "," */
+  virtual void _walk_field_post (const_tree t);
+  virtual void _walk_return_post (const_tree t);
+
+  /* Append "," */
+  virtual void _walk_args_post (const_tree t);
+  virtual void _walk_arg_post (const_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 ExprCollector : public ExprWalker
+{
+public:
+  ExprCollector ()
+  {};
+
+  /* Holds the result after collecting from all trees.  */
+  tpartitions_t get_record_reaching_trees ()
+  {
+    return typeCollector.get_record_reaching_trees ();
+  }
+
+private:
+  TypeCollector typeCollector;
+
+  /* Catch all callback for all nested expressions E.  */
+  virtual void _walk_pre (const_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 GimpleTypeCollector : public GimpleWalker
+{
+public:
+  GimpleTypeCollector ()
+  {};
+
+  /* This holds the result after walking the whole program.  */
+  tpartitions_t get_record_reaching_trees ()
+  {
+    return exprCollector.get_record_reaching_trees ();
+  }
+
+  // Print final results.
+  // TODO: I believe this could be made const.
+  void print_collected ();
+
+private:
+  ExprCollector exprCollector;
+
+  /* Call back for global variables.  */
+  virtual void _walk_pre_tree (const_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<const_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 TypeEscaper : public TypeWalker
+{
+public:
+  TypeEscaper (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 (const_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 (const_tree t);
+  virtual void _walk_POINTER_TYPE_post (const_tree t);
+  virtual void _walk_REFERENCE_TYPE_pre (const_tree t);
+  virtual void _walk_ARRAY_TYPE_pre (const_tree t);
+  virtual void _walk_ARRAY_TYPE_post (const_tree t);
+  virtual void _walk_RECORD_TYPE_pre (const_tree t);
+  virtual void _walk_RECORD_TYPE_post (const_tree t);
+  virtual void _walk_field_pre (const_tree t);
+  virtual bool is_memoized (const_tree t);
+
+  /* Mark escaping reason as having a function pointer in a structure,
+   * propagate up and down.  */
+  virtual void _walk_METHOD_TYPE_pre (const_tree t);
+  virtual void _walk_FUNCTION_TYPE_pre (const_tree t);
+
+  /* Mark escaping reason as having a union and propagate up and down.  */
+  virtual void _walk_UNION_TYPE_pre (const_tree t);
+  virtual void _walk_UNION_TYPE_post (const_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;
+
+  // Reason to be propagated to all trees reachable by root T
+  // Can be updated during the walk.
+  Reason _reason;
+
+  // Recursive inner function.
+  void _update (const_tree t);
+
+  // 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 ExprEscaper : public ExprWalker
+{
+public:
+  ExprEscaper (tpartitions_t &types) : typeEscaper (types)
+  {};
+
+  /* Main interface: T escapes because R.  */
+  void update (const_tree t, Reason r);
+
+  /* Will be used to propagate escaping reasons to Types.  */
+  TypeEscaper typeEscaper;
+
+  /* Holds the end result.  */
+  tpartitions_t get_sets ();
+
+  /* Print end result.  */
+  void print_reasons ();
+
+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<const_tree> _stack;
+
+  // Reason to propagate across all subexpressions.
+  Reason _r;
+
+  // push to stack.
+  virtual void _walk_pre (const_tree e);
+
+  // pop to stack.
+  virtual void _walk_post (const_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 (const_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 (const_tree e);
+};
+
+// Do a type structural equality for two types.
+class TypeStructuralEquality
+{
+public:
+  TypeStructuralEquality ()
+  {};
+
+  // Return TRUE if A and B have equal structures
+  bool equal (const_tree a, const_tree b);
+
+protected:
+  // Recursive _equal
+  virtual bool _equal (const_tree a, const_tree b);
+
+private:
+  // Use to limit recursion if we are revisiting a node
+  typedef std::set<const_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 (const_tree a, const_tree b);
+
+  // Wrapper around POINTER_TYPE, ARRAY_TYPE and REFERENCE_TYPE
+  bool _equal_wrapper (const_tree a, const_tree b);
+
+  // Different types we are comparing
+#define TSE_FUNC_DECL(code)					\
+  virtual bool _walk_##code (const_tree l, const_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 TypeIncompleteEquality : public TypeStructuralEquality
+{
+public:
+  TypeIncompleteEquality ()
+  {};
+
+protected:
+  virtual bool _equal (const_tree l, const_tree r);
+};
+
+/* Inspect gimple code and find reasons why types might escape given a 
gimple
+ * stmt.  */
+class GimpleEscaper : public GimpleWalker
+{
+public:
+  GimpleEscaper (tpartitions_t &types) : exprEscaper (types)
+  {
+    _init ();
+  };
+
+  /* Propagate escaping reason to subexpressions.  */
+  ExprEscaper exprEscaper;
+
+  /* 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<const_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 (const_tree);
+
+  /* Return true if function is externally visible.  */
+  static bool is_function_escaping (cgraph_node *);
+  static bool is_function_escaping (const_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 (const_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 GimpleCaster : public GimpleEscaper
+{
+public:
+  GimpleCaster (tpartitions_t &types) : GimpleEscaper (types)
+{};
+
+private:
+  /* Determine if cast comes from a known function.  */
+  static bool follow_def_to_find_if_really_cast (const_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<const_tree, unsigned> field_access_map_t;
+
+// maps RECORD_TYPE -> (FIELD_DECL -> bitflag).
+typedef std::map<const_tree, field_access_map_t> record_field_map_t;
+
+// Class used to determine if a FIELD is read, written or never accessed.
+class TypeAccessor : public TypeWalker
+{
+public:
+  TypeAccessor (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<const_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 (const_tree t);
+  void add_all_fields_in_struct (const_tree t);
+
+  bool is_memoized (const_tree t);
+};
+
+// Determine if a FIELD is read, written or never accessed from
+// an expression.
+class ExprAccessor : public ExprWalker
+{
+public:
+  ExprAccessor () : _typeAccessor (record_field_map)
+  {};
+
+  // Expr E is accessed in A manner.
+  void update (const_tree e, unsigned a);
+
+  // Print results.
+  void print_accesses ();
+
+  // Add all fields to map.  Initialize with empty.
+  void add_all_fields_in_struct (const_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<const_tree> _stack;
+
+  // Holds main results.
+  record_field_map_t record_field_map;
+
+  // Aids expr-accessor in updating types.
+  TypeAccessor _typeAccessor;
+
+  // 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 (const_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 (const_tree e);
+
+  // Push to stack.
+  virtual void _walk_pre (const_tree t);
+
+  // Pop from stack.
+  virtual void _walk_post (const_tree t);
+};
+
+/* Walk all gimple and determine if fields were accessed.  */
+class GimpleAccesser : public GimpleWalker
+{
+public:
+  GimpleAccesser ()
+  {};
+
+  /* Print final results.  */
+  void print_accesses ();
+
+  /* Get final results.  */
+  record_field_map_t get_map ();
+
+private:
+  /* Navigate expressions in gimple statements.  */
+  ExprAccessor exprAccessor;
+
+  /* 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<const_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/testsuite/gcc.dg/ipa/ipa-access-counter-00-simple-read-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-00-simple-read-0.c
new file mode 100644
index 00000000000..89e658ec73d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-00-simple-read-0.c
@@ -0,0 +1,22 @@
+/* { dg-do link } */
+/* { dg-options  "-fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis -fprint-access-analysis " } */
+
+#include <stdio.h>
+
+struct astruct_s
+{
+  _Bool a;
+  _Bool b;
+  _Bool c;
+};
+struct astruct_s astruct;
+
+int
+main ()
+{
+  printf ("%d\n", astruct.a);
+  printf ("%d\n", astruct.a);
+}
+
+// This means a read.
+/* { dg-final { scan-wpa-ipa-dump "astruct_s.a = 0x0001" 
"type-escape-analysis" } } */
diff --git 
a/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-01-simple-write-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-01-simple-write-0.c
new file mode 100644
index 00000000000..2ec0cf11049
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-01-simple-write-0.c
@@ -0,0 +1,22 @@
+/* { dg-do link } */
+/* { dg-options  "-fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis -fprint-access-analysis " } */
+
+#include <stdio.h>
+
+struct astruct_s
+{
+  _Bool a;
+  _Bool b;
+  _Bool c;
+};
+struct astruct_s astruct;
+
+int
+main ()
+{
+  astruct.a++;
+  astruct.a = 3;
+}
+
+// This means that this is only a write and not a read.
+/* { dg-final { scan-wpa-ipa-dump "astruct_s.a = 0x0003" 
"type-escape-analysis" } } */
diff --git 
a/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-02-pointer-read-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-02-pointer-read-0.c
new file mode 100644
index 00000000000..b2ba8963b1e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-02-pointer-read-0.c
@@ -0,0 +1,22 @@
+/* { dg-do link } */
+/* { dg-options  "-fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis -fprint-access-analysis " } */
+
+#include <stdio.h>
+
+struct astruct_s
+{
+  _Bool a;
+  _Bool b;
+  _Bool c;
+};
+struct astruct_s *astruct = NULL;
+
+int
+main ()
+{
+  printf ("%d\n", astruct->a);
+  printf ("%d\n", astruct->a);
+}
+
+// So, even if we have a pointer COMPONENT_REF counter still works...
+/* { dg-final { scan-wpa-ipa-dump "astruct_s.a = 0x0001" 
"type-escape-analysis" } } */
diff --git 
a/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-03-pointer-write-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-03-pointer-write-0.c
new file mode 100644
index 00000000000..c8a966f45e9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-03-pointer-write-0.c
@@ -0,0 +1,22 @@
+/* { dg-do link } */
+/* { dg-options  "-fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis -fprint-access-analysis " } */
+
+#include <stdio.h>
+
+struct astruct_s
+{
+  _Bool a;
+  _Bool b;
+  _Bool c;
+};
+struct astruct_s *astruct;
+
+int
+main ()
+{
+  astruct->a++;
+  astruct->a = 3;
+}
+
+// This says that only writes are happening even if astruct is a pointer
+/* { dg-final { scan-wpa-ipa-dump "astruct_s.a = 0x0003" 
"type-escape-analysis" } } */
diff --git 
a/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-04-gimple-cond-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-04-gimple-cond-0.c
new file mode 100644
index 00000000000..799457794d7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-04-gimple-cond-0.c
@@ -0,0 +1,24 @@
+/* { dg-do link } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis -fprint-access-analysis " } */
+
+#include <stdio.h>
+
+struct astruct_s
+{
+  _Bool a;
+  _Bool b;
+  _Bool c;
+};
+struct astruct_s astruct;
+
+int
+main ()
+{
+  if (astruct.a)
+    {
+      puts ("hello world");
+    }
+}
+
+// This says that astruct_s.a is read in a conditional
+/* { dg-final { scan-wpa-ipa-dump "astruct_s.a = 0x0001" 
"type-escape-analysis" } } */
diff --git 
a/gcc/testsuite/gcc.dg/ipa/ipa-ea-00-collect-global-record-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-ea-00-collect-global-record-0.c
new file mode 100644
index 00000000000..e4e62d4f127
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-ea-00-collect-global-record-0.c
@@ -0,0 +1,20 @@
+/* { dg-do link } */
+/* { dg-options  "-fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis -fprint-escape-analysis" } */
+
+struct astruct_s
+{
+  _Bool a;
+  _Bool b;
+  _Bool c;
+};
+struct astruct_s astruct;
+
+int
+main ()
+{
+  astruct.a = 0;
+}
+
+// Please note that braces and semicollons are replaced with dots in order
+// to parse correctly
+/* { dg-final { scan-ipa-dump "collected:  record astruct_s 
.boolean_type a.boolean_type b.boolean_type c.." "type-escape-analysis" 
} } */
diff --git 
a/gcc/testsuite/gcc.dg/ipa/ipa-ea-01-collect-global-pointers-to-record-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-ea-01-collect-global-pointers-to-record-0.c
new file mode 100644
index 00000000000..692daf9dc93
--- /dev/null
+++ 
b/gcc/testsuite/gcc.dg/ipa/ipa-ea-01-collect-global-pointers-to-record-0.c
@@ -0,0 +1,23 @@
+/* { dg-do link } */
+/* { dg-options  "-fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis -fprint-escape-analysis" } */
+
+#include <stddef.h>
+
+struct astruct_s
+{
+  _Bool a;
+  _Bool b;
+  _Bool c;
+};
+struct astruct_s *astruct;
+
+int
+main ()
+{
+  astruct = NULL;
+}
+
+// This is for the structure
+/* { dg-final { scan-ipa-dump "collected:  record astruct_s 
.boolean_type a.boolean_type b.boolean_type c.." "type-escape-analysis" 
} } */
+// This one has an extra dot to mark the * for the pointer
+/* { dg-final { scan-ipa-dump "collected:  record astruct_s 
.boolean_type a.boolean_type b.boolean_type c..." "type-escape-analysis" 
} } */
diff --git 
a/gcc/testsuite/gcc.dg/ipa/ipa-ea-02-collect-global-array-to-record-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-ea-02-collect-global-array-to-record-0.c
new file mode 100644
index 00000000000..0f9b3438d3d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-ea-02-collect-global-array-to-record-0.c
@@ -0,0 +1,23 @@
+/* { dg-do link } */
+/* { dg-options  "-fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis -fprint-escape-analysis" } */
+
+#include <stddef.h>
+
+struct astruct_s
+{
+  _Bool a;
+  _Bool b;
+  _Bool c;
+};
+struct astruct_s astruct[2];
+
+int
+main ()
+{
+  struct astruct_s another = astruct[0];
+}
+
+// This one is for the structure
+/* { dg-final { scan-ipa-dump "collected:  record astruct_s 
.boolean_type a.boolean_type b.boolean_type c.." "type-escape-analysis" 
} } */
+// This one is for the array. That's why it has two dots at the end. 
They correspond to []
+/* { dg-final { scan-ipa-dump "collected:  record astruct_s 
.boolean_type a.boolean_type b.boolean_type c...." 
"type-escape-analysis" } } */
diff --git 
a/gcc/testsuite/gcc.dg/ipa/ipa-ea-03-collect-nested-record-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-ea-03-collect-nested-record-0.c
new file mode 100644
index 00000000000..efba2e5b33c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-ea-03-collect-nested-record-0.c
@@ -0,0 +1,26 @@
+/* { dg-do link } */
+/* { dg-options  "-fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis -fprint-escape-analysis" } */
+
+#include <stddef.h>
+
+struct astruct_s
+{
+  _Bool a;
+  _Bool b;
+  _Bool c;
+};
+struct outer_struct
+{
+  _Bool d;
+  struct astruct_s a;
+};
+struct outer_struct bstruct;
+
+int
+main ()
+{
+  bstruct.d = 0;
+}
+
+// We only care about collecting the inner struct for this test
+/* { dg-final { scan-ipa-dump "collected:  record astruct_s 
.boolean_type a.boolean_type b.boolean_type c.." "type-escape-analysis" 
} } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-ea-04-collect-parameters-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-ea-04-collect-parameters-0.c
new file mode 100644
index 00000000000..d646c8599e8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-ea-04-collect-parameters-0.c
@@ -0,0 +1,40 @@
+/* { dg-do link } */
+/* { dg-options  "-fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis -fprint-escape-analysis" } */
+
+#include <stddef.h>
+
+struct astruct_s
+{
+  _Bool a;
+  _Bool b;
+  _Bool c;
+};
+
+void
+record_parameter (struct astruct_s a)
+{}
+void
+pointer_parameter (struct astruct_s *a)
+{}
+void
+array_parameter (struct astruct_s a[])
+{}
+
+int
+main ()
+{}
+
+// We have a complete type, probably from record_parameter
+/* { dg-final { scan-wpa-ipa-dump "collected:  record astruct_s 
.boolean_type a.boolean_type b.boolean_type c.." "type-escape-analysis" 
} } */
+// Now we have an incomplete struct
+/* { dg-final { scan-wpa-ipa-dump "collected:  record astruct_s .." 
"type-escape-analysis" } } */
+// This is the pointer...
+/* { dg-final { scan-wpa-ipa-dump "collected:  record astruct_s ..." 
"type-escape-analysis" } } */
+// We are missing the array parameter
+// But it seems that the array parameter is passed as a pointer, which 
makes
+// sense... array_parameter (struct astruct_s * a)
+// {
+//   <bb 2> :
+//   return;
+//
+// }
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-ea-05-global-escapes-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-ea-05-global-escapes-0.c
new file mode 100644
index 00000000000..25f6761978b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-ea-05-global-escapes-0.c
@@ -0,0 +1,37 @@
+/* { dg-do link } */
+/* { dg-options "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis -fprint-cast-analysis" } */
+/* { dg-require-effective-target lto } */
+
+#include <stddef.h>
+
+struct astruct_s
+{
+  _Bool a;
+  _Bool b;
+  _Bool c;
+};
+__attribute__ ((
+  externally_visible)) struct astruct_s astruct; // This should escape
+struct bstruct_s
+{
+  _Bool a;
+  _Bool b;
+  _Bool c;
+};
+struct bstruct_s bstruct; // This should not escape
+
+int
+main ()
+{
+  astruct.a = 0;
+  bstruct.b = 0;
+}
+
+/* { dg-final { scan-wpa-ipa-dump "collected:  record astruct_s 
.boolean_type a;boolean_type b;boolean_type c;." "type-escape-analysis" 
} } */
+/* { dg-final { scan-wpa-ipa-dump "collected:  record bstruct_s 
.boolean_type a;boolean_type b;boolean_type c;." "type-escape-analysis" 
} } */
+// Do we find the externally visible struct?
+// This says that record astruct_s is escaping because the reason g 
(global is
+// visible) is set to true...
+/* { dg-final { scan-wpa-ipa-dump " record astruct_s .boolean_type 
a.boolean_type b.boolean_type c.. reason: e=1 g=1 p=0 r=0 c=0 v=0 u=0 
i=0" "type-escape-analysis" } } */
+// This says that record bstruct_s is not escaping
+/* { dg-final { scan-wpa-ipa-dump " record bstruct_s .boolean_type 
a.boolean_type b.boolean_type c.. reason: e=0 g=0 p=0 r=0 c=0 v=0 u=0 
i=0" "type-escape-analysis" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-ea-06-global-type-escapes-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-ea-06-global-type-escapes-0.c
new file mode 100644
index 00000000000..9d6728d6b4d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-ea-06-global-type-escapes-0.c
@@ -0,0 +1,42 @@
+/* { dg-do link } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis -fprint-cast-analysis" } */
+
+#include <stddef.h>
+
+struct astruct_s
+{
+  _Bool a;
+  _Bool b;
+  _Bool c;
+};
+__attribute__ ((
+  externally_visible)) struct astruct_s astruct; // This should escape
+struct bstruct_s
+{
+  _Bool a;
+  _Bool b;
+  _Bool c;
+};
+struct bstruct_s bstruct; // This should not escape
+
+int
+main ()
+{
+  astruct.a = 0;
+  bstruct.b = 0;
+}
+
+// This test is pretty much the same as the previous one.
+// The reason for this is because initially the previous
+// test tested the escaping of variables and this one of
+// types. Since, we are now not checking variables escaping
+// these two tests have merged.
+
+/* { dg-final { scan-wpa-ipa-dump "collected:  record astruct_s 
.boolean_type a;boolean_type b;boolean_type c;." "type-escape-analysis" 
} } */
+/* { dg-final { scan-wpa-ipa-dump "collected:  record bstruct_s 
.boolean_type a;boolean_type b;boolean_type c;." "type-escape-analysis" 
} } */
+// Do we find the externally visible struct?
+// This says that record astruct_s is escaping because the reason g 
(global is
+// visible) is set to true...
+/* { dg-final { scan-wpa-ipa-dump " record astruct_s .boolean_type 
a.boolean_type b.boolean_type c.. reason: e=1 g=1 p=0 r=0 c=0 v=0 u=0 
i=0" "type-escape-analysis" } } */
+// This says that record bstruct_s is not escaping
+/* { dg-final { scan-wpa-ipa-dump " record bstruct_s .boolean_type 
a.boolean_type b.boolean_type c.. reason: e=0 g=0 p=0 r=0 c=0 v=0 u=0 
i=0" "type-escape-analysis" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-ea-08-parameter-escapes-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-ea-08-parameter-escapes-0.c
new file mode 100644
index 00000000000..c4e8c78cd5f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-ea-08-parameter-escapes-0.c
@@ -0,0 +1,37 @@
+/* { dg-do link } */
+/* { dg-options "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis -fprint-cast-analysis" } */
+/* { dg-require-effective-target lto } */
+
+#include <stddef.h>
+
+struct astruct_s
+{
+  _Bool a;
+  _Bool b;
+  _Bool c;
+};
+struct astruct_s astruct; // This should not escape
+struct bstruct_s
+{
+  _Bool a;
+  _Bool b;
+  _Bool c;
+};
+struct bstruct_s bstruct; // This should not escape
+
+__attribute__ ((externally_visible)) void
+escaping (struct astruct_s cstruct)
+{}
+void
+non_escaping (struct bstruct_s dstruct)
+{}
+
+int
+main ()
+{
+  escaping (astruct);
+  non_escaping (bstruct);
+}
+
+/* { dg-final { scan-wpa-ipa-dump " record astruct_s .boolean_type 
a;boolean_type b;boolean_type c;. reason: e=1 g=0 p=1 r=0 c=0 v=0 u=0 
i=0" "type-escape-analysis" } } */
+/* { dg-final { scan-wpa-ipa-dump " record bstruct_s .boolean_type 
a;boolean_type b;boolean_type c;. reason: e=0 g=0 p=0 r=0 c=0 v=0 u=0 
i=0" "type-escape-analysis" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-ea-10-return-type-escapes-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-ea-10-return-type-escapes-0.c
new file mode 100644
index 00000000000..55879c43719
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-ea-10-return-type-escapes-0.c
@@ -0,0 +1,42 @@
+/* { dg-do link } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis -fprint-cast-analysis" } */
+
+#include <stddef.h>
+
+struct astruct_s
+{
+  _Bool a;
+  _Bool b;
+  _Bool c;
+};
+struct astruct_s astruct; // This should not escape
+struct bstruct_s
+{
+  _Bool a;
+  _Bool b;
+  _Bool c;
+};
+struct bstruct_s bstruct; // This should not escape
+
+// This will make astruct_s escape
+struct astruct_s __attribute__ ((externally_visible)) escaping ()
+{
+  struct astruct_s a;
+  return a;
+}
+struct bstruct_s
+non_escaping ()
+{}
+
+int
+main ()
+{
+  astruct = escaping ();
+  bstruct = non_escaping ();
+}
+
+// This says that astruct_s escapes because it is returning from an 
externally
+// visible function
+/* { dg-final { scan-wpa-ipa-dump " record astruct_s .boolean_type 
a;boolean_type b;boolean_type c;. reason: e=1 g=0 p=0 r=1 c=0 v=0 u=0 
i=0" "type-escape-analysis" } } */
+// This says that bstruct_s does not escape
+/* { dg-final { scan-wpa-ipa-dump " record bstruct_s .boolean_type 
a;boolean_type b;boolean_type c;. reason: e=0 g=0 p=0 r=0 c=0 v=0 u=0 
i=0" "type-escape-analysis" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-ea-11-cast-to-void-ptr-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-ea-11-cast-to-void-ptr-0.c
new file mode 100644
index 00000000000..e4293d93bf9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-ea-11-cast-to-void-ptr-0.c
@@ -0,0 +1,44 @@
+/* { dg-do link } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis -fprint-cast-analysis" } */
+
+#include <stddef.h>
+
+struct astruct_s
+{
+  _Bool a;
+  _Bool b;
+  _Bool c;
+};
+struct bstruct_s
+{
+  _Bool a;
+  _Bool b;
+  _Bool c;
+  _Bool d;
+};
+
+struct bstruct_s *
+casting_to_void (struct astruct_s *s)
+{
+  return (struct bstruct_s *) (s);
+}
+
+int
+main ()
+{
+  struct astruct_s astruct;
+  struct bstruct_s bstruct;
+  casting_to_void (&astruct);
+}
+
+// The type
+/* { dg-final { scan-wpa-ipa-dump " record bstruct_s .boolean_type 
a;boolean_type b;boolean_type c;boolean_type d;. reason: e=1 g=0 p=0 r=0 
c=1 v=0 u=0 i=0" "type-escape-analysis" } } */
+/* { dg-final { scan-wpa-ipa-dump " record astruct_s .boolean_type 
a;boolean_type b;boolean_type c;. reason: e=1 g=0 p=0 r=0 c=1 v=0 u=0 
i=0" "type-escape-analysis" } } */
+// The pointer
+/* { dg-final { scan-wpa-ipa-dump " record bstruct_s .boolean_type 
a;boolean_type b;boolean_type c;boolean_type d;.. reason: e=1 g=0 p=0 
r=0 c=1 v=0 u=0 i=0" "type-escape-analysis" } } */
+/* { dg-final { scan-wpa-ipa-dump " record astruct_s {boolean_type 
a;boolean_type b;boolean_type c;}* reason: e=1 g=0 p=0 r=0 c=1 v=0 u=0 
i=0" "type-escape-analysis" } } */
+
+// But there are incomplete types... should does be marked as escaping 
as well
+// here? No, because at the moment, how we compute it is with the fixed 
point
+// and at that moment, we get rid of reasons. So, at the moment, it is
+// sufficient to say that only a fraction of equivalent types escape.
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-ea-12-cast-to-void-ptr-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-ea-12-cast-to-void-ptr-0.c
new file mode 100644
index 00000000000..3d2c0c342fc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-ea-12-cast-to-void-ptr-0.c
@@ -0,0 +1,38 @@
+/* { dg-do link } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis -fprint-cast-analysis" } */
+
+#include <stddef.h>
+
+struct astruct_s
+{
+  _Bool a;
+  _Bool b;
+  _Bool c;
+};
+struct astruct_s astruct; // This should not escape
+struct bstruct_s
+{
+  _Bool a;
+  _Bool b;
+  _Bool c;
+};
+struct bstruct_s bstruct; // This should not escape
+
+void
+casting_to_void (struct astruct_s *s)
+{
+  void *nullify_non_escape = s;
+}
+
+int
+main ()
+{
+  astruct.a = 0;
+  bstruct.b = 0;
+}
+
+/* { dg-final { scan-wpa-ipa-dump "void_type. reason: e=1 g=0 p=0 r=0 
c=1 v=0 u=0 i=0" "type-escape-analysis" } } */
+// base type
+/* { dg-final { scan-wpa-ipa-dump " record astruct_s .boolean_type 
a;boolean_type b;boolean_type c;. reason: e=1 g=0 p=0 r=0 c=1 v=0 u=0" 
"type-escape-analysis" } } */
+// pointer
+/* { dg-final { scan-wpa-ipa-dump " record astruct_s .boolean_type 
a;boolean_type b;boolean_type c;.. reason: e=1 g=0 p=0 r=0 c=1 v=0 u=0" 
"type-escape-analysis" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-ea-13-calling-printf-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-ea-13-calling-printf-0.c
new file mode 100644
index 00000000000..3821eb9816e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-ea-13-calling-printf-0.c
@@ -0,0 +1,27 @@
+/* { dg-do link } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis -fprint-cast-analysis" } */
+
+#include <stddef.h>
+#include <stdio.h>
+
+int
+main (int argc, char **argv)
+{
+  char *filename = "helloworld.txt";
+  FILE *f = fopen (filename, "r");
+  fclose (f);
+}
+
+// This is the incomplete type p=0 because it is memoized and it is an
+// optimization. However, I will also match a 1
+/* { dg-final { scan-wpa-ipa-dump " record _IO_FILE .. reason: e=1 g=0 
p=. r=1 c=0 v=0 u=0 i=." "type-escape-analysis" } } */
+/* { dg-final { scan-wpa-ipa-dump " record _IO_FILE ... reason: e=1 g=0 
p=. r=1 c=0 v=0 u=0 i=." "type-escape-analysis" } } */
+/* { dg-final { scan-wpa-ipa-dump " record _IO_wide_data .. reason: e=1 
g=0 p=. r=1 c=0 v=0 u=0 i=." "type-escape-analysis" } } */
+/* { dg-final { scan-wpa-ipa-dump " record _IO_wide_data ... reason: 
e=1 g=0 p=. r=1 c=0 v=0 u=0 i=." "type-escape-analysis" } } */
+/* { dg-final { scan-wpa-ipa-dump " record _IO_codecvt .. reason: e=1 
g=0 p=. r=1 c=0 v=0 u=0 i=." "type-escape-analysis" } } */
+/* { dg-final { scan-wpa-ipa-dump " record _IO_codecvt ... reason: e=1 
g=0 p=. r=1 c=0 v=0 u=0 i=." "type-escape-analysis" } } */
+/* { dg-final { scan-wpa-ipa-dump "void_type. reason: e=1 g=0 p=. r=1 
c=0 v=0 u=0 i=." "type-escape-analysis" } } */
+/* { dg-final { scan-wpa-ipa-dump " record _IO_marker .. reason: e=1 
g=0 p=. r=1 c=0 v=0 u=0 i=." "type-escape-analysis" } } */
+/* { dg-final { scan-wpa-ipa-dump " record _IO_marker ... reason: e=1 
g=0 p=. r=1 c=0 v=0 u=0 i=." "type-escape-analysis" } } */
+// This is the complete type... but I have condensed it to match .*
+/* { dg-final { scan-wpa-ipa-dump "  record FILE .* reason: e=1 g=0 p=. 
r=1 c=0 v=0 u=0 i=." "type-escape-analysis" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-ea-14-volatile-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-ea-14-volatile-0.c
new file mode 100644
index 00000000000..4607b8b068d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-ea-14-volatile-0.c
@@ -0,0 +1,20 @@
+/* { dg-do link } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis -fprint-cast-analysis" } */
+
+#include <stddef.h>
+#include <stdio.h>
+
+int
+main (int argc, char **argv)
+{
+  struct astruct_s
+  {
+    _Bool a;
+    _Bool b;
+    _Bool c;
+  };
+  volatile struct astruct_s astruct;
+}
+
+// This says that astruct_s has a volatile
+/* { dg-final { scan-wpa-ipa-dump " record astruct_s .boolean_type 
a.boolean_type b.boolean_type c.. reason: e=1 g=0 p=0 r=0 c=0 v=1 u=0 
i=0" "type-escape-analysis" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-ea-15-union-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-ea-15-union-0.c
new file mode 100644
index 00000000000..e998ec8bfcb
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-ea-15-union-0.c
@@ -0,0 +1,25 @@
+/* { dg-do link } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis -fprint-cast-analysis" } */
+
+#include <stddef.h>
+#include <stdio.h>
+
+int
+main (int argc, char **argv)
+{
+  struct astruct_s
+  {
+    _Bool a;
+    _Bool b;
+    _Bool c;
+  };
+  union outer
+  {
+    struct astruct_s a;
+    double b;
+  };
+  union outer an_outer;
+}
+
+// This says that astruct_s is inside a union
+/* { dg-final { scan-wpa-ipa-dump " record astruct_s {boolean_type 
a;boolean_type b;boolean_type c;} reason: e=1 g=0 p=0 r=0 c=0 v=0 u=1 
i=0" "type-escape-analysis" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-ea-16-parameter-cast-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-ea-16-parameter-cast-0.c
new file mode 100644
index 00000000000..c2ac3e3eaf3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-ea-16-parameter-cast-0.c
@@ -0,0 +1,33 @@
+/* { dg-do link } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis -fprint-cast-analysis 
-Wno-incompatible-pointer-types" } */
+
+#include <stddef.h>
+#include <stdio.h>
+
+struct astruct_s
+{
+  _Bool a;
+  _Bool b;
+  _Bool c;
+};
+struct bstruct_s
+{
+  _Bool a;
+  _Bool b;
+  _Bool c;
+};
+void
+foo (struct bstruct_s *s){};
+
+int
+main (int argc, char **argv)
+{
+  struct astruct_s astruct;
+  foo (&astruct);
+}
+
+// This says that astruct_s is casted
+/* { dg-final { scan-wpa-ipa-dump " record astruct_s .boolean_type 
a;boolean_type b;boolean_type c;. reason: e=1 g=0 p=0 r=0 c=1 v=0 u=0 i=0"
+"type-escape-analysis" } } */
+// This says that the pointer is casted
+/* { dg-final { scan-wpa-ipa-dump " record astruct_s .boolean_type 
a;boolean_type b;boolean_type c;.. reason: e=1 g=0 p=0 r=0 c=1 v=0 u=0 
i=0" "type-escape-analysis" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-ea-17-malloc-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-ea-17-malloc-0.c
new file mode 100644
index 00000000000..6579b1926fa
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-ea-17-malloc-0.c
@@ -0,0 +1,24 @@
+/* { dg-do link } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis -fprint-cast-analysis 
-Wno-incompatible-pointer-types" } */
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+struct astruct_s
+{
+  _Bool a;
+  _Bool b;
+  _Bool c;
+};
+
+int
+main (int argc, char **argv)
+{
+  struct astruct_s *a = malloc (sizeof (struct astruct_s));
+}
+
+// This says that astruct_s is not casted
+/* { dg-final { scan-wpa-ipa-dump " record astruct_s .boolean_type 
a;boolean_type b;boolean_type c;. reason: e=0 g=0 p=0 r=0 c=0 v=0 u=0 
i=0" "type-escape-analysis" } } */
+/* { dg-final { scan-wpa-ipa-dump " record astruct_s .boolean_type 
a;boolean_type b;boolean_type c;.. reason: e=0 g=0 p=0 r=0 c=0 v=0 u=0 i=0"
+"type-escape-analysis" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-03-new-type-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-03-new-type-0.c
new file mode 100644
index 00000000000..f3d203759e4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-03-new-type-0.c
@@ -0,0 +1,21 @@
+/* { dg-do link } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis -fprint-access-analysis " } */
+
+#include <stdio.h>
+
+struct astruct_s
+{
+  _Bool a;
+  _Bool b;
+  _Bool c;
+};
+struct astruct_s astruct;
+
+int
+main ()
+{
+  printf ("%d\n", astruct.a);
+  printf ("%d\n", astruct.c);
+}
+
+/* { dg-final { scan-ipa-dump " record astruct_s .boolean_type 
a;boolean_type b;boolean_type c;. ..  record astruct_s .boolean_type 
a;boolean_type c;." "type-escape-analysis" } } */
diff --git 
a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-04-heterogeneous-struct-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-04-heterogeneous-struct-0.c
new file mode 100644
index 00000000000..40133126bb1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-04-heterogeneous-struct-0.c
@@ -0,0 +1,21 @@
+/* { dg-do link } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis -fprint-access-analysis " } */
+
+#include <stdio.h>
+
+struct astruct_s
+{
+  float a;
+  _Bool b;
+  int c;
+};
+struct astruct_s astruct;
+
+int
+main ()
+{
+  printf ("%d\n", astruct.a);
+  printf ("%d\n", astruct.c);
+}
+
+/* { dg-final { scan-ipa-dump " record astruct_s .real_type 
a.boolean_type b.integer_type c.. ..  record astruct_s .real_type 
a.integer_type c.." "type-escape-analysis" } } */
diff --git 
a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-04-layout-compile-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-04-layout-compile-0.c
new file mode 100644
index 00000000000..0424f4cb6ea
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-04-layout-compile-0.c
@@ -0,0 +1,21 @@
+/* { dg-do run } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis" } */
+
+#include <stddef.h>
+#include <assert.h>
+
+int
+main (int argc, char **argv)
+{
+  struct astruct_s
+  {
+    int a;
+    int b;
+    int c;
+  };
+  struct astruct_s astruct;
+  int *c = &astruct.c;
+  int *a = &astruct.a;
+  ptrdiff_t d = c - a;
+  assert (d == 1);
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-05-field-reads-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-05-field-reads-0.c
new file mode 100644
index 00000000000..18e8fe0a596
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-05-field-reads-0.c
@@ -0,0 +1,20 @@
+/* { dg-do run } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis " } */
+
+int
+main ()
+{
+  struct astruct_s
+  {
+    _Bool a;
+    _Bool b;
+    _Bool c;
+  };
+  struct astruct_s astruct;
+  _Bool a = astruct.a;
+  _Bool c = astruct.c;
+  return 0;
+}
+
+/* { dg-final { scan-ipa-dump "replacing field a 0 with a 0" 
"type-escape-analysis" } } */
+/* { dg-final { scan-ipa-dump "replacing field c 16 with a 8" 
"type-escape-analysis" } } */
diff --git 
a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-05-nested-struct-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-05-nested-struct-0.c
new file mode 100644
index 00000000000..9e5ebfddc99
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-05-nested-struct-0.c
@@ -0,0 +1,30 @@
+/* { dg-do link } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis -fprint-access-analysis " } */
+
+#include <stdio.h>
+
+struct astruct_s
+{
+  float a;
+  _Bool b;
+  int c;
+};
+struct ostruct_s
+{
+  struct astruct_s a;
+  float b;
+  float c;
+};
+struct ostruct_s ostruct;
+
+int
+main ()
+{
+  printf ("%d\n", ostruct.b);
+  printf ("%d\n", ostruct.c);
+  printf ("%f\n", ostruct.a.a);
+  printf ("%d\n", ostruct.a.c);
+}
+
+/* { dg-final { scan-ipa-dump " record astruct_s .real_type 
a;boolean_type b;integer_type c;. ->  record astruct_s .real_type 
a;integer_type c;." "type-escape-analysis" } } */
+/* { dg-final { scan-ipa-dump " record ostruct_s . record astruct_s 
.real_type a;boolean_type b;integer_type c;. a;real_type b;real_type c;. 
->  record ostruct_s . record astruct_s .real_type a;integer_type c;. 
a;real_type b;real_type c;." "type-escape-analysis" } } */
diff --git 
a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-05-rewrite-local-decl-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-05-rewrite-local-decl-0.c
new file mode 100644
index 00000000000..d383dd8643e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-05-rewrite-local-decl-0.c
@@ -0,0 +1,23 @@
+/* { dg-do run } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis " } */
+
+#include <stdio.h>
+
+int
+main ()
+{
+  struct astruct_s
+  {
+    _Bool a;
+    _Bool b;
+    _Bool c;
+  };
+  struct astruct_s astruct;
+  printf ("%d %d\n", astruct.a, astruct.c);
+  return 0;
+}
+
+// This is different from previous because here we are replacing a local
+// declaration
+/* { dg-final { scan-ipa-dump "replacing field a 0 with a 0" 
"type-escape-analysis" } } */
+/* { dg-final { scan-ipa-dump "replacing field c 16 with c 8" 
"type-escape-analysis" } } */
diff --git 
a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-06-field-writes-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-06-field-writes-0.c
new file mode 100644
index 00000000000..6f064c6902b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-06-field-writes-0.c
@@ -0,0 +1,24 @@
+/* { dg-do run } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis " } */
+
+#include <stdio.h>
+
+int
+main ()
+{
+  struct astruct_s
+  {
+    _Bool a;
+    _Bool b;
+    _Bool c;
+  };
+  struct astruct_s astruct;
+  astruct.c = 0;
+  printf ("%d %d\n", astruct.a, astruct.c);
+  return 0;
+}
+
+/* { dg-final { scan-ipa-dump "replacing field a 0 with a 0" 
"type-escape-analysis" } } */
+// There's two... mmm.. not sure how to convey this here to the test?
+/* { dg-final { scan-ipa-dump "replacing field c 16 with c 8" 
"type-escape-analysis" } } */
+/* { dg-final { scan-ipa-dump "replacing field c 16 with c 8" 
"type-escape-analysis" } } */
diff --git 
a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-06-pointer-struct-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-06-pointer-struct-0.c
new file mode 100644
index 00000000000..4d704fd51cd
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-06-pointer-struct-0.c
@@ -0,0 +1,31 @@
+/* { dg-do link } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis -fprint-access-analysis " } */
+
+#include <stdio.h>
+
+struct astruct_s
+{
+  float a;
+  _Bool b;
+  int c;
+};
+struct ostruct_s
+{
+  struct astruct_s *a;
+  float b;
+  float c;
+};
+struct ostruct_s ostruct;
+
+int
+main ()
+{
+  printf ("%d\n", ostruct.b);
+  printf ("%d\n", ostruct.c);
+  printf ("%f\n", ostruct.a->a);
+  printf ("%d\n", ostruct.a->c);
+}
+
+/* { dg-final { scan-ipa-dump " record astruct_s ... ->  record 
astruct_s ..." "type-escape-analysis" } } */
+/* { dg-final { scan-ipa-dump " record ostruct_s . record astruct_s ... 
a;real_type b;real_type c;. ->  record ostruct_s . record astruct_s ... 
a;real_type b;real_type c;." "type-escape-analysis" } } */
+/* { dg-final { scan-ipa-dump " record astruct_s .real_type 
a;boolean_type b;integer_type c.. ->  record astruct_s .real_type 
a;integer_type c.." "type-escape-analysis" } } */
diff --git 
a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-07-delete-first-field-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-07-delete-first-field-0.c
new file mode 100644
index 00000000000..a6ba015276b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-07-delete-first-field-0.c
@@ -0,0 +1,23 @@
+/* { dg-do run } */
+/* { dg-options  "-w -flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis " } */
+
+#include <assert.h>
+#include <stdio.h>
+
+int
+main ()
+{
+  struct astruct_s
+  {
+    _Bool b;
+    _Bool a;
+    _Bool c;
+    _Bool d;
+  };
+  struct astruct_s astruct;
+
+  printf ("%d %d %d\n", astruct.a, astruct.c, astruct.d);
+  _Bool *a_ptr = &astruct.a;
+  struct astruct_s *s_ptr = &astruct;
+  assert (a_ptr == s_ptr);
+}
diff --git 
a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-08-modify-double-struct-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-08-modify-double-struct-0.c
new file mode 100644
index 00000000000..a2572b37b04
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-08-modify-double-struct-0.c
@@ -0,0 +1,33 @@
+/* { dg-do run } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis " } */
+
+#include <assert.h>
+#include <stdio.h>
+int
+main ()
+{
+  struct inner_s
+  {
+    _Bool a;
+    _Bool b;
+    _Bool c;
+    _Bool d;
+  };
+  struct astruct_s
+  {
+    struct inner_s a;
+    struct inner_s b;
+    struct inner_s c;
+    struct inner_s d;
+  };
+  struct astruct_s astruct;
+  // printf("%d %d %d\n", &astruct.a, &astruct.c, &astruct.d);
+  struct inner_s *a_ptr = &(astruct.a);
+  struct inner_s *c_ptr = &(astruct.c);
+  struct inner_s *d_ptr = &(astruct.d);
+  printf ("%d %d %d %d\n", a_ptr->a, a_ptr->b, a_ptr->c, a_ptr->d);
+  struct inner_s *c_ptr_2 = a_ptr + 1;
+  struct inner_s *a_ptr_2 = d_ptr - 2;
+  assert (c_ptr_2 == c_ptr);
+  assert (a_ptr == a_ptr_2);
+}
diff --git 
a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-09-modify-int-struct-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-09-modify-int-struct-0.c
new file mode 100644
index 00000000000..e5e80860034
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-09-modify-int-struct-0.c
@@ -0,0 +1,22 @@
+/* { dg-do run } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis " } */
+
+#include <assert.h>
+
+int
+main ()
+{
+  struct astruct_s
+  {
+    int a;
+    int b;
+    int c;
+    int d;
+  };
+  struct astruct_s astruct;
+  int *a = &(astruct.a);
+  int *c = &(astruct.c);
+  int *d = &(astruct.d);
+  assert (c - 1 == a);
+  assert (a + 2 == d);
+}
diff --git 
a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-1-prints-structs-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-1-prints-structs-0.c
new file mode 100644
index 00000000000..1f6078e842d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-1-prints-structs-0.c
@@ -0,0 +1,19 @@
+/* { dg-do run } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis" } */
+
+int
+main ()
+{
+  struct astruct_s
+  {
+    _Bool a;
+    _Bool b;
+    _Bool c;
+  };
+  struct astruct_s astruct;
+  return 0;
+}
+
+/* { dg-final { scan-ipa-dump "astruct_s.a may be deleted" 
"type-escape-analysis" } } */
+/* { dg-final { scan-ipa-dump "astruct_s.b may be deleted" 
"type-escape-analysis" } } */
+/* { dg-final { scan-ipa-dump "astruct_s.c may be deleted" 
"type-escape-analysis" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-10-array-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-10-array-0.c
new file mode 100644
index 00000000000..1e84a46cfe2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-10-array-0.c
@@ -0,0 +1,23 @@
+/* { dg-do run } */
+/* { dg-options  " -flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis" } */
+
+#include <assert.h>
+#include <stdio.h>
+
+int
+main ()
+{
+  struct astruct_s
+  {
+    _Bool a;
+    _Bool b;
+    _Bool c;
+  };
+  struct astruct_s a;
+  printf ("%d %d\n", a.a, a.c);
+  struct astruct_s b[2];
+  a = b[0];
+  _Bool *a_ptr = &a.a;
+  _Bool *c_ptr = &a.c;
+  assert (a_ptr + 1 == c_ptr);
+}
diff --git 
a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-11-rewrites-minus-expr-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-11-rewrites-minus-expr-0.c
new file mode 100644
index 00000000000..2501da43b64
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-11-rewrites-minus-expr-0.c
@@ -0,0 +1,22 @@
+/* { dg-do run } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis" } */
+
+#include <assert.h>
+#include <stddef.h>
+
+int
+main ()
+{
+  struct astruct_s
+  {
+    _Bool a;
+    _Bool b;
+    _Bool c;
+  };
+  struct astruct_s astruct;
+  _Bool *c_ptr = &(astruct.c);
+  _Bool *a_ptr = &(astruct.a);
+  ptrdiff_t diff = c_ptr - a_ptr;
+  assert (diff == 1);
+  return 0;
+}
diff --git 
a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-12-delete-last-field-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-12-delete-last-field-0.c
new file mode 100644
index 00000000000..5183e632228
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-12-delete-last-field-0.c
@@ -0,0 +1,23 @@
+/* { dg-do run } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis" } */
+
+#include <assert.h>
+
+int
+main ()
+{
+  struct astruct_s
+  {
+    _Bool a;
+    _Bool c;
+    _Bool b;
+  };
+  struct astruct_s b[2];
+  _Bool *first_of_second = &(b[1].a);
+  _Bool *c_0 = &(b[0].c);
+  _Bool *a_1 = &(b[1].a);
+  _Bool *a_1_from_c_0 = c_0 + 1;
+  _Bool test = a_1_from_c_0 == a_1;
+  char compile_test[test ? 1 : -1];
+  assert (test);
+}
diff --git 
a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-13-modify-size-four-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-13-modify-size-four-0.c
new file mode 100644
index 00000000000..911e9cba242
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-13-modify-size-four-0.c
@@ -0,0 +1,25 @@
+/* { dg-do run } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis" } */
+
+#include <assert.h>
+#include <stddef.h>
+
+int
+main ()
+{
+  struct astruct_s
+  {
+    _Bool a;
+    _Bool b;
+    _Bool c;
+    _Bool d;
+  };
+  struct astruct_s astruct;
+  _Bool *a = &(astruct.a);
+  _Bool *c = &(astruct.c);
+  _Bool *d = &(astruct.d);
+  ptrdiff_t diff_1 = c - a;
+  ptrdiff_t diff_2 = d - a;
+  assert (diff_1 == 1);
+  assert (diff_2 == 2);
+}
diff --git 
a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-14-rewrite-plus-expr-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-14-rewrite-plus-expr-0.c
new file mode 100644
index 00000000000..eb2ce4fc975
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-14-rewrite-plus-expr-0.c
@@ -0,0 +1,25 @@
+/* { dg-do run } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis" } */
+
+#include <assert.h>
+#include <stddef.h>
+
+int
+main ()
+{
+  struct astruct_s
+  {
+    _Bool a;
+    _Bool b;
+    _Bool c;
+  };
+  struct astruct_s astruct;
+  astruct.a = 1;
+  astruct.c = 1;
+  int d = astruct.a + astruct.c;
+  assert (d == 2);
+  _Bool *a = &(astruct.a);
+  _Bool *c = &(astruct.c);
+  assert (a + 1 == c);
+  return 0;
+}
diff --git 
a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-15-rewrite-mult-expr-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-15-rewrite-mult-expr-0.c
new file mode 100644
index 00000000000..1412d503acf
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-15-rewrite-mult-expr-0.c
@@ -0,0 +1,25 @@
+/* { dg-do run } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis" } */
+
+#include <stddef.h>
+#include <assert.h>
+
+int
+main ()
+{
+  struct astruct_s
+  {
+    _Bool a;
+    _Bool b;
+    _Bool c;
+  };
+  struct astruct_s astruct;
+  astruct.a = 1;
+  astruct.c = 1;
+  int d = astruct.a * astruct.c;
+  assert (d == 1);
+  _Bool *a = &(astruct.a);
+  _Bool *c = &(astruct.c);
+  assert (a + 1 == c);
+  return 0;
+}
diff --git 
a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-16-rewrite-field-reads-ptr-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-16-rewrite-field-reads-ptr-0.c
new file mode 100644
index 00000000000..90d6073ada7
--- /dev/null
+++ 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-16-rewrite-field-reads-ptr-0.c
@@ -0,0 +1,24 @@
+/* { dg-do run } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis" } */
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdio.h>
+
+int
+main ()
+{
+  struct astruct_s
+  {
+    _Bool a;
+    _Bool b;
+    _Bool c;
+  };
+  struct astruct_s astruct;
+  struct astruct_s *astruct_p = &astruct;
+  printf ("%d %d\n", astruct_p->a, astruct_p->c);
+  _Bool *a = &(astruct.a);
+  _Bool *c = &(astruct.c);
+  assert (a + 1 == c);
+  return 0;
+}
diff --git 
a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-17-rewrite-field-write-ptr-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-17-rewrite-field-write-ptr-0.c
new file mode 100644
index 00000000000..22dd58f46c5
--- /dev/null
+++ 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-17-rewrite-field-write-ptr-0.c
@@ -0,0 +1,23 @@
+/* { dg-do run } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis" } */
+
+#include <assert.h>
+
+int
+main ()
+{
+  struct astruct_s
+  {
+    _Bool a;
+    _Bool b;
+    _Bool c;
+  };
+  struct astruct_s astruct;
+  struct astruct_s *astruct_p = &astruct;
+  astruct_p->c = 1;
+  _Bool *a = &(astruct.a);
+  _Bool *c_ptr = &(astruct.c);
+  _Bool *c = a + 1;
+  assert (*c == *c_ptr);
+  return 0;
+}
diff --git 
a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-18-field-writes-deref-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-18-field-writes-deref-0.c
new file mode 100644
index 00000000000..d58955521c2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-18-field-writes-deref-0.c
@@ -0,0 +1,26 @@
+/* { dg-do run } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis" } */
+
+#include <assert.h>
+
+int
+main ()
+{
+  struct astruct_s
+  {
+    _Bool a;
+    _Bool b;
+    _Bool c;
+    _Bool d;
+  };
+  struct astruct_s astruct;
+  _Bool *c_ptr = &astruct.c;
+  *c_ptr = 1;
+  _Bool *a_ptr = &astruct.a;
+  _Bool *d_ptr = &astruct.d;
+  a_ptr++;
+  d_ptr--;
+  assert (*a_ptr == 1);
+  assert (*d_ptr == 1);
+  return 0;
+}
diff --git 
a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-19-middle-pointer-equal-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-19-middle-pointer-equal-0.c
new file mode 100644
index 00000000000..d0e477641ca
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-19-middle-pointer-equal-0.c
@@ -0,0 +1,26 @@
+/* { dg-do run } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis" } */
+
+#include <assert.h>
+
+int
+main ()
+{
+  struct astruct_s
+  {
+    _Bool a;
+    _Bool b;
+    _Bool c;
+    _Bool d;
+  };
+  struct astruct_s astruct;
+  _Bool *a = &astruct.a;
+  _Bool *d = &astruct.d;
+  _Bool *c = &astruct.c;
+  _Bool *c_from_a = a + 1;
+  _Bool *c_from_d = d - 1;
+  assert (c == c_from_a);
+  assert (c == c_from_d);
+  assert (c_from_a == c_from_d);
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-2-modifies-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-2-modifies-0.c
new file mode 100644
index 00000000000..14638d9414d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-2-modifies-0.c
@@ -0,0 +1,20 @@
+/* { dg-do run } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis" } */
+
+int
+main ()
+{
+  struct astruct_s
+  {
+    _Bool a;
+    _Bool b;
+    _Bool c;
+  };
+  struct astruct_s astruct;
+  astruct.a = astruct.c;
+  astruct.c = astruct.a;
+  return 0;
+}
+
+/* { dg-final { scan-ipa-dump "astruct_s.b may be deleted"
+ * "type-escape-analysis" } } */
diff --git 
a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-20-array-offset-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-20-array-offset-0.c
new file mode 100644
index 00000000000..21280681b0c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-20-array-offset-0.c
@@ -0,0 +1,24 @@
+/* { dg-do run } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis " } */
+
+#include <assert.h>
+
+int
+main ()
+{
+  struct astruct_s
+  {
+    _Bool a;
+    _Bool b;
+    _Bool c;
+  };
+  struct astruct_s b[2];
+  _Bool *a_0_ptr = &(b[0].a);
+  _Bool *c_0_ptr = &(b[0].c);
+  _Bool *a_1_ptr = &(b[1].a);
+
+  _Bool *c_0_ptr_from_a_0_ptr = a_0_ptr + 1;
+  _Bool *c_0_ptr_from_a_1_ptr = a_1_ptr - 1;
+  assert (c_0_ptr_from_a_0_ptr == c_0_ptr);
+  assert (c_0_ptr_from_a_1_ptr == c_0_ptr);
+}
diff --git 
a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-22-rewrites-addr-expr-read-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-22-rewrites-addr-expr-read-0.c
new file mode 100644
index 00000000000..869d2b622e0
--- /dev/null
+++ 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-22-rewrites-addr-expr-read-0.c
@@ -0,0 +1,23 @@
+/* { dg-do run } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis " } */
+
+#include <assert.h>
+
+int
+main ()
+{
+  struct astruct_s
+  {
+    _Bool a;
+    _Bool b;
+    _Bool c;
+  };
+  struct astruct_s astruct;
+  _Bool *a = &astruct.a;
+  _Bool *c = &astruct.c;
+  _Bool *c_1 = a + 1;
+  _Bool *a_1 = c - 1;
+  assert (c_1 == c);
+  assert (a_1 == a);
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-23-array-cast-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-23-array-cast-0.c
new file mode 100644
index 00000000000..41618e06376
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-23-array-cast-0.c
@@ -0,0 +1,31 @@
+/* { dg-do run } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis " } */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <stdio.h>
+
+int
+main ()
+{
+  struct astruct_s
+  {
+    _Bool a;
+    _Bool b;
+    _Bool c;
+  };
+  struct astruct_s a[2];
+  struct astruct_s *a_0 = &(a[0]);
+  struct astruct_s *a_1 = &(a[1]);
+  struct astruct_s *a_1_from_a_0 = a_0 + 1;
+  printf ("%d %d\n", a_0->a, a_0->c);
+  //    old  new
+  // 0   a    a
+  // 1   b    c
+  // 2   c    a
+  // 3   a    c
+  // 4   b    a
+  // 5   c    c
+  assert (a_1 == a_1_from_a_0);
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-25-array-cast-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-25-array-cast-0.c
new file mode 100644
index 00000000000..bf867b6cd43
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-25-array-cast-0.c
@@ -0,0 +1,31 @@
+/* { dg-do run } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis" } */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stddef.h>
+
+int
+main ()
+{
+  struct astruct_s
+  {
+    _Bool a;
+    _Bool b;
+    _Bool c;
+    _Bool d;
+  };
+  struct astruct_s a[2];
+  struct bstruct_s
+  {
+    _Bool a;
+    _Bool c;
+    _Bool d;
+  };
+
+  struct astruct_s *a_1 = &(a[1]);
+  struct astruct_s *a_0 = a_1 - 1;
+  struct bstruct_s *b_1 = (struct bstruct_s *) a_1;
+  struct bstruct_s *b_0 = b_1 - 1;
+  assert ((struct bstruct_s *) a_0 != b_0);
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-26-array-cast-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-26-array-cast-0.c
new file mode 100644
index 00000000000..ceef8d65f0d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-26-array-cast-0.c
@@ -0,0 +1,24 @@
+/* { dg-do run } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis " } */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stddef.h>
+
+int
+main (int argc, char **argv)
+{
+  struct astruct_s
+  {
+    _Bool a;
+    _Bool b;
+    _Bool c;
+    _Bool d;
+  };
+  struct astruct_s a[2];
+  struct astruct_s *a_0 = &(a[0]);
+  struct astruct_s *a_1 = a_0 + argc;
+  ptrdiff_t d = a_1 - a_0;
+  printf ("%d %d %d\n", a_0->a, a_0->c, a_0->d);
+  printf ("%d\n", d);
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-27-array-cast-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-27-array-cast-0.c
new file mode 100644
index 00000000000..7e3812718f0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-27-array-cast-0.c
@@ -0,0 +1,21 @@
+/* { dg-do run } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis " } */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stddef.h>
+
+int
+main (int argc, char **argv)
+{
+  struct astruct_s
+  {
+    _Bool a;
+    _Bool b;
+    _Bool c;
+    _Bool d;
+  };
+  struct astruct_s a[2][2];
+  struct astruct_s b = a[argc][argc];
+  printf ("%d %d %d\n", b.a, b.c, b.d);
+}
diff --git 
a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-29-heterogeneous-struct.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-29-heterogeneous-struct.c
new file mode 100644
index 00000000000..ee86abde434
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-29-heterogeneous-struct.c
@@ -0,0 +1,22 @@
+/* { dg-do run } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis " } */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stddef.h>
+
+int
+main ()
+{
+  struct astruct_s
+  {
+    int a;
+    _Bool b;
+    int c;
+  };
+  struct astruct_s astruct;
+  int *a = &(astruct.a);
+  int *c = &(astruct.c);
+  ptrdiff_t d = c - a;
+  assert (d == 1);
+}
diff --git 
a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-30-heterogenous-struct-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-30-heterogenous-struct-0.c
new file mode 100644
index 00000000000..611c2250411
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-30-heterogenous-struct-0.c
@@ -0,0 +1,27 @@
+/* { dg-do run } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis " } */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stddef.h>
+
+int
+main ()
+{
+  // unmodified { a = 1, b = 4; c = 5; d = 8; e = 12
+  // modified { a = 1, c = 2; d = 4, e = 8
+  struct astruct_s
+  {
+    _Bool a;
+    int b;
+    _Bool c;
+    int d;
+    _Bool e;
+  };
+  struct astruct_s astruct;
+  _Bool *a = &(astruct.a);
+  printf ("%d %d\n", astruct.c, astruct.d);
+  _Bool *e = &(astruct.e);
+  ptrdiff_t diff = e - a;
+  assert (diff == 8);
+}
diff --git 
a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-31-heterogenous-struct-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-31-heterogenous-struct-0.c
new file mode 100644
index 00000000000..d5807ac51c3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-31-heterogenous-struct-0.c
@@ -0,0 +1,30 @@
+/* { dg-do run } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis " } */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stddef.h>
+
+int
+main ()
+{
+  // unmodified a = 0, d = 5; e = 6; f = 7; b = 8; c = 9
+  // modified a = 0, d = 1, e = 2, f = 3, c = 4;
+  struct astruct_s
+  {
+    _Bool a;
+    _Bool d;
+    _Bool e;
+    _Bool f;
+    _Bool b;
+    int c;
+  };
+  struct astruct_s astruct;
+  struct astruct_s *p = &astruct;
+  printf ("%d %d %d %d %d\n", p->a, p->d, p->e, p->f, p->c);
+  _Bool *a = &(p->a);
+  int *c = &(p->c);
+  ptrdiff_t d = (_Bool *) c - a;
+  printf ("%d\n", d);
+  assert (d == 4);
+}
diff --git 
a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-33-nested-struct-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-33-nested-struct-0.c
new file mode 100644
index 00000000000..9a7ea83f5ff
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-33-nested-struct-0.c
@@ -0,0 +1,39 @@
+/* { dg-do run } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis " } */
+
+#include <assert.h>
+
+int
+main ()
+{
+  struct astruct_s
+  {
+    _Bool _a;
+    _Bool _b;
+    _Bool _c;
+    _Bool _d;
+  };
+  struct outerstruct_s
+  {
+    struct astruct_s a;
+    struct astruct_s b;
+    struct astruct_s c;
+    struct astruct_s d;
+  };
+  struct outerstruct_s outerstruct;
+  struct astruct_s a = outerstruct.a;
+  struct astruct_s b = outerstruct.b;
+  struct astruct_s c = outerstruct.c;
+  struct astruct_s d = outerstruct.d;
+  _Bool _a = a._a;
+  _Bool _c = a._c;
+  _Bool _d = a._d;
+}
+
+/* { dg-final { scan-ipa-dump "replacing field a 0 with a 0" 
"type-escape-analysis" } } */
+/* { dg-final { scan-ipa-dump "replacing field b 32 with b 32" 
"type-escape-analysis" } } */
+/* { dg-final { scan-ipa-dump "replacing field c 64 with c 64" 
"type-escape-analysis" } } */
+/* { dg-final { scan-ipa-dump "replacing field d 96 with d 96" 
"type-escape-analysis" } } */
+/* { dg-final { scan-ipa-dump "replacing field _a 0 with _a 0" 
"type-escape-analysis" } } */
+/* { dg-final { scan-ipa-dump "replacing field _c 16 with _c 8" 
"type-escape-analysis" } } */
+/* { dg-final { scan-ipa-dump "replacing field _d 24 with _d 16" 
"type-escape-analysis" } } */
diff --git 
a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-33-pointer-indirection-level-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-33-pointer-indirection-level-0.c
new file mode 100644
index 00000000000..ce32ed48f24
--- /dev/null
+++ 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-33-pointer-indirection-level-0.c
@@ -0,0 +1,26 @@
+/* { dg-do run } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis " } */
+
+#include <assert.h>
+
+int
+main ()
+{
+  struct astruct_s
+  {
+    _Bool a;
+    _Bool b;
+    _Bool c;
+    _Bool d;
+  };
+  struct astruct_s astruct;
+  struct astruct_s *p0 = &astruct;
+  struct astruct_s **p1 = &p0;
+  _Bool *a_ptr = &(astruct.a);
+  _Bool *c_ptr = &(astruct.c);
+  _Bool *c_ptr_from_1 = a_ptr + 1;
+  _Bool *a_ptr_2 = &((*p1)->a);
+  _Bool *c_ptr_from_2 = a_ptr_2 + 1;
+  assert (c_ptr == c_ptr_from_1);
+  assert (c_ptr == c_ptr_from_2);
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-34-array-cast-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-34-array-cast-0.c
new file mode 100644
index 00000000000..13e7863495f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-34-array-cast-0.c
@@ -0,0 +1,26 @@
+/* { dg-do run } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis " } */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stddef.h>
+
+int
+main (int argc, char **argv)
+{
+  struct astruct_s
+  {
+    _Bool a;
+    _Bool b;
+    _Bool c;
+    _Bool d;
+  };
+  struct astruct_s a[2][2];
+
+  struct astruct_s b = a[argc][argc];
+  printf ("%d %d %d\n", b.a, b.c, b.d);
+}
+
+/* { dg-final { scan-ipa-dump "replacing field a 0 with a 0" 
"type-escape-analysis" } } */
+/* { dg-final { scan-ipa-dump "replacing field c 16 with c 8" 
"type-escape-analysis" } } */
+/* { dg-final { scan-ipa-dump "replacing field d 24 with d 16" 
"type-escape-analysis" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-36-arguments-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-36-arguments-0.c
new file mode 100644
index 00000000000..048560aac8e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-36-arguments-0.c
@@ -0,0 +1,42 @@
+/* { dg-do run } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis " } */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stddef.h>
+
+struct astruct_s
+{
+  _Bool a;
+  _Bool b;
+  _Bool c;
+  _Bool d;
+};
+
+// PASS BY VALUE
+_Bool
+foo (struct astruct_s astruct)
+{
+  _Bool *a = &astruct.a;
+  assert (!*a);
+  _Bool *c = a + 1;
+  assert (*c);
+  _Bool *d = a + 2;
+  assert (*d);
+  return *c;
+}
+
+int
+main (int argc, char **argv)
+{
+  struct astruct_s astruct;
+  astruct.a = 0;
+  astruct.c = argc;
+  astruct.d = 1;
+  printf ("%d %d %d\n", astruct.a, astruct.c, astruct.d);
+  foo (astruct);
+}
+
+/* { dg-final { scan-ipa-dump "replacing field a 0 with a 0" 
"type-escape-analysis" } } */
+/* { dg-final { scan-ipa-dump "replacing field c 16 with c 8" 
"type-escape-analysis" } } */
+/* { dg-final { scan-ipa-dump "replacing field d 24 with d 16" 
"type-escape-analysis" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-37-arguments-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-37-arguments-0.c
new file mode 100644
index 00000000000..638474007d1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-37-arguments-0.c
@@ -0,0 +1,43 @@
+/* { dg-do run } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis " } */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stddef.h>
+
+struct astruct_s
+{
+  _Bool a;
+  _Bool b;
+  _Bool c;
+  _Bool d;
+};
+
+// PASS BY REFERENCE
+_Bool
+foo (struct astruct_s *astruct)
+{
+  assert (astruct);
+  _Bool *a = &(astruct->a);
+  assert (!*a);
+  _Bool *c = a + 1;
+  assert (*c);
+  _Bool *d = a + 2;
+  assert (*d);
+  return *c;
+}
+
+int
+main (int argc, char **argv)
+{
+  struct astruct_s astruct;
+  astruct.a = 0;
+  astruct.c = argc;
+  astruct.d = 1;
+  printf ("%d %d %d\n", astruct.a, astruct.c, astruct.d);
+  foo (&astruct);
+}
+
+/* { dg-final { scan-ipa-dump "replacing field a 0 with a 0" 
"type-escape-analysis" } } */
+/* { dg-final { scan-ipa-dump "replacing field c 16 with c 8" 
"type-escape-analysis" } } */
+/* { dg-final { scan-ipa-dump "replacing field d 24 with d 16" 
"type-escape-analysis" } } */
diff --git 
a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-38-return-values-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-38-return-values-0.c
new file mode 100644
index 00000000000..0235945a1ec
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-38-return-values-0.c
@@ -0,0 +1,39 @@
+/* { dg-do run } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis " } */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stddef.h>
+
+struct astruct_s
+{
+  _Bool a;
+  _Bool b;
+  _Bool c;
+  _Bool d;
+};
+
+// RETURN BY VALUE
+struct astruct_s
+foo (_Bool c)
+{
+  struct astruct_s astruct;
+  astruct.a = 0;
+  astruct.c = c;
+  astruct.d = 1;
+  return astruct;
+}
+
+int
+main (int argc, char **argv)
+{
+  struct astruct_s astruct;
+  astruct = foo (argc);
+  printf ("%d %d %d\n", astruct.a, astruct.c, astruct.d);
+  _Bool *a = &(astruct.a);
+  assert (!*a);
+  _Bool *c = a + 1;
+  assert (*c == argc);
+  _Bool *d = a + 2;
+  assert (*d);
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-39-typedef-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-39-typedef-0.c
new file mode 100644
index 00000000000..cd680066b47
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-39-typedef-0.c
@@ -0,0 +1,21 @@
+/* { dg-do run } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis " } */
+
+#include <stdio.h>
+
+int
+main ()
+{
+  typedef struct astruct_s
+  {
+    _Bool a;
+    _Bool b;
+    _Bool c;
+  } astruct_s;
+  astruct_s astruct;
+  printf ("%d %d", astruct.a, astruct.c);
+  return 0;
+}
+
+/* { dg-final { scan-ipa-dump "replacing field a 0 with a 0" 
"type-escape-analysis" } } */
+/* { dg-final { scan-ipa-dump "replacing field c 16 with c 8" 
"type-escape-analysis" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-40-typedef-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-40-typedef-0.c
new file mode 100644
index 00000000000..01ee28f0f1a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-40-typedef-0.c
@@ -0,0 +1,22 @@
+/* { dg-do run } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis " } */
+
+#include <stdio.h>
+
+int
+main ()
+{
+  struct astruct_s
+  {
+    _Bool a;
+    _Bool b;
+    _Bool c;
+  };
+  typedef struct astruct_s astruct_s;
+  astruct_s astruct;
+  printf ("%d %d", astruct.a, astruct.c);
+  return 0;
+}
+
+/* { dg-final { scan-ipa-dump "replacing field a 0 with a 0" 
"type-escape-analysis" } } */
+/* { dg-final { scan-ipa-dump "replacing field c 16 with c 8" 
"type-escape-analysis" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-41-deref-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-41-deref-0.c
new file mode 100644
index 00000000000..31bf8cd1d21
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-41-deref-0.c
@@ -0,0 +1,30 @@
+/* { dg-do run } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis " } */
+
+#include <stdio.h>
+#include <assert.h>
+#include <stdbool.h>
+
+int
+main ()
+{
+  struct astruct_s
+  {
+    _Bool a;
+    _Bool b;
+    _Bool c;
+  };
+  struct astruct_s astruct;
+  struct astruct_s *t, copy;
+  t = &astruct;
+  t->a = true;
+  t->c = true;
+  copy = *t;
+  printf ("%d %d", copy.a, copy.c);
+  assert (astruct.a == true);
+  assert (astruct.c == true);
+  return 0;
+}
+
+/* { dg-final { scan-ipa-dump "replacing field a 0 with a 0" 
"type-escape-analysis" } } */
+/* { dg-final { scan-ipa-dump "replacing field c 16 with c 8" 
"type-escape-analysis" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-42-mem-ref-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-42-mem-ref-0.c
new file mode 100644
index 00000000000..b7e361bb08d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-42-mem-ref-0.c
@@ -0,0 +1,32 @@
+/* { dg-do link } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis " } */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+typedef struct astruct astruct_t;
+typedef struct astruct *astruct_p;
+
+struct astruct
+{
+  int a;
+  int b;
+  astruct_p one;
+  astruct_p two;
+  int c;
+  int d;
+};
+
+int
+main ()
+{
+  int n = 10;
+  astruct_p *astructs;
+  register astruct_t *astructnew
+    = (astruct_t *) malloc (n * sizeof (astruct_p));
+  astructs = (astruct_p *) malloc (n * n * sizeof (astruct_p));
+  astructs[n - 1][n - 1] = astructnew[0];
+  printf ("%d %d %d %d\n", astructnew->a, astructnew->b, astructnew->c,
+	  astructnew->d);
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-43-args-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-43-args-0.c
new file mode 100644
index 00000000000..a85d8b70d44
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-43-args-0.c
@@ -0,0 +1,39 @@
+/* { dg-do run } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis " } */
+
+#include <stdio.h>
+
+#include <stdlib.h>
+
+struct astruct_s
+{
+  _Bool a;
+  _Bool b;
+  _Bool c;
+};
+struct wrapper_s
+{
+  struct astruct_s *a;
+};
+
+void
+foo (struct wrapper_s *wrapper){};
+
+void
+bar (struct wrapper_s *wrapper)
+{
+  foo (wrapper);
+};
+
+int
+main ()
+{
+  struct wrapper_s a_wrapper;
+  _Bool is_non_null = a_wrapper.a != NULL;
+  printf ("%d %d %d", &a_wrapper.a, is_non_null ? a_wrapper.a->a : 0,
+	  is_non_null ? a_wrapper.a->c : 0);
+  bar (&a_wrapper);
+}
+
+/* { dg-final { scan-ipa-dump "replacing field a 0 with a 0" 
"type-escape-analysis" } } */
+/* { dg-final { scan-ipa-dump "replacing field c 16 with a 8" 
"type-escape-analysis" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-44-cond-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-44-cond-0.c
new file mode 100644
index 00000000000..67c1d8db6eb
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-44-cond-0.c
@@ -0,0 +1,16 @@
+/* { dg-do link } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis " } */
+
+struct a
+{
+  struct b *b;
+} c (struct a *d)
+{
+  while (d)
+    ;
+}
+void
+main ()
+{}
+
+/* { dg-final { scan-ipa-dump "deleting all fields for struct a" 
"type-escape-analysis" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-45-phis-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-45-phis-0.c
new file mode 100644
index 00000000000..cd4fc80d2f0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-45-phis-0.c
@@ -0,0 +1,17 @@
+/* { dg-do link } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis " } */
+
+struct a
+{
+  struct a_inner *b;
+} c (struct a *d, struct a *e)
+{
+  while (e)
+    d = d;
+}
+int
+main ()
+{}
+
+/* { dg-final { scan-ipa-dump "deleting all fields for struct a"
+ * "type-escape-analysis" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-46-static-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-46-static-0.c
new file mode 100644
index 00000000000..636d8c6b5a0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-46-static-0.c
@@ -0,0 +1,23 @@
+/* { dg-do run } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis " } */
+
+#include <assert.h>
+#include <stddef.h>
+
+struct a_s
+{
+  _Bool a;
+  _Bool b;
+  _Bool c;
+};
+
+struct a_s a_t;
+
+int
+main ()
+{
+  _Bool *a = &(a_t.a);
+  _Bool *c = &(a_t.c);
+  ptrdiff_t diff = c - a;
+  assert (diff == 1);
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-47-constructor-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-47-constructor-0.c
new file mode 100644
index 00000000000..52dc67589cc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-47-constructor-0.c
@@ -0,0 +1,27 @@
+/* { dg-do run } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis " } */
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdio.h>
+
+int
+main ()
+{
+  struct astruct_s
+  {
+    _Bool a;
+    _Bool b;
+    _Bool c;
+  };
+  struct astruct_s an_arc;
+  struct another
+  {
+    _Bool a;
+    struct astruct_s d;
+    _Bool c;
+  };
+  struct another an_another = {0, {0, 1}, 1};
+  struct astruct_s a = an_another.d;
+  printf ("%d %d %d %d %d", an_another.a, &a, a.a, a.c, an_another.c);
+}
diff --git 
a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-48-function-ptr-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-48-function-ptr-0.c
new file mode 100644
index 00000000000..405ccab3c34
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-48-function-ptr-0.c
@@ -0,0 +1,44 @@
+/* { dg-do run } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis " } */
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdio.h>
+
+struct astruct_s
+{
+  _Bool a;
+  _Bool b;
+  _Bool c;
+};
+
+_Bool
+returnLast (struct astruct_s astruct)
+{
+  return astruct.c;
+}
+
+_Bool
+returnLast2 (struct astruct_s astruct)
+{
+  _Bool *ptr = &(astruct.a);
+  ptr = ptr + 1;
+  return *ptr;
+}
+
+int
+main (int argc, char **argv)
+{
+  _Bool (*func1) (struct astruct_s);
+  func1 = &returnLast;
+  _Bool (*func2) (struct astruct_s);
+  func2 = &returnLast2;
+  struct astruct_s astruct;
+  astruct.c = argc;
+  printf ("%d %d", astruct.a, astruct.c);
+  // These test means that things remain equal
+  // A.k.a without an optimization.
+  // Why? Because a function pointer can be a
+  // pointer to anything
+  assert (func1 (astruct) != func2 (astruct));
+}
diff --git 
a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-50-field-write-delete-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-50-field-write-delete-0.c
new file mode 100644
index 00000000000..ae1b23c324a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-50-field-write-delete-0.c
@@ -0,0 +1,24 @@
+/* { dg-do run } */
+/* { dg-options  "-flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis " } */
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <stdio.h>
+
+int
+main (int argc, char **argv)
+{
+  struct astruct_s
+  {
+    _Bool a;
+    _Bool delete_me;
+    _Bool c;
+  };
+  struct astruct_s astruct;
+  printf ("%d %d", astruct.a, astruct.c);
+  astruct.delete_me = false;
+  return 0;
+}
+
+/* { dg-final { scan-ipa-dump "deleting field delete_me 8" 
"type-escape-analysis" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-51-creduce-0.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-51-creduce-0.c
new file mode 100644
index 00000000000..1d86ad808be
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-51-creduce-0.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-options  "-flto -flto-partition=none 
-fipa-type-escape-analysis" } */
+
+struct
+{
+} main () {}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-52-creduce-1.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-52-creduce-1.c
new file mode 100644
index 00000000000..0eeda3f82b4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-52-creduce-1.c
@@ -0,0 +1,13 @@
+/* { dg-do run } */
+/* { dg-options  "-w -flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis " } */
+
+#include <stdint.h>
+union a
+{
+  int16_t b
+} c ()
+{
+  union a d;
+  -d.b;
+}
+main () {}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-53-csmith-2.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-53-csmith-2.c
new file mode 100644
index 00000000000..87268497d39
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-53-csmith-2.c
@@ -0,0 +1,6 @@
+/* { dg-do run } */
+/* { dg-options  "-w -flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis " } */
+struct
+{
+} a;
+main () {}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-54-csmith-3.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-54-csmith-3.c
new file mode 100644
index 00000000000..0b4e981deb4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-54-csmith-3.c
@@ -0,0 +1,24 @@
+/* { dg-do run } */
+/* { dg-options  "-w -flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis " } */
+
+#include <stdint.h>
+// TODO: So, our analysis says that we are deleting a field "a".
+// And that the field "a" is contained in struct "b".
+// However, we are doing is_interesting_struct("c") == yes
+// is_interesting_field("a") == yes
+// and so we delete field a from struct c.
+struct
+{
+  uint64_t a
+} b[];
+struct
+{
+  unsigned : 5;
+  unsigned a
+} c;
+d ()
+{
+  uint16_t e = b;
+  int8_t f = c.a;
+}
+main () {}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-55-csmith-4.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-55-csmith-4.c
new file mode 100644
index 00000000000..d4f1d684614
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-55-csmith-4.c
@@ -0,0 +1,9 @@
+/* { dg-do run } */
+/* { dg-options  "-w -flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis " } */
+
+#include <stdint.h>
+union a
+{
+  int8_t b
+} c () { union a d = {4073709551608}; }
+main () {}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-56-csmith-5.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-56-csmith-5.c
new file mode 100644
index 00000000000..b016a3b8ea1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-56-csmith-5.c
@@ -0,0 +1,25 @@
+/* { dg-do run } */
+/* { dg-options  "-w -flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis " } */
+
+#include <stdint.h>
+struct a
+{
+  int8_t b
+};
+struct c
+{
+  struct a d
+} e[];
+
+/* Analysis failed because e[2].d was considered not read
+ * we were only looking at e[2].d.b which is considered read.
+ * So we need to recurse
+ */
+f () { g (e[2].d.b, 0); }
+
+void
+g (int8_t a, int8_t b)
+{
+  a + b;
+}
+main () {}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-57-csmith-6.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-57-csmith-6.c
new file mode 100644
index 00000000000..985975e01d8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-57-csmith-6.c
@@ -0,0 +1,8 @@
+/* { dg-do run } */
+/* { dg-options  "-w -flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis " } */
+
+struct a
+{
+};
+b (struct a c) {}
+main () {}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-58-csmith-7.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-58-csmith-7.c
new file mode 100644
index 00000000000..bd49a606df8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-58-csmith-7.c
@@ -0,0 +1,15 @@
+/* { dg-do run } */
+/* { dg-options  "-w -flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis " } */
+
+#include <stdint.h>
+struct a
+{
+  int32_t b
+} c;
+d ()
+{
+  for (;; c.b = 0)
+    ;
+}
+main () {}
+/* { dg-final { scan-ipa-dump "deleting field b 0" 
"type-escape-analysis" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-59-csmith-8.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-59-csmith-8.c
new file mode 100644
index 00000000000..d8c546e4d32
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-59-csmith-8.c
@@ -0,0 +1,14 @@
+/* { dg-do run } */
+/* { dg-options  "-w -flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis " } */
+
+struct a
+{
+  signed b
+};
+struct
+{
+  struct a b
+} volatile c;
+main () { c.b.b; }
+
+// we will do nothing because volatile
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-60-csmith-9.c 
b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-60-csmith-9.c
new file mode 100644
index 00000000000..64bd2711aad
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-60-csmith-9.c
@@ -0,0 +1,26 @@
+/* { dg-do run } */
+/* { dg-options  "-w -flto -fipa-type-escape-analysis 
-fdump-ipa-type-escape-analysis " } */
+
+#include <stdint.h>
+
+void
+foo (uint64_t a, uint64_t b)
+{
+  a + b;
+}
+
+struct a
+{
+  uint64_t b;
+  uint8_t c
+} d ()
+{
+  // I think the problem here is with the const attribute...
+  const struct a e;
+  foo (0, e.b);
+  return e;
+}
+
+main () {}
+
+/* { dg-final { scan-ipa-dump "a.c may be deleted" 
"type-escape-analysis" } } */
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



More information about the Gcc-patches mailing list