summaryrefslogtreecommitdiff
path: root/0022-DFE-Add-Dead-Field-Elimination-in-Struct-Reorg.patch
diff options
context:
space:
mode:
authorCoprDistGit <infra@openeuler.org>2025-02-28 10:03:49 +0000
committerCoprDistGit <infra@openeuler.org>2025-02-28 10:03:49 +0000
commit73127104a245052cd5cf29cdaaca3e5c32c70348 (patch)
tree8e28b63e478c43c252f18b49836dff7313affe54 /0022-DFE-Add-Dead-Field-Elimination-in-Struct-Reorg.patch
parent49d3feaf4665cdb07576fc1a2382a4d82a612d35 (diff)
automatic import of gccopeneuler24.03_LTS_SP1
Diffstat (limited to '0022-DFE-Add-Dead-Field-Elimination-in-Struct-Reorg.patch')
-rw-r--r--0022-DFE-Add-Dead-Field-Elimination-in-Struct-Reorg.patch1753
1 files changed, 1753 insertions, 0 deletions
diff --git a/0022-DFE-Add-Dead-Field-Elimination-in-Struct-Reorg.patch b/0022-DFE-Add-Dead-Field-Elimination-in-Struct-Reorg.patch
new file mode 100644
index 0000000..2822078
--- /dev/null
+++ b/0022-DFE-Add-Dead-Field-Elimination-in-Struct-Reorg.patch
@@ -0,0 +1,1753 @@
+From 9d03b0a7741915e3a0172d60b9c21bf5abbda89e Mon Sep 17 00:00:00 2001
+From: Mingchuan Wu <wumingchuan1992@foxmail.com>
+Date: Mon, 28 Aug 2023 18:11:02 +0800
+Subject: [PATCH 22/22] [DFE] Add Dead Field Elimination in Struct-Reorg.
+
+We can transform gimple to eliminate fields that are never read
+and replace the dead fields in stmt by creating a new ssa.
+---
+ gcc/common.opt | 4 +
+ gcc/ipa-struct-reorg/ipa-struct-reorg.cc | 240 +++++++++++++++++-
+ gcc/ipa-struct-reorg/ipa-struct-reorg.h | 8 +
+ gcc/opts.cc | 17 ++
+ gcc/testsuite/gcc.dg/struct/dfe_DTE_verify.c | 86 +++++++
+ .../gcc.dg/struct/dfe_ele_minus_verify.c | 60 +++++
+ .../gcc.dg/struct/dfe_extr_board_init.c | 77 ++++++
+ gcc/testsuite/gcc.dg/struct/dfe_extr_claw.c | 84 ++++++
+ gcc/testsuite/gcc.dg/struct/dfe_extr_dtrace.c | 56 ++++
+ gcc/testsuite/gcc.dg/struct/dfe_extr_gc.c | 162 ++++++++++++
+ gcc/testsuite/gcc.dg/struct/dfe_extr_hpsa.c | 126 +++++++++
+ .../gcc.dg/struct/dfe_extr_mv_udc_core.c | 82 ++++++
+ .../gcc.dg/struct/dfe_extr_tcp_usrreq.c | 58 +++++
+ .../gcc.dg/struct/dfe_extr_ui_main.c | 61 +++++
+ .../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 | 4 +
+ .../struct/wo_prof_escape_replace_type.c | 49 ++++
+ 21 files changed, 1436 insertions(+), 7 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_extr_board_init.c
+ create mode 100644 gcc/testsuite/gcc.dg/struct/dfe_extr_claw.c
+ create mode 100644 gcc/testsuite/gcc.dg/struct/dfe_extr_dtrace.c
+ create mode 100644 gcc/testsuite/gcc.dg/struct/dfe_extr_gc.c
+ create mode 100644 gcc/testsuite/gcc.dg/struct/dfe_extr_hpsa.c
+ create mode 100644 gcc/testsuite/gcc.dg/struct/dfe_extr_mv_udc_core.c
+ create mode 100644 gcc/testsuite/gcc.dg/struct/dfe_extr_tcp_usrreq.c
+ create mode 100644 gcc/testsuite/gcc.dg/struct/dfe_extr_ui_main.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
+ create mode 100644 gcc/testsuite/gcc.dg/struct/wo_prof_escape_replace_type.c
+
+diff --git a/gcc/common.opt b/gcc/common.opt
+index 14633c821..8bb735551 100644
+--- a/gcc/common.opt
++++ b/gcc/common.opt
+@@ -1988,6 +1988,10 @@ fipa-struct-reorg
+ Common 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, 3)
++-fipa-struct-reorg=[0,1,2,3] adding none, struct-reorg, reorder-fields, dfe optimizations.
++
+ fipa-vrp
+ Common Var(flag_ipa_vrp) Optimization
+ Perform IPA Value Range Propagation.
+diff --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.cc b/gcc/ipa-struct-reorg/ipa-struct-reorg.cc
+index 3e5f9538b..eac5fac7e 100644
+--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.cc
++++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.cc
+@@ -87,6 +87,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"
+@@ -268,10 +269,43 @@ enum srmode
+ STRUCT_REORDER_FIELDS
+ };
+
++/* 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_SLO,
++ DEAD_FIELD_ELIMINATION
++};
++
+ static bool is_result_of_mult (tree arg, tree *num, tree struct_size);
+ static bool isptrptr (tree type);
++void get_base (tree &base, tree expr);
+
+ 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
+
+@@ -353,7 +387,8 @@ srfield::srfield (tree field, srtype *base)
+ fielddecl (field),
+ base (base),
+ type (NULL),
+- clusternum (0)
++ clusternum (0),
++ field_access (EMPTY_FIELD)
+ {
+ for (int i = 0; i < max_split; i++)
+ newfield[i] = NULL_TREE;
+@@ -392,6 +427,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
+@@ -595,7 +649,17 @@ srtype::analyze (void)
+ into 2 different structures. In future we intend to add profile
+ info and/or static heuristics to differentiate splitting process. */
+ if (fields.length () == 2)
+- fields[1]->clusternum = 1;
++ {
++ /* Currently, when the replacement structure type exists,
++ we only split the replacement structure. */
++ for (hash_map<tree, tree>::iterator it = replace_type_map.begin ();
++ it != replace_type_map.end (); ++it)
++ {
++ if (types_compatible_p ((*it).second, this->type))
++ return;
++ }
++ fields[1]->clusternum = 1;
++ }
+
+ /* Otherwise we do nothing. */
+ if (fields.length () >= 3)
+@@ -838,6 +902,10 @@ srtype::create_new_type (void)
+ for (unsigned i = 0; i < fields.length (); i++)
+ {
+ srfield *f = fields[i];
++ if (current_mode == STRUCT_REORDER_FIELDS
++ && struct_layout_optimize_level >= DEAD_FIELD_ELIMINATION
++ && !(f->field_access & READ_FIELD))
++ continue;
+ f->create_new_fields (newtype, newfields, newlast);
+ }
+
+@@ -856,6 +924,16 @@ srtype::create_new_type (void)
+
+ warn_padded = save_warn_padded;
+
++ if (current_mode == STRUCT_REORDER_FIELDS
++ && replace_type_map.get (this->newtype[0]) == NULL)
++ replace_type_map.put (this->newtype[0], this->type);
++ if (dump_file)
++ {
++ if (current_mode == STRUCT_REORDER_FIELDS
++ && 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);
+@@ -1269,6 +1347,7 @@ public:
+ 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
+@@ -3057,6 +3136,119 @@ ipa_struct_reorg::find_vars (gimple *stmt)
+ }
+ }
+
++static HOST_WIDE_INT
++get_offset (tree op, HOST_WIDE_INT offset)
++{
++ switch (TREE_CODE (op))
++ {
++ case COMPONENT_REF:
++ {
++ return int_byte_position (TREE_OPERAND (op, 1));
++ }
++ case MEM_REF:
++ {
++ return tree_to_uhwi (TREE_OPERAND (op, 1));
++ }
++ default:
++ return offset;
++ }
++ return offset;
++}
++
++/* Record field access. */
++static void
++record_field_access (tree type, HOST_WIDE_INT offset,
++ unsigned access, void *data)
++{
++ srtype *this_srtype = ((ipa_struct_reorg *)data)->find_type (type);
++ if (this_srtype == NULL)
++ return;
++ srfield *this_srfield = this_srtype->find_field (offset);
++ 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, type);
++ fprintf (dump_file, " field:");
++ print_generic_expr (dump_file, this_srfield->fielddecl);
++ fprintf (dump_file, "\n");
++ }
++ return;
++
++}
++
++/* Update field_access in srfield. */
++
++static void
++update_field_access (tree node, tree op, unsigned access, void *data)
++{
++ HOST_WIDE_INT offset = 0;
++ offset = get_offset (op, offset);
++ tree node_type = inner_type (TREE_TYPE (node));
++ record_field_access (node_type, offset, access, data);
++ tree base = node;
++ get_base (base, node);
++ tree base_type = inner_type (TREE_TYPE (base));
++ if (!types_compatible_p (base_type, node_type))
++ {
++ record_field_access (base_type, get_offset (node, offset),
++ access, data);
++ }
++ return;
++}
++
++/* A callback for walk_stmt_load_store_ops to visit store. */
++
++static bool
++find_field_p_store (gimple *stmt ATTRIBUTE_UNUSED,
++ tree node, tree op, void *data)
++{
++ update_field_access (node, op, WRITE_FIELD, data);
++
++ return false;
++}
++
++/* A callback for walk_stmt_load_store_ops to visit load. */
++
++static bool
++find_field_p_load (gimple *stmt ATTRIBUTE_UNUSED,
++ tree node, tree op, void *data)
++{
++ update_field_access (node, op, 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)
++ return true;
++ return false;
++}
++
+ /* Maybe record access of statement for further analaysis. */
+
+ void
+@@ -3078,6 +3270,13 @@ ipa_struct_reorg::maybe_record_stmt (cgraph_node *node, gimple *stmt)
+ default:
+ break;
+ }
++ if (current_mode == STRUCT_REORDER_FIELDS
++ && 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. */
+@@ -3368,8 +3567,11 @@ ipa_struct_reorg::maybe_mark_or_record_other_side (tree side, tree other,
+ }
+ 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
+@@ -3949,8 +4151,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))
+ {
+@@ -4216,7 +4419,9 @@ ipa_struct_reorg::check_other_side (srdecl *decl, tree other, gimple *stmt,
+ }
+
+ srtype *t1 = find_type (inner_type (t));
+- if (t1 == type)
++ /* In the other side check, escape mark is added
++ when the replacement struct type exists. */
++ if (t1 == type || is_replace_type (inner_type (t), type->type))
+ {
+ /* In Complete Struct Relayout, if lhs type is the same
+ as rhs type, we could return without any harm. */
+@@ -5513,6 +5718,27 @@ bool
+ ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi)
+ {
+ bool remove = false;
++
++ if (current_mode == STRUCT_REORDER_FIELDS
++ && 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);
++ }
++ /* Replace the dead field in stmt by creating a dummy ssa. */
++ tree dummy_ssa = make_ssa_name (TREE_TYPE (gimple_assign_lhs (stmt)));
++ gimple_assign_set_lhs (stmt, dummy_ssa);
++ update_stmt (stmt);
++ if (dump_file && (dump_flags & TDF_DETAILS))
++ {
++ fprintf (dump_file, "To: \n");
++ print_gimple_stmt (dump_file, stmt, 0);
++ }
++ }
++
+ 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 6f85adeb4..719f7b308 100644
+--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.h
++++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.h
+@@ -143,6 +143,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)
+ {
+@@ -164,6 +165,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;
+@@ -175,6 +182,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/opts.cc b/gcc/opts.cc
+index c3cc2c169..b868d189e 100644
+--- a/gcc/opts.cc
++++ b/gcc/opts.cc
+@@ -2957,6 +2957,23 @@ common_handle_option (struct gcc_options *opts,
+ SET_OPTION_IF_UNSET (opts, opts_set, flag_profile_correction, value);
+ break;
+
++ case OPT_fipa_struct_reorg_:
++ /* No break here - do -fipa-struct-reorg processing. */
++ /* FALLTHRU. */
++ case OPT_fipa_struct_reorg:
++ opts->x_flag_ipa_struct_reorg = value;
++ if (value && !opts->x_struct_layout_optimize_level)
++ {
++ /* Using the -fipa-struct-reorg option is equivalent to using
++ -fipa-struct-reorg=1. */
++ opts->x_struct_layout_optimize_level = 1;
++ }
++ break;
++
++ case OPT_fipa_reorder_fields:
++ SET_OPTION_IF_UNSET (opts, opts_set, flag_ipa_struct_reorg, value);
++ break;
++
+ case OPT_fprofile_generate_:
+ opts->x_profile_data_prefix = xstrdup (arg);
+ value = true;
+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..0c9e384c4
+--- /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 "reorder_fields" } } */
+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..717fcc386
+--- /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 "reorder_fields" } } */
+diff --git a/gcc/testsuite/gcc.dg/struct/dfe_extr_board_init.c b/gcc/testsuite/gcc.dg/struct/dfe_extr_board_init.c
+new file mode 100644
+index 000000000..7723c240b
+--- /dev/null
++++ b/gcc/testsuite/gcc.dg/struct/dfe_extr_board_init.c
+@@ -0,0 +1,77 @@
++/* { dg-do compile} */
++
++#define NULL ((void*)0)
++typedef unsigned long size_t;
++typedef long intptr_t;
++typedef unsigned long uintptr_t;
++typedef long scalar_t__;
++typedef int bool;
++#define false 0
++#define true 1
++
++typedef struct TYPE_5__ TYPE_2__;
++typedef struct TYPE_4__ TYPE_1__;
++
++struct TYPE_4__
++{
++ int Pin;
++ int Pull;
++ int Mode;
++ int Speed;
++};
++
++struct TYPE_5__
++{
++ int MEMRMP;
++};
++typedef TYPE_1__ GPIO_InitTypeDef;
++
++int BT_RST_PIN;
++int BT_RST_PORT;
++int CONN_POS10_PIN;
++int CONN_POS10_PORT;
++int GPIO_HIGH (int, int);
++int GPIO_MODE_INPUT;
++int GPIO_MODE_OUTPUT_PP;
++int GPIO_NOPULL;
++int GPIO_PULLUP;
++int GPIO_SPEED_FREQ_LOW;
++int HAL_GPIO_Init (int, TYPE_1__ *);
++scalar_t__ IS_GPIO_RESET (int, int);
++TYPE_2__ *SYSCFG;
++int __HAL_RCC_GPIOB_CLK_ENABLE ();
++int __HAL_RCC_GPIOC_CLK_ENABLE ();
++
++__attribute__((used)) static void
++LBF_DFU_If_Needed (void)
++{
++ GPIO_InitTypeDef GPIO_InitStruct;
++ __HAL_RCC_GPIOC_CLK_ENABLE ();
++ GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
++ GPIO_InitStruct.Pull = GPIO_NOPULL;
++ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
++ GPIO_InitStruct.Pin = BT_RST_PIN;
++ HAL_GPIO_Init (BT_RST_PORT, &GPIO_InitStruct);
++
++ GPIO_HIGH (BT_RST_PORT, BT_RST_PIN);
++ __HAL_RCC_GPIOB_CLK_ENABLE ();
++ GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
++ GPIO_InitStruct.Pull = GPIO_PULLUP;
++ GPIO_InitStruct.Pin = CONN_POS10_PIN;
++ HAL_GPIO_Init (CONN_POS10_PORT, &GPIO_InitStruct);
++
++ if (IS_GPIO_RESET (CONN_POS10_PORT, CONN_POS10_PIN))
++ {
++ SYSCFG->MEMRMP = 0x00000001;
++ asm (
++ "LDR R0, =0x000000\n\t"
++ "LDR SP, [R0, #0]\n\t"
++ );
++ asm (
++ "LDR R0, [R0, #0]\n\t"
++ "BX R0\n\t"
++ );
++ }
++}
++
++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 0 "reorder_fields" } } */
+diff --git a/gcc/testsuite/gcc.dg/struct/dfe_extr_claw.c b/gcc/testsuite/gcc.dg/struct/dfe_extr_claw.c
+new file mode 100644
+index 000000000..a1feac966
+--- /dev/null
++++ b/gcc/testsuite/gcc.dg/struct/dfe_extr_claw.c
+@@ -0,0 +1,84 @@
++/* { dg-do compile} */
++
++#define NULL ((void*)0)
++typedef unsigned long size_t;
++typedef long intptr_t;
++typedef unsigned long uintptr_t;
++typedef long scalar_t__;
++typedef int bool;
++#define false 0
++#define true 1
++
++typedef struct TYPE_2__ TYPE_1__;
++
++struct net_device
++{
++ struct claw_privbk* ml_priv;
++};
++struct clawctl
++{
++ int linkid;
++};
++struct claw_privbk
++{
++ int system_validate_comp;
++ TYPE_1__* p_env;
++ int ctl_bk;
++};
++typedef int __u8;
++struct TYPE_2__
++{
++ scalar_t__ packing;
++ int api_type;
++};
++
++int CLAW_DBF_TEXT (int, int, char*);
++int CONNECTION_REQUEST;
++int HOST_APPL_NAME;
++scalar_t__ PACKING_ASK;
++scalar_t__ PACK_SEND;
++int WS_APPL_NAME_IP_NAME;
++int WS_APPL_NAME_PACKED;
++int claw_send_control (struct net_device*, int, int, int, int, int, int);
++int setup;
++
++__attribute__((noinline)) int
++claw_send_control (struct net_device* net, int a, int b, int c, int d, int e,
++ int f)
++{
++ return net->ml_priv->system_validate_comp + a + b + c + d + f;
++}
++
++__attribute__((used)) static int
++claw_snd_conn_req (struct net_device *dev, __u8 link)
++{
++ int rc;
++ struct claw_privbk *privptr = dev->ml_priv;
++ struct clawctl *p_ctl;
++ CLAW_DBF_TEXT (2, setup, "snd_conn");
++ rc = 1;
++ p_ctl = (struct clawctl *)&privptr->ctl_bk;
++ p_ctl->linkid = link;
++ if (privptr->system_validate_comp == 0x00)
++ {
++ return rc;
++ }
++ if (privptr->p_env->packing == PACKING_ASK)
++ {
++ rc = claw_send_control (dev, CONNECTION_REQUEST, 0, 0, 0,
++ WS_APPL_NAME_PACKED, WS_APPL_NAME_PACKED);
++ }
++ if (privptr->p_env->packing == PACK_SEND)
++ {
++ rc = claw_send_control (dev, CONNECTION_REQUEST, 0, 0, 0,
++ WS_APPL_NAME_IP_NAME, WS_APPL_NAME_IP_NAME);
++ }
++ if (privptr->p_env->packing == 0)
++ {
++ rc = claw_send_control (dev, CONNECTION_REQUEST, 0, 0, 0,
++ HOST_APPL_NAME, privptr->p_env->api_type);
++ }
++ return rc;
++}
++
++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 1 "reorder_fields" } } */
+diff --git a/gcc/testsuite/gcc.dg/struct/dfe_extr_dtrace.c b/gcc/testsuite/gcc.dg/struct/dfe_extr_dtrace.c
+new file mode 100644
+index 000000000..fd1e936ca
+--- /dev/null
++++ b/gcc/testsuite/gcc.dg/struct/dfe_extr_dtrace.c
+@@ -0,0 +1,56 @@
++/* { dg-do compile} */
++
++#define NULL ((void*)0)
++typedef unsigned long size_t;
++typedef long intptr_t;
++typedef unsigned long uintptr_t;
++typedef long scalar_t__;
++typedef int bool;
++#define false 0
++#define true 1
++
++typedef struct TYPE_4__ TYPE_2__;
++typedef struct TYPE_3__ TYPE_1__;
++
++typedef int uint8_t;
++typedef int uint16_t;
++
++struct TYPE_4__
++{
++ size_t cpu_id;
++};
++
++struct TYPE_3__
++{
++ int cpuc_dtrace_flags;
++};
++
++TYPE_2__ *CPU;
++volatile int CPU_DTRACE_FAULT;
++TYPE_1__ *cpu_core;
++scalar_t__ dtrace_load8 (uintptr_t);
++
++__attribute__((used)) static int
++dtrace_bcmp (const void *s1, const void *s2, size_t len)
++{
++ volatile uint16_t *flags;
++ flags = (volatile uint16_t *)&cpu_core[CPU->cpu_id].cpuc_dtrace_flags;
++ if (s1 == s2)
++ return (0);
++ if (s1 == NULL || s2 == NULL)
++ return (1);
++ if (s1 != s2 && len != 0)
++ {
++ const uint8_t *ps1 = s1;
++ const uint8_t *ps2 = s2;
++ do
++ {
++ if (dtrace_load8 ((uintptr_t)ps1++) != *ps2++)
++ return (1);
++ }
++ while (--len != 0 && !(*flags & CPU_DTRACE_FAULT));
++ }
++ return (0);
++}
++
++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 0 "reorder_fields" } } */
+diff --git a/gcc/testsuite/gcc.dg/struct/dfe_extr_gc.c b/gcc/testsuite/gcc.dg/struct/dfe_extr_gc.c
+new file mode 100644
+index 000000000..b13d785a9
+--- /dev/null
++++ b/gcc/testsuite/gcc.dg/struct/dfe_extr_gc.c
+@@ -0,0 +1,162 @@
++/* { dg-do compile} */
++
++#define NULL ((void*)0)
++typedef unsigned long size_t;
++typedef long intptr_t;
++typedef unsigned long uintptr_t;
++typedef long scalar_t__;
++typedef int bool;
++#define false 0
++#define true 1
++
++struct mrb_context
++{
++ size_t stack;
++ size_t stbase;
++ size_t stend;
++ size_t eidx;
++ int *ci;
++ int *cibase;
++ int status;
++};
++
++struct RObject
++{
++ int dummy;
++};
++
++struct RHash
++{
++ int dummy;
++};
++
++struct RFiber
++{
++ struct mrb_context *cxt;
++};
++
++struct RClass
++{
++ int dummy;
++};
++
++struct RBasic
++{
++ int tt;
++};
++
++struct RArray
++{
++ int dummy;
++};
++
++typedef int mrb_state;
++typedef int mrb_gc;
++typedef int mrb_callinfo;
++size_t ARY_LEN (struct RArray *);
++size_t MRB_ENV_STACK_LEN (struct RBasic *);
++int MRB_FIBER_TERMINATED;
++
++#define MRB_TT_ARRAY 140
++#define MRB_TT_CLASS 139
++#define MRB_TT_DATA 138
++#define MRB_TT_ENV 137
++#define MRB_TT_EXCEPTION 136
++#define MRB_TT_FIBER 135
++#define MRB_TT_HASH 134
++#define MRB_TT_ICLASS 133
++#define MRB_TT_MODULE 132
++#define MRB_TT_OBJECT 131
++#define MRB_TT_PROC 130
++#define MRB_TT_RANGE 129
++#define MRB_TT_SCLASS 128
++
++size_t ci_nregs (int *);
++int gc_mark_children (int *, int *, struct RBasic *);
++size_t mrb_gc_mark_hash_size (int *, struct RHash *);
++size_t mrb_gc_mark_iv_size (int *, struct RObject *);
++size_t mrb_gc_mark_mt_size (int *, struct RClass *);
++
++__attribute__((used)) static size_t
++gc_gray_mark (mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
++{
++ size_t children = 0;
++ gc_mark_children (mrb, gc, obj);
++ switch (obj->tt)
++ {
++ case MRB_TT_ICLASS:
++ children++;
++ break;
++
++ case MRB_TT_CLASS:
++ case MRB_TT_SCLASS:
++ case MRB_TT_MODULE:
++ {
++ struct RClass *c = (struct RClass *)obj;
++ children += mrb_gc_mark_iv_size (mrb, (struct RObject *)obj);
++ children += mrb_gc_mark_mt_size (mrb, c);
++ children ++;
++ }
++ break;
++
++ case MRB_TT_OBJECT:
++ case MRB_TT_DATA:
++ case MRB_TT_EXCEPTION:
++ children += mrb_gc_mark_iv_size (mrb, (struct RObject *)obj);
++ break;
++
++ case MRB_TT_ENV:
++ children += MRB_ENV_STACK_LEN (obj);
++ break;
++
++ case MRB_TT_FIBER:
++ {
++ struct mrb_context *c = ((struct RFiber *)obj)->cxt;
++ size_t i;
++ mrb_callinfo *ci;
++ if (!c || c->status == MRB_FIBER_TERMINATED)
++ break;
++
++ i = c->stack - c->stbase;
++ if (c->ci)
++ {
++ i += ci_nregs (c->ci);
++ }
++ if (c->stbase + i > c->stend)
++ i = c->stend - c->stbase;
++
++ children += i;
++ children += c->eidx;
++ if (c->cibase)
++ {
++ for (i = 0, ci = c->cibase; ci <= c->ci; i++, ci++)
++ ;
++ }
++ children += i;
++ }
++ break;
++
++ case MRB_TT_ARRAY:
++ {
++ struct RArray *a = (struct RArray *)obj;
++ children += ARY_LEN (a);
++ }
++ break;
++
++ case MRB_TT_HASH:
++ children += mrb_gc_mark_iv_size (mrb, (struct RObject *)obj);
++ children += mrb_gc_mark_hash_size (mrb, (struct RHash *)obj);
++ break;
++
++ case MRB_TT_PROC:
++ case MRB_TT_RANGE:
++ children += 2;
++ break;
++ default:
++ break;
++ }
++
++ return children;
++}
++
++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 0 "reorder_fields" } } */
+diff --git a/gcc/testsuite/gcc.dg/struct/dfe_extr_hpsa.c b/gcc/testsuite/gcc.dg/struct/dfe_extr_hpsa.c
+new file mode 100644
+index 000000000..bc28a658a
+--- /dev/null
++++ b/gcc/testsuite/gcc.dg/struct/dfe_extr_hpsa.c
+@@ -0,0 +1,126 @@
++/* { dg-do compile} */
++
++#define NULL ((void*)0)
++typedef unsigned long size_t;
++typedef long intptr_t;
++typedef unsigned long uintptr_t;
++typedef long scalar_t__;
++typedef int bool;
++#define false 0
++#define true 1
++
++typedef struct TYPE_6__ TYPE_3__;
++typedef struct TYPE_5__ TYPE_2__;
++typedef struct TYPE_4__ TYPE_1__;
++
++struct io_accel2_cmd
++{
++ int dummy;
++};
++
++struct hpsa_tmf_struct
++{
++ int it_nexus;
++};
++
++struct hpsa_scsi_dev_t
++{
++ int nphysical_disks;
++ int ioaccel_handle;
++ struct hpsa_scsi_dev_t **phys_disk;
++};
++
++struct ctlr_info
++{
++ TYPE_3__ *pdev;
++ struct io_accel2_cmd *ioaccel2_cmd_pool;
++};
++struct TYPE_4__
++{
++ int LunAddrBytes;
++};
++
++struct TYPE_5__
++{
++ TYPE_1__ LUN;
++};
++
++struct CommandList
++{
++ size_t cmdindex;
++ int cmd_type;
++ struct hpsa_scsi_dev_t *phys_disk;
++ TYPE_2__ Header;
++};
++
++struct TYPE_6__
++{
++ int dev;
++};
++
++int BUG ();
++#define CMD_IOACCEL1 132
++#define CMD_IOACCEL2 131
++#define CMD_IOCTL_PEND 130
++#define CMD_SCSI 129
++#define IOACCEL2_TMF 128
++int dev_err (int *, char *, int);
++scalar_t__ hpsa_is_cmd_idle (struct CommandList *);
++int le32_to_cpu (int);
++int test_memcmp (unsigned char *, int *, int);
++
++__attribute__((used)) static bool
++hpsa_cmd_dev_match (struct ctlr_info *h, struct CommandList *c,
++ struct hpsa_scsi_dev_t *dev, unsigned char *scsi3addr)
++{
++ int i;
++ bool match = false;
++ struct io_accel2_cmd * c2 = &h->ioaccel2_cmd_pool[c->cmdindex];
++ struct hpsa_tmf_struct *ac = (struct hpsa_tmf_struct *)c2;
++
++ if (hpsa_is_cmd_idle (c))
++ return false;
++
++ switch (c->cmd_type)
++ {
++ case CMD_SCSI:
++ case CMD_IOCTL_PEND:
++ match = !test_memcmp (scsi3addr, &c->Header.LUN.LunAddrBytes,
++ sizeof (c->Header.LUN.LunAddrBytes));
++ break;
++
++ case CMD_IOACCEL1:
++ case CMD_IOACCEL2:
++ if (c->phys_disk == dev)
++ {
++ match = true;
++ }
++ else
++ {
++ for (i = 0; i < dev->nphysical_disks && !match; i++)
++ {
++ match = dev->phys_disk[i] == c->phys_disk;
++ }
++ }
++ break;
++
++ case IOACCEL2_TMF:
++ for (i = 0; i < dev->nphysical_disks && !match; i++)
++ {
++ match = dev->phys_disk[i]->ioaccel_handle ==
++ le32_to_cpu (ac->it_nexus);
++ }
++ break;
++
++ case 0:
++ match = false;
++ break;
++ default:
++ dev_err (&h->pdev->dev, "unexpected cmd_type: %d\n", c->cmd_type);
++ BUG ();
++ }
++
++ return match;
++}
++
++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 0 "reorder_fields" } } */
+diff --git a/gcc/testsuite/gcc.dg/struct/dfe_extr_mv_udc_core.c b/gcc/testsuite/gcc.dg/struct/dfe_extr_mv_udc_core.c
+new file mode 100644
+index 000000000..0a585ac3d
+--- /dev/null
++++ b/gcc/testsuite/gcc.dg/struct/dfe_extr_mv_udc_core.c
+@@ -0,0 +1,82 @@
++/* { dg-do compile} */
++
++#define NULL ((void*)0)
++typedef unsigned long size_t;
++typedef long intptr_t;
++typedef unsigned long uintptr_t;
++typedef long scalar_t__;
++typedef int bool;
++#define false 0
++#define true 1
++
++typedef struct TYPE_4__ TYPE_2__;
++typedef struct TYPE_3__ TYPE_1__;
++typedef int u32;
++
++struct mv_udc
++{
++ TYPE_2__ *op_regs;
++ TYPE_1__ *ep_dqh;
++ struct mv_ep *eps;
++};
++
++struct mv_ep
++{
++ TYPE_1__ *dqh;
++ struct mv_udc *udc;
++};
++
++struct TYPE_4__
++{
++ int *epctrlx;
++};
++
++struct TYPE_3__
++{
++ int max_packet_length;
++ int next_dtd_ptr;
++};
++
++int EP0_MAX_PKT_SIZE;
++int EPCTRL_RX_ENABLE;
++int EPCTRL_RX_EP_TYPE_SHIFT;
++int EPCTRL_TX_ENABLE;
++int EPCTRL_TX_EP_TYPE_SHIFT;
++int EP_QUEUE_HEAD_IOS;
++int EP_QUEUE_HEAD_MAX_PKT_LEN_POS;
++int EP_QUEUE_HEAD_NEXT_TERMINATE;
++int USB_ENDPOINT_XFER_CONTROL;
++int readl (int *);
++int writel (int, int *);
++
++__attribute__((used)) static void
++ep0_reset (struct mv_udc *udc)
++{
++ struct mv_ep *ep;
++ u32 epctrlx;
++ int i = 0;
++ for (i = 0; i < 2; i++)
++ {
++ ep = &udc->eps[i];
++ ep->udc = udc;
++ ep->dqh = &udc->ep_dqh[i];
++ ep->dqh->max_packet_length =
++ (EP0_MAX_PKT_SIZE << EP_QUEUE_HEAD_MAX_PKT_LEN_POS)
++ | EP_QUEUE_HEAD_IOS;
++ ep->dqh->next_dtd_ptr = EP_QUEUE_HEAD_NEXT_TERMINATE;
++ epctrlx = readl (&udc->op_regs->epctrlx[0]);
++ if (i)
++ {
++ epctrlx |= EPCTRL_TX_ENABLE
++ | (USB_ENDPOINT_XFER_CONTROL << EPCTRL_TX_EP_TYPE_SHIFT);
++ }
++ else
++ {
++ epctrlx |= EPCTRL_RX_ENABLE
++ | (USB_ENDPOINT_XFER_CONTROL << EPCTRL_RX_EP_TYPE_SHIFT);
++ }
++ writel (epctrlx, &udc->op_regs->epctrlx[0]);
++ }
++}
++
++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 2 "reorder_fields" } } */
+diff --git a/gcc/testsuite/gcc.dg/struct/dfe_extr_tcp_usrreq.c b/gcc/testsuite/gcc.dg/struct/dfe_extr_tcp_usrreq.c
+new file mode 100644
+index 000000000..bddd862fe
+--- /dev/null
++++ b/gcc/testsuite/gcc.dg/struct/dfe_extr_tcp_usrreq.c
+@@ -0,0 +1,58 @@
++/* { dg-do compile} */
++
++#define NULL ((void*)0)
++typedef unsigned long size_t;
++typedef long intptr_t;
++typedef unsigned long uintptr_t;
++typedef long scalar_t__;
++typedef int bool;
++#define false 0
++#define true 1
++
++struct tcpcb
++{
++ int t_state;
++};
++
++struct socket
++{
++ int dummy;
++};
++
++struct proc
++{
++ int dummy;
++};
++
++struct inpcb
++{
++ scalar_t__ inp_lport;
++};
++
++int COMMON_END (int);
++int COMMON_START ();
++int PRU_LISTEN;
++int TCPS_LISTEN;
++int in_pcbbind (struct inpcb *, int *, struct proc *);
++struct inpcb* sotoinpcb (struct socket *);
++
++__attribute__((used)) static void
++tcp_usr_listen (struct socket *so, struct proc *p)
++{
++ int error = 0;
++ struct inpcb *inp = sotoinpcb (so);
++ struct tcpcb *tp;
++
++ COMMON_START ();
++ if (inp->inp_lport == 0)
++ {
++ error = in_pcbbind (inp, NULL, p);
++ }
++ if (error == 0)
++ {
++ tp->t_state = TCPS_LISTEN;
++ }
++ COMMON_END (PRU_LISTEN);
++}
++
++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 1 "reorder_fields" } } */
+diff --git a/gcc/testsuite/gcc.dg/struct/dfe_extr_ui_main.c b/gcc/testsuite/gcc.dg/struct/dfe_extr_ui_main.c
+new file mode 100644
+index 000000000..1a06f5eec
+--- /dev/null
++++ b/gcc/testsuite/gcc.dg/struct/dfe_extr_ui_main.c
+@@ -0,0 +1,61 @@
++/* { dg-do compile} */
++
++#define NULL ((void*)0)
++typedef unsigned long size_t;
++typedef long intptr_t;
++typedef unsigned long uintptr_t;
++typedef long scalar_t__;
++typedef int bool;
++#define false 0
++#define true 1
++
++typedef struct TYPE_4__ TYPE_2__;
++typedef struct TYPE_3__ TYPE_1__;
++
++struct TYPE_4__
++{
++ size_t modCount;
++ TYPE_1__ *modList;
++};
++
++struct TYPE_3__
++{
++ void *modDescr;
++ void *modName;
++};
++
++size_t MAX_MODS;
++void *String_Alloc (char *);
++int test_strlen (char *);
++int trap_FD_GetFileList (char *, char *, char *, int);
++TYPE_2__ uiInfo;
++
++__attribute__((used)) static void
++UI_LoadMods ()
++{
++ int numdirs;
++ char dirlist[2048];
++ char *dirptr;
++ char *descptr;
++ int i;
++ int dirlen;
++
++ uiInfo.modCount = 0;
++ numdirs = trap_FD_GetFileList ("$modelist", "", dirlist, sizeof (dirlist));
++ dirptr = dirlist;
++ for (i = 0; i < numdirs; i++)
++ {
++ dirlen = test_strlen (dirptr) + 1;
++ descptr = dirptr + dirlen;
++ uiInfo.modList[uiInfo.modCount].modName = String_Alloc (dirptr);
++ uiInfo.modList[uiInfo.modCount].modDescr = String_Alloc (descptr);
++ dirptr += dirlen + test_strlen (descptr) + 1;
++ uiInfo.modCount++;
++ if (uiInfo.modCount >= MAX_MODS)
++ {
++ break;
++ }
++ }
++}
++
++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 1 "reorder_fields" } } */
+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..94eb88d5c
+--- /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 "reorder_fields" } } */
+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..bbf9420d0
+--- /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 "reorder_fields" } } */
+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..f706db968
+--- /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 "reorder_fields" } } */
+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..963295cb4
+--- /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 "reorder_fields" } } */
+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..aa10506a1
+--- /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 "reorder_fields" } } */
+diff --git a/gcc/testsuite/gcc.dg/struct/struct-reorg.exp b/gcc/testsuite/gcc.dg/struct/struct-reorg.exp
+index 5a476e8f9..6ccb753b5 100644
+--- a/gcc/testsuite/gcc.dg/struct/struct-reorg.exp
++++ b/gcc/testsuite/gcc.dg/struct/struct-reorg.exp
+@@ -43,6 +43,10 @@ gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/csr_*.c]] \
+ gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/rf_*.c]] \
+ "" "-fipa-reorder-fields -fdump-ipa-all -flto-partition=one -fwhole-program"
+
++# -fipa-struct-reorg=3
++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/dfe*.c]] \
++ "" "-fipa-reorder-fields -fipa-struct-reorg=3 -fdump-ipa-all -flto-partition=one -fwhole-program"
++
+ # All done.
+ torture-finish
+ dg-finish
+diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_escape_replace_type.c b/gcc/testsuite/gcc.dg/struct/wo_prof_escape_replace_type.c
+new file mode 100644
+index 000000000..fa8c66b9e
+--- /dev/null
++++ b/gcc/testsuite/gcc.dg/struct/wo_prof_escape_replace_type.c
+@@ -0,0 +1,49 @@
++/* { dg-do compile } */
++
++#include <stdlib.h>
++
++struct AngleDef
++{
++ double K;
++ double th0;
++};
++typedef struct AngleDef angldef;
++
++struct bndangdihe
++{
++ int nbond;
++ int nangl;
++ int ndihe;
++};
++typedef struct bndangdihe bah;
++
++struct ambprmtop
++{
++ double *AnglK;
++ double *AnglEq;
++ bah nBAH;
++ angldef *AParam;
++ char source[512];
++ char eprulesource[512];
++};
++typedef struct ambprmtop prmtop;
++
++static void OrderBondParameters (prmtop *tp)
++{
++ int i;
++ tp->AParam = (angldef *)malloc (tp->nBAH.nangl * sizeof (angldef));
++ for (i = 0; i < tp->nBAH.nangl; i++)
++ {
++ tp->AParam[i].K = tp->AnglK[i];
++ tp->AParam[i].th0 = tp->AnglEq[i];
++ }
++}
++
++void main ()
++{
++ prmtop *tp = (prmtop *)malloc (100 * sizeof (prmtop));
++ OrderBondParameters (tp);
++}
++
++/*---------------------------------------------------------------------------------------------*/
++/* { dg-final { scan-ipa-dump "No structures to transform" "struct_reorg" } } */
+--
+2.33.0
+