summaryrefslogtreecommitdiff
path: root/0038-DFE-Add-Dead-Field-Elimination-in-Struct-Reorg.patch
diff options
context:
space:
mode:
authorCoprDistGit <infra@openeuler.org>2023-10-17 02:15:03 +0000
committerCoprDistGit <infra@openeuler.org>2023-10-17 02:15:03 +0000
commitcc47ed6ddebfece0584ad7ee706549614d16c0f0 (patch)
tree973a28470803b27c914f813f43d43f8932763ea3 /0038-DFE-Add-Dead-Field-Elimination-in-Struct-Reorg.patch
parent1e2198a988cc8d2ea55ab6ca2a1835e60149ab5c (diff)
automatic import of gccopeneuler22.03_LTS_SP2
Diffstat (limited to '0038-DFE-Add-Dead-Field-Elimination-in-Struct-Reorg.patch')
-rw-r--r--0038-DFE-Add-Dead-Field-Elimination-in-Struct-Reorg.patch902
1 files changed, 902 insertions, 0 deletions
diff --git a/0038-DFE-Add-Dead-Field-Elimination-in-Struct-Reorg.patch b/0038-DFE-Add-Dead-Field-Elimination-in-Struct-Reorg.patch
new file mode 100644
index 0000000..6b913ae
--- /dev/null
+++ b/0038-DFE-Add-Dead-Field-Elimination-in-Struct-Reorg.patch
@@ -0,0 +1,902 @@
+From edd4200e2b3e94d5c124900657b91c22dfe9c557 Mon Sep 17 00:00:00 2001
+From: Mingchuan Wu <wumingchuan1992@foxmail.com>
+Date: Wed, 15 Jun 2022 16:00:25 +0800
+Subject: [PATCH 04/12] [DFE] Add Dead Field Elimination in Struct-Reorg.
+
+We can transform gimple to eliminate fields that are never read
+and remove their redundant stmts.
+Also we adapted the partial escape_cast_another_ptr for struct relayout.
+Add flag -fipa-struct-reorg=3 to enable dead field elimination.
+---
+ gcc/common.opt | 4 +-
+ gcc/ipa-struct-reorg/ipa-struct-reorg.c | 209 ++++++++++++++++--
+ gcc/ipa-struct-reorg/ipa-struct-reorg.h | 9 +-
+ gcc/testsuite/gcc.dg/struct/dfe_DTE_verify.c | 86 +++++++
+ .../gcc.dg/struct/dfe_ele_minus_verify.c | 60 +++++
+ .../gcc.dg/struct/dfe_mem_ref_offset.c | 58 +++++
+ .../struct/dfe_mul_layer_ptr_record_bug.c | 30 +++
+ gcc/testsuite/gcc.dg/struct/dfe_ptr_diff.c | 71 ++++++
+ .../gcc.dg/struct/dfe_ptr_negate_expr.c | 55 +++++
+ gcc/testsuite/gcc.dg/struct/dfe_ptr_ptr.c | 55 +++++
+ gcc/testsuite/gcc.dg/struct/struct-reorg.exp | 21 +-
+ 11 files changed, 639 insertions(+), 19 deletions(-)
+ create mode 100644 gcc/testsuite/gcc.dg/struct/dfe_DTE_verify.c
+ create mode 100644 gcc/testsuite/gcc.dg/struct/dfe_ele_minus_verify.c
+ create mode 100644 gcc/testsuite/gcc.dg/struct/dfe_mem_ref_offset.c
+ create mode 100644 gcc/testsuite/gcc.dg/struct/dfe_mul_layer_ptr_record_bug.c
+ create mode 100644 gcc/testsuite/gcc.dg/struct/dfe_ptr_diff.c
+ create mode 100644 gcc/testsuite/gcc.dg/struct/dfe_ptr_negate_expr.c
+ create mode 100644 gcc/testsuite/gcc.dg/struct/dfe_ptr_ptr.c
+
+diff --git a/gcc/common.opt b/gcc/common.opt
+index 7fc075d35..b5ea3c7a1 100644
+--- a/gcc/common.opt
++++ b/gcc/common.opt
+@@ -1884,8 +1884,8 @@ Common Report Var(flag_ipa_struct_reorg) Init(0) Optimization
+ Perform structure layout optimizations.
+
+ fipa-struct-reorg=
+-Common RejectNegative Joined UInteger Var(struct_layout_optimize_level) Init(0) IntegerRange(0, 2)
+--fipa-struct-reorg=[0,1,2] adding none, struct-reorg, reorder-fields optimizations.
++Common RejectNegative Joined UInteger Var(struct_layout_optimize_level) Init(0) IntegerRange(0, 3)
++-fipa-struct-reorg=[0,1,2,3] adding none, struct-reorg, reorder-fields, dfe optimizations.
+
+ fipa-extend-auto-profile
+ Common Report Var(flag_ipa_extend_auto_profile)
+diff --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.c b/gcc/ipa-struct-reorg/ipa-struct-reorg.c
+index 9214ee74a..2fa560239 100644
+--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.c
++++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.c
+@@ -81,6 +81,7 @@ along with GCC; see the file COPYING3. If not see
+ #include "tree-pretty-print.h"
+ #include "gimple-pretty-print.h"
+ #include "gimple-iterator.h"
++#include "gimple-walk.h"
+ #include "cfg.h"
+ #include "ssa.h"
+ #include "tree-dfa.h"
+@@ -238,11 +239,44 @@ enum srmode
+ STRUCT_LAYOUT_OPTIMIZE
+ };
+
++/* Enum the struct layout optimize level,
++ which should be the same as the option -fstruct-reorg=. */
++
++enum struct_layout_opt_level
++{
++ NONE = 0,
++ STRUCT_REORG,
++ STRUCT_REORDER_FIELDS,
++ DEAD_FIELD_ELIMINATION
++};
++
+ static bool is_result_of_mult (tree arg, tree *num, tree struct_size);
+ bool isptrptr (tree type);
+
+ srmode current_mode;
+
++hash_map<tree, tree> replace_type_map;
++
++/* Return true if one of these types is created by struct-reorg. */
++
++static bool
++is_replace_type (tree type1, tree type2)
++{
++ if (replace_type_map.is_empty ())
++ return false;
++ if (type1 == NULL_TREE || type2 == NULL_TREE)
++ return false;
++ tree *type_value = replace_type_map.get (type1);
++ if (type_value)
++ if (types_compatible_p (*type_value, type2))
++ return true;
++ type_value = replace_type_map.get (type2);
++ if (type_value)
++ if (types_compatible_p (*type_value, type1))
++ return true;
++ return false;
++}
++
+ } // anon namespace
+
+ namespace struct_reorg {
+@@ -318,12 +352,13 @@ srfunction::simple_dump (FILE *file)
+ /* Constructor of FIELD. */
+
+ srfield::srfield (tree field, srtype *base)
+- : offset(int_byte_position (field)),
++ : offset (int_byte_position (field)),
+ fieldtype (TREE_TYPE (field)),
+ fielddecl (field),
+- base(base),
+- type(NULL),
+- clusternum(0)
++ base (base),
++ type (NULL),
++ clusternum (0),
++ field_access (EMPTY_FIELD)
+ {
+ for(int i = 0;i < max_split; i++)
+ newfield[i] = NULL_TREE;
+@@ -362,6 +397,25 @@ srtype::srtype (tree type)
+ }
+ }
+
++/* Check it if all fields in the RECORD_TYPE are referenced. */
++
++bool
++srtype::has_dead_field (void)
++{
++ bool may_dfe = false;
++ srfield *this_field;
++ unsigned i;
++ FOR_EACH_VEC_ELT (fields, i, this_field)
++ {
++ if (!(this_field->field_access & READ_FIELD))
++ {
++ may_dfe = true;
++ break;
++ }
++ }
++ return may_dfe;
++}
++
+ /* Mark the type as escaping type E at statement STMT. */
+
+ void
+@@ -833,6 +887,10 @@ srtype::create_new_type (void)
+ for (unsigned i = 0; i < fields.length (); i++)
+ {
+ srfield *f = fields[i];
++ if (current_mode == STRUCT_LAYOUT_OPTIMIZE
++ && struct_layout_optimize_level >= DEAD_FIELD_ELIMINATION
++ && !(f->field_access & READ_FIELD))
++ continue;
+ f->create_new_fields (newtype, newfields, newlast);
+ }
+
+@@ -854,6 +912,16 @@ srtype::create_new_type (void)
+
+ warn_padded = save_warn_padded;
+
++ if (current_mode == STRUCT_LAYOUT_OPTIMIZE
++ && replace_type_map.get (this->newtype[0]) == NULL)
++ replace_type_map.put (this->newtype[0], this->type);
++ if (dump_file)
++ {
++ if (current_mode == STRUCT_LAYOUT_OPTIMIZE
++ && struct_layout_optimize_level >= DEAD_FIELD_ELIMINATION
++ && has_dead_field ())
++ fprintf (dump_file, "Dead field elimination.\n");
++ }
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Created %d types:\n", maxclusters);
+@@ -1128,12 +1196,12 @@ csrtype::init_type_info (void)
+
+ /* Close enough to pad to improve performance.
+ 33~63 should pad to 64 but 33~48 (first half) are too far away, and
+- 65~127 should pad to 128 but 65~96 (first half) are too far away. */
++ 65~127 should pad to 128 but 65~80 (first half) are too far away. */
+ if (old_size > 48 && old_size < 64)
+ {
+ new_size = 64;
+ }
+- if (old_size > 96 && old_size < 128)
++ if (old_size > 80 && old_size < 128)
+ {
+ new_size = 128;
+ }
+@@ -1272,6 +1340,7 @@ public:
+ bool has_rewritten_type (srfunction*);
+ void maybe_mark_or_record_other_side (tree side, tree other, gimple *stmt);
+ unsigned execute_struct_relayout (void);
++ bool remove_dead_field_stmt (tree lhs);
+ };
+
+ struct ipa_struct_relayout
+@@ -3206,6 +3275,90 @@ ipa_struct_reorg::find_vars (gimple *stmt)
+ }
+ }
+
++/* Update field_access in srfield. */
++
++static void
++update_field_access (tree record, tree field, unsigned access, void *data)
++{
++ srtype *this_srtype = ((ipa_struct_reorg *)data)->find_type (record);
++ if (this_srtype == NULL)
++ return;
++ srfield *this_srfield = this_srtype->find_field (int_byte_position (field));
++ if (this_srfield == NULL)
++ return;
++
++ this_srfield->field_access |= access;
++ if (dump_file && (dump_flags & TDF_DETAILS))
++ {
++ fprintf (dump_file, "record field access %d:", access);
++ print_generic_expr (dump_file, record);
++ fprintf (dump_file, " field:");
++ print_generic_expr (dump_file, field);
++ fprintf (dump_file, "\n");
++ }
++ return;
++}
++
++/* A callback for walk_stmt_load_store_ops to visit store. */
++
++static bool
++find_field_p_store (gimple *, tree node, tree op, void *data)
++{
++ if (TREE_CODE (op) != COMPONENT_REF)
++ return false;
++ tree node_type = TREE_TYPE (node);
++ if (!handled_type (node_type))
++ return false;
++
++ update_field_access (node_type, TREE_OPERAND (op, 1), WRITE_FIELD, data);
++
++ return false;
++}
++
++/* A callback for walk_stmt_load_store_ops to visit load. */
++
++static bool
++find_field_p_load (gimple *, tree node, tree op, void *data)
++{
++ if (TREE_CODE (op) != COMPONENT_REF)
++ return false;
++ tree node_type = TREE_TYPE (node);
++ if (!handled_type (node_type))
++ return false;
++
++ update_field_access (node_type, TREE_OPERAND (op, 1), READ_FIELD, data);
++
++ return false;
++}
++
++/* Determine whether the stmt should be deleted. */
++
++bool
++ipa_struct_reorg::remove_dead_field_stmt (tree lhs)
++{
++ tree base = NULL_TREE;
++ bool indirect = false;
++ srtype *t = NULL;
++ srfield *f = NULL;
++ bool realpart = false;
++ bool imagpart = false;
++ bool address = false;
++ bool escape_from_base = false;
++ if (!get_type_field (lhs, base, indirect, t, f, realpart, imagpart,
++ address, escape_from_base))
++ return false;
++ if (t ==NULL)
++ return false;
++ if (t->newtype[0] == t->type)
++ return false;
++ if (f == NULL)
++ return false;
++ if (f->newfield[0] == NULL
++ && (f->field_access & WRITE_FIELD))
++ return true;
++ return false;
++}
++
+ /* Maybe record access of statement for further analaysis. */
+
+ void
+@@ -3227,6 +3380,13 @@ ipa_struct_reorg::maybe_record_stmt (cgraph_node *node, gimple *stmt)
+ default:
+ break;
+ }
++ if (current_mode == STRUCT_LAYOUT_OPTIMIZE
++ && struct_layout_optimize_level >= DEAD_FIELD_ELIMINATION)
++ {
++ /* Look for loads and stores. */
++ walk_stmt_load_store_ops (stmt, this, find_field_p_load,
++ find_field_p_store);
++ }
+ }
+
+ /* Calculate the multiplier. */
+@@ -3543,8 +3703,11 @@ ipa_struct_reorg::maybe_mark_or_record_other_side (tree side, tree other, gimple
+ }
+ else if (type != d->type)
+ {
+- type->mark_escape (escape_cast_another_ptr, stmt);
+- d->type->mark_escape (escape_cast_another_ptr, stmt);
++ if (!is_replace_type (d->type->type, type->type))
++ {
++ type->mark_escape (escape_cast_another_ptr, stmt);
++ d->type->mark_escape (escape_cast_another_ptr, stmt);
++ }
+ }
+ /* x_1 = y.x_nodes; void *x;
+ Directly mark the structure pointer type assigned
+@@ -4131,8 +4294,9 @@ ipa_struct_reorg::check_type_and_push (tree newdecl, srdecl *decl,
+ }
+ /* If we have a non void* or a decl (which is hard to track),
+ then mark the type as escaping. */
+- if (!VOID_POINTER_P (TREE_TYPE (newdecl))
+- || DECL_P (newdecl))
++ if (replace_type_map.get (type->type) == NULL
++ && (!VOID_POINTER_P (TREE_TYPE (newdecl))
++ || DECL_P (newdecl)))
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+@@ -4142,7 +4306,7 @@ ipa_struct_reorg::check_type_and_push (tree newdecl, srdecl *decl,
+ print_generic_expr (dump_file, TREE_TYPE (newdecl));
+ fprintf (dump_file, "\n");
+ }
+- type->mark_escape (escape_cast_another_ptr, stmt);
++ type->mark_escape (escape_cast_another_ptr, stmt);
+ return;
+ }
+ /* At this point there should only be unkown void* ssa names. */
+@@ -4465,11 +4629,13 @@ ipa_struct_reorg::check_other_side (srdecl *decl, tree other, gimple *stmt, vec<
+
+ return;
+ }
++ if (!is_replace_type (t1->type, type->type))
++ {
++ if (t1)
++ t1->mark_escape (escape_cast_another_ptr, stmt);
+
+- if (t1)
+- t1->mark_escape (escape_cast_another_ptr, stmt);
+-
+- type->mark_escape (escape_cast_another_ptr, stmt);
++ type->mark_escape (escape_cast_another_ptr, stmt);
++ }
+ }
+
+
+@@ -5722,6 +5888,19 @@ bool
+ ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi)
+ {
+ bool remove = false;
++
++ if (current_mode == STRUCT_LAYOUT_OPTIMIZE
++ && struct_layout_optimize_level >= DEAD_FIELD_ELIMINATION
++ && remove_dead_field_stmt (gimple_assign_lhs (stmt)))
++ {
++ if (dump_file && (dump_flags & TDF_DETAILS))
++ {
++ fprintf (dump_file, "\n rewriting statement (remove): \n");
++ print_gimple_stmt (dump_file, stmt, 0);
++ }
++ return true;
++ }
++
+ if (gimple_clobber_p (stmt))
+ {
+ tree lhs = gimple_assign_lhs (stmt);
+diff --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.h b/gcc/ipa-struct-reorg/ipa-struct-reorg.h
+index 54b0dc655..936c0fa6f 100644
+--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.h
++++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.h
+@@ -142,6 +142,7 @@ public:
+
+ bool create_new_type (void);
+ void analyze (void);
++ bool has_dead_field (void);
+ void mark_escape (escape_type, gimple *stmt);
+ bool has_escaped (void)
+ {
+@@ -163,6 +164,12 @@ public:
+ }
+ };
+
++/* Bitflags used for determining if a field
++ is never accessed, read or written. */
++const unsigned EMPTY_FIELD = 0x0u;
++const unsigned READ_FIELD = 0x01u;
++const unsigned WRITE_FIELD = 0x02u;
++
+ struct srfield
+ {
+ unsigned HOST_WIDE_INT offset;
+@@ -174,7 +181,7 @@ struct srfield
+ unsigned clusternum;
+
+ tree newfield[max_split];
+-
++ unsigned field_access; /* FIELD_DECL -> bitflag (use for dfe). */
+ // Constructors
+ srfield (tree field, srtype *base);
+
+diff --git a/gcc/testsuite/gcc.dg/struct/dfe_DTE_verify.c b/gcc/testsuite/gcc.dg/struct/dfe_DTE_verify.c
+new file mode 100644
+index 000000000..4261d2352
+--- /dev/null
++++ b/gcc/testsuite/gcc.dg/struct/dfe_DTE_verify.c
+@@ -0,0 +1,86 @@
++/* { dg-do compile } */
++
++#include <stdio.h>
++#include <stdlib.h>
++
++typedef struct node node_t;
++typedef struct node *node_p;
++
++typedef struct arc arc_t;
++typedef struct arc *arc_p;
++
++typedef struct network
++{
++ arc_p arcs;
++ arc_p sorted_arcs;
++ int x;
++ node_p nodes;
++ node_p stop_nodes;
++} network_t;
++
++struct node
++{
++ int64_t potential;
++ int orientation;
++ node_p child;
++ node_p pred;
++ node_p sibling;
++ node_p sibling_prev;
++ arc_p basic_arc;
++ arc_p firstout;
++ arc_p firstin;
++ arc_p arc_tmp;
++ int64_t flow;
++ int64_t depth;
++ int number;
++ int time;
++};
++
++struct arc
++{
++ int id;
++ int64_t cost;
++ node_p tail;
++ node_p head;
++ short ident;
++ arc_p nextout;
++ arc_p nextin;
++ int64_t flow;
++ int64_t org_cost;
++ network_t* net_add;
++};
++
++
++const int MAX = 100;
++
++/* let it escape_array, "Type is used in an array [not handled yet]". */
++network_t* net[2];
++arc_p stop_arcs = NULL;
++
++int
++main ()
++{
++ net[0] = (network_t*) calloc (1, sizeof(network_t));
++ net[0]->arcs = (arc_p) calloc (MAX, sizeof (arc_t));
++ stop_arcs = (arc_p) calloc (MAX, sizeof (arc_t));
++
++ net[0]->arcs->id = 100;
++
++ for (unsigned i = 0; i < 3; i++)
++ {
++ net[0]->arcs->id = net[0]->arcs->id + 2;
++ stop_arcs->cost = net[0]->arcs->id / 2;
++ stop_arcs->net_add = net[0];
++ printf("stop_arcs->cost = %ld\n", stop_arcs->cost);
++ net[0]->arcs++;
++ stop_arcs++;
++ }
++
++ if( net[1] != 0 && stop_arcs != 0)
++ {
++ return -1;
++ }
++ return 0;
++}
++
++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 2 "struct_layout" } } */
+diff --git a/gcc/testsuite/gcc.dg/struct/dfe_ele_minus_verify.c b/gcc/testsuite/gcc.dg/struct/dfe_ele_minus_verify.c
+new file mode 100644
+index 000000000..42d38c63a
+--- /dev/null
++++ b/gcc/testsuite/gcc.dg/struct/dfe_ele_minus_verify.c
+@@ -0,0 +1,60 @@
++// verify newarc[cmp-1].flow
++/* { dg-do compile } */
++
++#include <stdio.h>
++#include <stdlib.h>
++
++typedef struct node node_t;
++typedef struct node *node_p;
++
++typedef struct arc arc_t;
++typedef struct arc *arc_p;
++
++struct node
++{
++ int64_t potential;
++ int orientation;
++ node_p child;
++ node_p pred;
++ node_p sibling;
++ node_p sibling_prev;
++ arc_p basic_arc;
++ arc_p firstout;
++ arc_p firstin;
++ arc_p arc_tmp;
++ int64_t flow;
++ int64_t depth;
++ int number;
++ int time;
++};
++
++struct arc
++{
++ int id;
++ int64_t cost;
++ node_p tail;
++ node_p head;
++ short ident;
++ arc_p nextout;
++ arc_p nextin;
++ int64_t flow;
++ int64_t org_cost;
++};
++
++const int MAX = 100;
++arc_p ap = NULL;
++
++int
++main ()
++{
++ ap = (arc_p) calloc(MAX, sizeof(arc_t));
++ printf("%d\n", ap[0].id);
++ for (int i = 1; i < MAX; i++)
++ {
++ ap[i-1].id = 500;
++ }
++ printf("%d\n", ap[0].id);
++ return 0;
++}
++
++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 2 "struct_layout" } } */
+diff --git a/gcc/testsuite/gcc.dg/struct/dfe_mem_ref_offset.c b/gcc/testsuite/gcc.dg/struct/dfe_mem_ref_offset.c
+new file mode 100644
+index 000000000..53583fe82
+--- /dev/null
++++ b/gcc/testsuite/gcc.dg/struct/dfe_mem_ref_offset.c
+@@ -0,0 +1,58 @@
++/* Supports the MEM_REF offset.
++ _1 = MEM[(struct arc *)ap_4 + 72B].flow;
++ Old rewrite:_1 = ap.reorder.0_8->flow;
++ New rewrite:_1 = MEM[(struct arc.reorder.0 *)ap.reorder.0_8 + 64B].flow. */
++/* { dg-do compile } */
++
++#include <stdio.h>
++#include <stdlib.h>
++
++typedef struct node node_t;
++typedef struct node *node_p;
++
++typedef struct arc arc_t;
++typedef struct arc *arc_p;
++
++struct node
++{
++ int64_t potential;
++ int orientation;
++ node_p child;
++ node_p pred;
++ node_p sibling;
++ node_p sibling_prev;
++ arc_p basic_arc;
++ arc_p firstout;
++ arc_p firstin;
++ arc_p arc_tmp;
++ int64_t flow;
++ int64_t depth;
++ int number;
++ int time;
++};
++
++struct arc
++{
++ int id;
++ int64_t cost;
++ node_p tail;
++ node_p head;
++ short ident;
++ arc_p nextout;
++ arc_p nextin;
++ int64_t flow;
++ int64_t org_cost;
++};
++
++int
++main ()
++{
++ const int MAX = 100;
++ /* A similar scenario can be reproduced only by using local variables. */
++ arc_p ap = NULL;
++ ap = (arc_p) calloc(MAX, sizeof(arc_t));
++ printf("%d\n", ap[1].flow);
++ return 0;
++}
++
++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 2 "struct_layout" } } */
+diff --git a/gcc/testsuite/gcc.dg/struct/dfe_mul_layer_ptr_record_bug.c b/gcc/testsuite/gcc.dg/struct/dfe_mul_layer_ptr_record_bug.c
+new file mode 100644
+index 000000000..fd675ec2e
+--- /dev/null
++++ b/gcc/testsuite/gcc.dg/struct/dfe_mul_layer_ptr_record_bug.c
+@@ -0,0 +1,30 @@
++/* { dg-do compile } */
++
++#include <stdio.h>
++#include <stdlib.h>
++
++typedef struct T_HASH_ENTRY
++{
++ unsigned int hash;
++ unsigned int klen;
++ char *key;
++} iHashEntry;
++
++typedef struct T_HASH
++{
++ unsigned int size;
++ unsigned int fill;
++ unsigned int keys;
++
++ iHashEntry **array;
++} uHash;
++
++uHash *retval;
++
++int
++main() {
++ retval->array = (iHashEntry **)calloc(sizeof(iHashEntry *), retval->size);
++ return 0;
++}
++
++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 2 "struct_layout" } } */
+diff --git a/gcc/testsuite/gcc.dg/struct/dfe_ptr_diff.c b/gcc/testsuite/gcc.dg/struct/dfe_ptr_diff.c
+new file mode 100644
+index 000000000..600e7908b
+--- /dev/null
++++ b/gcc/testsuite/gcc.dg/struct/dfe_ptr_diff.c
+@@ -0,0 +1,71 @@
++// support POINTER_DIFF_EXPR & NOP_EXPR to avoid
++// escape_unhandled_rewrite, "Type escapes via a unhandled rewrite stmt"
++/* { dg-do compile } */
++
++#include <stdio.h>
++#include <stdlib.h>
++
++typedef struct node node_t;
++typedef struct node *node_p;
++
++typedef struct arc arc_t;
++typedef struct arc *arc_p;
++
++typedef struct network
++{
++ arc_p arcs;
++ arc_p sorted_arcs;
++ int x;
++ node_p nodes;
++ node_p stop_nodes;
++} network_t;
++
++struct node
++{
++ int64_t potential;
++ int orientation;
++ node_p child;
++ node_p pred;
++ node_p sibling;
++ node_p sibling_prev;
++ arc_p basic_arc;
++ arc_p firstout;
++ arc_p firstin;
++ arc_p arc_tmp;
++ int64_t flow;
++ int64_t depth;
++ int number;
++ int time;
++};
++
++struct arc
++{
++ int id;
++ int64_t cost;
++ node_p tail;
++ node_p head;
++ short ident;
++ arc_p nextout;
++ arc_p nextin;
++ int64_t flow;
++ int64_t org_cost;
++};
++
++int
++main ()
++{
++ arc_t *old_arcs;
++ node_t *node;
++ node_t *stop;
++ size_t off;
++ network_t* net;
++
++ for( ; node->number < stop->number; node++ )
++ {
++ off = node->basic_arc - old_arcs;
++ node->basic_arc = (arc_t *)(net->arcs + off);
++ }
++ return 0;
++}
++
++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 3 "struct_layout" } } */
+diff --git a/gcc/testsuite/gcc.dg/struct/dfe_ptr_negate_expr.c b/gcc/testsuite/gcc.dg/struct/dfe_ptr_negate_expr.c
+new file mode 100644
+index 000000000..f411364a7
+--- /dev/null
++++ b/gcc/testsuite/gcc.dg/struct/dfe_ptr_negate_expr.c
+@@ -0,0 +1,55 @@
++// support NEGATE_EXPR rewriting
++/* { dg-do compile } */
++
++#include <stdio.h>
++#include <stdlib.h>
++
++typedef struct node node_t;
++typedef struct node *node_p;
++
++typedef struct arc arc_t;
++typedef struct arc *arc_p;
++
++struct node
++{
++ int64_t potential;
++ int orientation;
++ node_p child;
++ node_p pred;
++ node_p sibling;
++ node_p sibling_prev;
++ arc_p basic_arc;
++ arc_p firstout;
++ arc_p firstin;
++ arc_p arc_tmp;
++ int64_t flow;
++ int64_t depth;
++ int number;
++ int time;
++};
++
++struct arc
++{
++ int id;
++ int64_t cost;
++ node_p tail;
++ node_p head;
++ short ident;
++ arc_p nextout;
++ arc_p nextin;
++ int64_t flow;
++ int64_t org_cost;
++};
++
++int
++main ()
++{
++ int64_t susp = 0;
++ const int MAX = 100;
++ arc_p ap = (arc_p) calloc(MAX, sizeof(arc_t));
++ ap -= susp;
++ printf("%d\n", ap[1].flow);
++ return 0;
++}
++
++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 2 "struct_layout" } } */
+diff --git a/gcc/testsuite/gcc.dg/struct/dfe_ptr_ptr.c b/gcc/testsuite/gcc.dg/struct/dfe_ptr_ptr.c
+new file mode 100644
+index 000000000..a4e723763
+--- /dev/null
++++ b/gcc/testsuite/gcc.dg/struct/dfe_ptr_ptr.c
+@@ -0,0 +1,55 @@
++// release escape_ptr_ptr, "Type is used in a pointer to a pointer [not handled yet]";
++/* { dg-do compile } */
++
++#include <stdio.h>
++#include <stdlib.h>
++
++typedef struct node node_t;
++typedef struct node *node_p;
++
++typedef struct arc arc_t;
++typedef struct arc *arc_p;
++
++struct node
++{
++ int64_t potential;
++ int orientation;
++ node_p child;
++ node_p pred;
++ node_p sibling;
++ node_p sibling_prev;
++ arc_p basic_arc;
++ arc_p firstout;
++ arc_p firstin;
++ arc_p arc_tmp;
++ int64_t flow;
++ int64_t depth;
++ int number;
++ int time;
++};
++
++struct arc
++{
++ int id;
++ int64_t cost;
++ node_p tail;
++ node_p head;
++ short ident;
++ arc_p nextout;
++ arc_p nextin;
++ int64_t flow;
++ int64_t org_cost;
++};
++
++const int MAX = 100;
++arc_t **ap = NULL;
++
++int
++main ()
++{
++ ap = (arc_t**) malloc(MAX * sizeof(arc_t*));
++ (*ap)[0].id = 300;
++ return 0;
++}
++
++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 2 "struct_layout" } } */
+diff --git a/gcc/testsuite/gcc.dg/struct/struct-reorg.exp b/gcc/testsuite/gcc.dg/struct/struct-reorg.exp
+index 67b3ac2d5..ac5585813 100644
+--- a/gcc/testsuite/gcc.dg/struct/struct-reorg.exp
++++ b/gcc/testsuite/gcc.dg/struct/struct-reorg.exp
+@@ -64,8 +64,27 @@ gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/complete_struct_relayout
+ "" "-fipa-struct-reorg=1 -fdump-ipa-all -flto-partition=one -fwhole-program"
+
+ # -fipa-struct-reorg=2
+-gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c]] \
++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/rf*.c]] \
++ "" "-fipa-struct-reorg=2 -fdump-ipa-all -flto-partition=one -fwhole-program"
++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/wo_prof_*.c]] \
+ "" "-fipa-struct-reorg=2 -fdump-ipa-all -flto-partition=one -fwhole-program"
++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/w_ratio_*.c]] \
++ "" "-fipa-struct-reorg=2 -fdump-ipa-all -flto-partition=one -fwhole-program"
++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/w_prof_*.c]] \
++ "" "-fipa-struct-reorg=2 -fdump-ipa-all -flto-partition=one -fwhole-program"
++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/struct_reorg*.c]] \
++ "" "-fipa-struct-reorg=2 -fdump-ipa-all -flto-partition=one -fwhole-program"
++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/sr_*.c]] \
++ "" "-fipa-struct-reorg=2 -fdump-ipa-all -flto-partition=one -fwhole-program"
++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/csr_*.c]] \
++ "" "-fipa-struct-reorg=2 -fdump-ipa-all -flto-partition=one -fwhole-program"
++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/complete_struct_relayout.c]] \
++ "" "-fipa-struct-reorg=2 -fdump-ipa-all -flto-partition=one -fwhole-program"
++
++# -fipa-struct-reorg=3
++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/dfe*.c]] \
++ "" "-fipa-struct-reorg=3 -fdump-ipa-all -flto-partition=one -fwhole-program"
++
+ # All done.
+ torture-finish
+ dg-finish
+--
+2.27.0.windows.1
+