Re: [PATCH 1/8 v4] Dead-field warning in structs at LTO-time

2020-12-10 Thread Erick Ochoa




On 10/12/2020 18:39, David Malcolm wrote:

On Fri, 2020-12-04 at 10:58 +0100, Erick Ochoa wrote:

+ // Anonymous fields? (Which the record can be!).
+   warning (OPT_Wdfa, "RECORD_TYPE %qE has dead field %qE in LTO.\n",
+   record, field);


Others have pointed out that -Wdfa isn't a good name for the warning, I
like their suggestions.

A few other nitpicks on this:

- "RECORD_TYPE" is an implementation detail of GCC.  Diagnostics should
be worded in terms of the user’s source code, and the source language,
rather than GCC’s own implementation details.

- "dead field" feels like jargon to me.

How about:
   field 'foo' in 'struct bar' is never used [-Wunused-field]
or somesuch?

- The "in LTO" in the message seems like a redundant implementation
detail to me.

- "warning" will implicitly use the global "input_location" as the
location of the diagnostic.  Better would be to use "warning_at" with
the location of the field's declaration.  I think you can get this via
DECL_SOURCE_LOCATION () on the FIELD_DECL.


See also:
   https://gcc.gnu.org/onlinedocs/gccint/Guidelines-for-Diagnostics.html



Thank you everyone for your input. I will change this in the next 
version of the patchset. I am already fixing some errors I found during 
the weekend.


I originally avoided the printing the field name because I believe that 
some fields may be anonymous and I was unsure on how to print them.


I also avoided to use warning_at because originally I didn't know where 
the location for the warning would be appropriate. (In the declaration 
of the structure? What if there are writes to the field but never reads? 
Currently these are marked as dead as well.)


"In LTO" is added in the warning because at the source level, if one 
were to remove the field from the declaration and compile, there might 
be compile time errors because dead code elimination has not yet been 
run and there might be references to these fields. (They're only truly 
dead after dead code elimination.)


At the moment, my next step will be to review the guidelines for 
diagnostics and think about how to improve the current diagnostic. If 
you have more suggestions, please do let me know!


-Erick




Hope this is constructive
Dave



[PATCH 8/8 v4] The Great STL migration

2020-12-04 Thread Erick Ochoa



---
 gcc/ipa-dfe.c  | 262 +++---
 gcc/ipa-dfe.h  | 108 +++---
 gcc/ipa-field-reorder.c| 134 +++
 gcc/ipa-type-escape-analysis.c | 636 -
 gcc/ipa-type-escape-analysis.h | 160 -
 5 files changed, 643 insertions(+), 657 deletions(-)

diff --git a/gcc/ipa-dfe.c b/gcc/ipa-dfe.c
index 7ab718c3628..98427e8e423 100644
--- a/gcc/ipa-dfe.c
+++ b/gcc/ipa-dfe.c
@@ -129,31 +129,31 @@ along with GCC; see the file COPYING3.  If not see
  * Find all non_escaping types which point to RECORD_TYPEs in
  * record_field_offset_map.
  */
-std::set
-get_all_types_pointing_to (record_field_offset_map_t 
record_field_offset_map,

-  tpartitions_t casting)
+void
+get_all_types_pointing_to (record_field_offset_map4_t 
_field_offset_map2,

+  tpartitions2_t casting,
+  hash_set _modify2)
 {
-  const tset_t _escaping = casting.non_escaping;
+  tset2_t _escaping = casting.non_escaping;
 -  std::set specific_types;
   type_stringifier stringifier;
+  hash_set specific_types2;
// Here we are just placing the types of interest in a set.
-  for (std::map::const_iterator i
-   = record_field_offset_map.begin (),
-   e = record_field_offset_map.end ();
+  for (hash_map::iterator i
+   = record_field_offset_map2.begin (),
+   e = record_field_offset_map2.end ();
i != e; ++i)
 {
-  tree record = i->first;
-  std::string name = stringifier.stringify (record);
-  specific_types.insert (record);
+  tree record = (*i).first;
+  specific_types2.add (record);
 }
 -  specific_type_collector specifier (specific_types);
+  specific_type_collector specifier (_types2);
// SpecificTypeCollector will collect all types which point to the 
types in

   // the set.
-  for (std::set::const_iterator i = non_escaping.begin (),
+  for (auto i = non_escaping.begin (),
e = non_escaping.end ();
i != e; ++i)
 {
@@ -162,8 +162,11 @@ get_all_types_pointing_to 
(record_field_offset_map_t record_field_offset_map,

 }
// These are all the types which need modifications.
-  std::set to_modify = specifier.get_set ();
-  return to_modify;
+  hash_set to_modify = specifier.get_set2 ();
+  for (hash_set::iterator i = to_modify.begin(), e = 
to_modify.end(); i != e; ++i)

+  {
+to_modify2.add (*i);
+  }
 }
  /* record_field_offset_map holds information on which FIELD_DECLs 
might be
@@ -180,13 +183,13 @@ get_all_types_pointing_to 
(record_field_offset_map_t record_field_offset_map,

  * The second maps old FIELD_DECLs trees to the new FIELD_DECLs.
  */
 reorg_maps_t
-get_types_replacement (record_field_offset_map_t record_field_offset_map,
-  std::set to_modify)
+get_types_replacement (record_field_offset_map4_t 
_field_offset_map2,
+		   hash_set _modify, reorg_record_map2_t , 
reorg_field_map2_t _map2)

 {
   type_stringifier stringifier;
 -  type_reconstructor reconstructor (record_field_offset_map, "reorg");
-  for (std::set::const_iterator i = to_modify.begin (),
+  type_reconstructor reconstructor (record_field_offset_map2, "reorg", 
map2, field_map2);

+  for (hash_set::iterator i = to_modify.begin (),
e = to_modify.end ();
i != e; ++i)
 {
@@ -194,7 +197,7 @@ get_types_replacement (record_field_offset_map_t 
record_field_offset_map,

   reconstructor.walk (TYPE_MAIN_VARIANT (record));
 }
 -  for (std::set::const_iterator i = to_modify.begin (),
+  for (hash_set::iterator i = to_modify.begin (),
e = to_modify.end ();
i != e; ++i)
 {
@@ -202,20 +205,17 @@ get_types_replacement (record_field_offset_map_t 
record_field_offset_map,

   reconstructor.walk (record);
 }
 -  reorg_record_map_t map = reconstructor.get_map ();
-  reorg_field_map_t field_map = reconstructor.get_field_map ();
-
   // Here, we are just making sure that we are not doing anything too 
crazy.

   // Also, we found some types for which TYPE_CACHED_VALUES_P is not being
   // rewritten.  This is probably indicative of a bug in 
TypeReconstructor.

-  for (std::map::const_iterator i = map.begin (),
- e = map.end ();
+  for (hash_map::iterator i = map2.begin (),
+ e = map2.end ();
i != e; ++i)
 {
-  tree o_record = i->first;
+  tree o_record = (*i).first;
   std::string o_name = stringifier.stringify (o_record);
   log ("original: %s\n", o_name.c_str ());
-  tree r_record = i->second;
+  tree r_record = (*i).second;
   std::string r_name
= r_record ? stringifier.stringify (r_record) : std::string ("");
   log ("modified: %s\n", r_name.c_str ());
@@ -227,16 +227,17 @@ get_types_replacement (record_field_offset_map_t 

[PATCH 7/8 v4] Add tests

2020-12-04 Thread Erick Ochoa



---
 gcc/common.opt|  4 ++
 gcc/ipa-type-escape-analysis.c| 11 +
 .../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   | 32 ++
 gcc/testsuite/gcc.dg/ipa/ipa-ea-17-malloc-0.c | 23 ++
 .../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 | 19 
 .../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| 16 +++
 .../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 

[PATCH 6/8 v4] Add heuristic to take into account void* pattern.

2020-12-04 Thread Erick Ochoa



We add a heuristic in order to be able to transform functions which
receive void* arguments as a way to generalize over arguments. An
example of this is qsort. The heuristic works by first inspecting
leaves in the call graph. If the leaves only contain a reference
to a single RECORD_TYPE then we color the nodes in the call graph
as "casts are safe in this function and does not call external
visible functions". We propagate this property up the callgraph
until a fixed point is reached. This will later be changed to
use ipa-modref.

2020-11-04  Erick Ochoa  

* ipa-type-escape-analysis.c : Add new heuristic.
* ipa-field-reorder.c : Use heuristic.
* ipa-type-escape-analysis.h : Change signatures.
---
 gcc/ipa-field-reorder.c|   3 +-
 gcc/ipa-type-escape-analysis.c | 193 +++--
 gcc/ipa-type-escape-analysis.h |  78 +++--
 3 files changed, 259 insertions(+), 15 deletions(-)

diff --git a/gcc/ipa-field-reorder.c b/gcc/ipa-field-reorder.c
index 633a5a7cedc..70d26d71324 100644
--- a/gcc/ipa-field-reorder.c
+++ b/gcc/ipa-field-reorder.c
@@ -588,8 +588,9 @@ lto_fr_execute ()
   log ("here in field reordering \n");
   // Analysis.
   detected_incompatible_syntax = false;
+  std::map whitelisted = get_whitelisted_nodes();
   tpartitions_t escaping_nonescaping_sets
-= partition_types_into_escaping_nonescaping ();
+= partition_types_into_escaping_nonescaping (whitelisted);
   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,
diff --git a/gcc/ipa-type-escape-analysis.c b/gcc/ipa-type-escape-analysis.c
index 970b74630dd..48d8dc2bcd8 100644
--- a/gcc/ipa-type-escape-analysis.c
+++ b/gcc/ipa-type-escape-analysis.c
@@ -104,6 +104,7 @@ along with GCC; see the file COPYING3.  If not see
 #include 
 #include 
 #include 
+#include 
  #include "config.h"
 #include "system.h"
@@ -249,6 +250,99 @@ lto_dfe_execute ()
   return 0;
 }
 +/* Heuristic to determine if casting is allowed in a function.
+ * This heuristic attempts to allow casting in functions which follow the
+ * pattern where a struct pointer or array pointer is casted to void* 
or + * char*.  The heuristic works as follows:

+ *
+ * There is a simple per-function analysis that determines whether there
+ * is more than 1 type of struct referenced in the body of the method.
+ * If there is more than 1 type of struct referenced in the body,
+ * then the layout of the structures referenced within the body
+ * cannot be casted.  However, if there's only one type of struct 
referenced

+ * in the body of the function, casting is allowed in the function itself.
+ * The logic behind this is that the if the code follows good programming
+ * practices, the only way the memory should be accessed is via a singular
+ * type. There is also another requisite to this per-function analysis, and
+ * that is that the function can only call colored functions or functions
+ * which are available in the linking unit.
+ *
+ * Using this per-function analysis, we then start coloring leaf nodes 
in the
+ * call graph as ``safe'' or ``unsafe''.  The color is propagated to 
the + * callers of the functions until a fixed point is reached.

+ */
+std::map
+get_whitelisted_nodes ()
+{
+  cgraph_node *node = NULL;
+  std::set nodes;
+  std::set leaf_nodes;
+  std::set leaf_nodes_decl;
+  FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
+  {
+node->get_untransformed_body ();
+nodes.insert(node);
+if (node->callees) continue;
+
+leaf_nodes.insert (node);
+leaf_nodes_decl.insert (node->decl);
+  }
+
+  std::queue worklist;
+  for (std::set::iterator i = leaf_nodes.begin (),
+e = leaf_nodes.end (); i != e; ++i)
+  {
+if (dump_file) fprintf (dump_file, "is a leaf node %s\n", 
(*i)->name ());

+worklist.push (*i);
+  }
+
+  for (std::set::iterator i = nodes.begin (),
+e = nodes.end (); i != e; ++i)
+  {
+worklist.push (*i);
+  }
+
+  std::map map;
+  while (!worklist.empty ())
+  {
+
+if (detected_incompatible_syntax) return map;
+cgraph_node *i = worklist.front ();
+worklist.pop ();
+if (dump_file) fprintf (dump_file, "analyzing %s %p\n", i->name (), 
(void*)i);

+gimple_white_lister whitelister;
+whitelister._walk_cnode (i);
+bool no_external = whitelister.does_not_call_external_functions (i, 
map);

+bool before_in_map = map.find (i->decl) != map.end ();
+bool place_callers_in_worklist = !before_in_map;
+if (!before_in_map)
+{
+  map.insert(std::pair(i->decl, no_external));
+} else
+{
+  map[i->decl] = no_external;
+}
+bool previous_value = map[i->decl];
+place_callers_in_worklist |= previous_value != no_external;
+if (previous_value != no_external)
+{
+   // This ensures we are having a tota

[PATCH 5/8 v4] Abort if Gimple from C++ or Fortran sources is found.

2020-12-04 Thread Erick Ochoa



2020-11-04  Erick Ochoa  

* ipa-field-reorder: Add flag to exit transformation.
* ipa-type-escape-analysis: Same.
---
 gcc/ipa-field-reorder.c|  3 +-
 gcc/ipa-type-escape-analysis.c | 54 --
 gcc/ipa-type-escape-analysis.h |  2 ++
 3 files changed, 49 insertions(+), 10 deletions(-)

diff --git a/gcc/ipa-field-reorder.c b/gcc/ipa-field-reorder.c
index e1094efe934..633a5a7cedc 100644
--- a/gcc/ipa-field-reorder.c
+++ b/gcc/ipa-field-reorder.c
@@ -587,6 +587,7 @@ lto_fr_execute ()
 {
   log ("here in field reordering \n");
   // Analysis.
+  detected_incompatible_syntax = false;
   tpartitions_t escaping_nonescaping_sets
 = partition_types_into_escaping_nonescaping ();
   record_field_map_t record_field_map = find_fields_accessed ();
@@ -594,7 +595,7 @@ lto_fr_execute ()
 = obtain_nonescaping_unaccessed_fields (escaping_nonescaping_sets,
record_field_map, 0);
 -  if (record_field_offset_map.empty ())
+  if (detected_incompatible_syntax || record_field_offset_map.empty ())
 return 0;
// Prepare for transformation.
diff --git a/gcc/ipa-type-escape-analysis.c b/gcc/ipa-type-escape-analysis.c
index f142b6e51ca..970b74630dd 100644
--- a/gcc/ipa-type-escape-analysis.c
+++ b/gcc/ipa-type-escape-analysis.c
@@ -171,6 +171,10 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-type-escape-analysis.h"
 #include "ipa-dfe.h"
 +#define ABORT_IF_NOT_C true
+
+bool detected_incompatible_syntax = false;
+
 // Main function that drives dfe.
 static unsigned int
 lto_dfe_execute ();
@@ -262,13 +266,15 @@ lto_dead_field_elimination ()
 if (cnode->inlined_to) continue;
 cnode->get_body();
   }
+
+  detected_incompatible_syntax = false;
   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, OPT_Wdfa);
-  if (record_field_offset_map.empty ())
+  if (detected_incompatible_syntax || record_field_offset_map.empty ())
 return;
  // Prepare for transformation.
@@ -588,6 +594,7 @@ type_walker::_walk (tree type)
   // Improve, verify that having a type is an invariant.
   // I think there was a specific example which didn't
   // allow for it
+  if (detected_incompatible_syntax) return;
   if (!type)
 return;
 @@ -641,9 +648,9 @@ type_walker::_walk (tree type)
 case POINTER_TYPE:
   this->walk_POINTER_TYPE (type);
   break;
-case REFERENCE_TYPE:
-  this->walk_REFERENCE_TYPE (type);
-  break;
+//case REFERENCE_TYPE:
+//  this->walk_REFERENCE_TYPE (type);
+//  break;
 case ARRAY_TYPE:
   this->walk_ARRAY_TYPE (type);
   break;
@@ -653,18 +660,24 @@ type_walker::_walk (tree type)
 case FUNCTION_TYPE:
   this->walk_FUNCTION_TYPE (type);
   break;
-case METHOD_TYPE:
-  this->walk_METHOD_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 REFERENCE_TYPE:
+case METHOD_TYPE:
 case QUAL_UNION_TYPE:
 case LANG_TYPE:
 default:
   {
log ("missing %s\n", get_tree_code_name (code));
+#ifdef ABORT_IF_NOT_C
+   detected_incompatible_syntax = true;
+#else
gcc_unreachable ();
+#endif
   }
   break;
 }
@@ -847,6 +860,7 @@ type_walker::_walk_arg (tree t)
 void
 expr_walker::walk (tree e)
 {
+  if (detected_incompatible_syntax) return;
   _walk_pre (e);
   _walk (e);
   _walk_post (e);
@@ -931,7 +945,11 @@ expr_walker::_walk (tree e)
 default:
   {
log ("missing %s\n", get_tree_code_name (code));
+#ifdef ABORT_IF_NOT_C
+   detected_incompatible_syntax = true;
+#else
gcc_unreachable ();
+#endif
   }
   break;
 }
@@ -1164,6 +1182,7 @@ gimple_walker::walk ()
   cgraph_node *node = NULL;
   FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
 {
+  if (detected_incompatible_syntax) return;
   node->get_untransformed_body ();
   tree decl = node->decl;
   gcc_assert (decl);
@@ -1410,7 +1429,11 @@ gimple_walker::_walk_gimple (gimple *stmt)
   // Break if something is unexpected.
   const char *name = gimple_code_name[code];
   log ("gimple code name %s\n", name);
+#ifdef ABORT_IF_NOT_C
+  detected_incompatible_syntax = true;
+#else
   gcc_unreachable ();
+#endif
 }
  void
@@ -2960,6 +2983,8 @@ type_stringifier::stringify (tree t)
 return std::string ("");
   _stringification.clear ();
   gcc_assert (t);
+  if (detected_incompatible_syntax)
+return

[PATCH 4/8 v4] Add documentation for dead field elimination

2020-12-04 Thread Erick Ochoa



2020-11-04  Erick Ochoa  

* Makefile.in: Add file to documentation sources.
* doc/dfe.texi: New section.
* doc/gccint.texi: Include new section.
---
 gcc/Makefile.in |   3 +-
 gcc/doc/dfe.texi| 187 
 gcc/doc/gccint.texi |   2 +
 3 files changed, 191 insertions(+), 1 deletion(-)
 create mode 100644 gcc/doc/dfe.texi

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 2184bd0fc3d..7e4c442416d 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -3275,7 +3275,8 @@ TEXI_GCCINT_FILES = gccint.texi gcc-common.texi 
gcc-vers.texi		\

 gnu.texi gpl_v3.texi fdl.texi contrib.texi languages.texi  \
 sourcebuild.texi gty.texi libgcc.texi cfg.texi tree-ssa.texi   \
 loop.texi generic.texi gimple.texi plugins.texi optinfo.texi   \
-match-and-simplify.texi analyzer.texi ux.texi poly-int.texi
+match-and-simplify.texi analyzer.texi ux.texi poly-int.texi\
+dfe.texi
  TEXI_GCCINSTALL_FILES = install.texi install-old.texi fdl.texi
\
 gcc-common.texi gcc-vers.texi
diff --git a/gcc/doc/dfe.texi b/gcc/doc/dfe.texi
new file mode 100644
index 000..e8d01d817d3
--- /dev/null
+++ b/gcc/doc/dfe.texi
@@ -0,0 +1,187 @@
+@c Copyright (C) 2001 Free Software Foundation, Inc.
+@c This is part of the GCC manual.
+@c For copying conditions, see the file gcc.texi.
+
+@node Dead Field Elimination
+@chapter Dead Field Elimination
+
+@node Dead Field Elimination Internals
+@section Dead Field Elimination Internals
+
+@subsection Introduction
+
+Dead field elimination is a compiler transformation that removes fields 
from structs. There are several challenges to removing fields from 
structs at link time but, depending on the workload of the compiled 
program and the architecture where the program runs, dead field 
elimination might be a worthwhile transformation to apply. Generally 
speaking, when the bottle-neck of an application is given by the memory 
bandwidth of the host system and the memory requested is of a struct 
which can be reduced in size, then that combination of workload, program 
and architecture can benefit from applying dead field elimination. The 
benefits come from removing unnecessary fields from structures and thus 
reducing the memory/cache requirements to represent a structure.  +

+ +
+While challenges exist to fully automate a dead field elimination 
transformation, similar and more powerful optimizations have been 
implemented in the past. Chakrabarti et al [0] implement struct peeling, 
splitting into hot and cold parts of a structure, and field reordering. 
Golovanevsky et al [1] also shows efforts to implement data layout 
optimizations at link time. Unlike the work of Chakrabarti and 
Golovanesky, this text only talks about dead field elimination. This 
doesn't mean that the implementation can't be expanded to perform other 
link-time layout optimizations, it just means that dead field 
elimination is the only transformation that is implemented at the time 
of this writing. +
+[0] Chakrabarti, Gautam, Fred Chow, and L. PathScale. "Structure layout 
optimizations in the open64 compiler: Design, implementation and 
measurements." Open64 Workshop at the International Symposium on Code 
Generation and Optimization. 2008.  +
+[1] Golovanevsky, Olga, and Ayal Zaks. "Struct-reorg: current status 
and future perspectives." Proceedings of the GCC Developers’ Summit. 
2007.  +

+@subsection Overview
+
+The dead field implementation is structured in the following way:  +
+ +@itemize @bullet
+@item
+Collect all types which can refer to a @code{RECORD_TYPE}. This means 
that if we have a pointer to a record, we also collect this pointer. Or 
an array, or a union. +@item

+Mark types as escaping. More of this in the following section.  +@item
+Find fields which can be deleted. (Iterate over all gimple code and 
find which fields are read.)  +@item
+Create new types with removed fields (and reference these types in 
pointers, arrays, etc.)  +@item

+Modify gimple to include these types.  +@end itemize
+
+
+Most of this code relies on the visitor pattern. Types, Expr, and 
Gimple statements are visited using this pattern. You can find the base 
classes in @file{type-walker.c} @file{expr-walker.c} and 
@file{gimple-walker.c}. There are assertions in place where a type, 
expr, or gimple code is encountered which has not been encountered 
before during the testing of this transformation. This facilitates 
fuzzying of the transformation.

+
+@subsubsection Implementation Details: Is a global variable escaping?
+
+How does the analysis determine whether a global variable is visible to 
code outside the current linking unit? In the file 
@file{gimple-escaper.c} we have a simple function called 
@code{is_variable_escaping} which checks whether a variable is visible 
to code outside the current linking unit by looking at the 
@code{varpool_node}’s @code{exter

[PATCH 3/8 v4] Add Field Reordering

2020-12-04 Thread Erick Ochoa



Field reordering of structs at link-time

2020-11-04  Erick Ochoa  

* Makefile.in: Add new file to list of sources.
* common.opt: Add new flag for field reordering.
* passes.def: Add new pass.
* tree-pass.h: Same.
* ipa-field-reorder.c: New file.
* ipa-type-escape-analysis.c: Export common functions.
* ipa-type-escape-analysis.h: Same.
---
 gcc/Makefile.in|   1 +
 gcc/common.opt |   4 +
 gcc/ipa-dfe.c  |  86 -
 gcc/ipa-dfe.h  |  26 +-
 gcc/ipa-field-reorder.c| 622 +
 gcc/ipa-type-escape-analysis.c |  44 ++-
 gcc/ipa-type-escape-analysis.h |  12 +-
 gcc/passes.def |   1 +
 gcc/tree-pass.h|   2 +
 9 files changed, 749 insertions(+), 49 deletions(-)
 create mode 100644 gcc/ipa-field-reorder.c

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 8ef6047870b..2184bd0fc3d 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1417,6 +1417,7 @@ OBJS = \
internal-fn.o \
ipa-type-escape-analysis.o \
ipa-dfe.o \
+   ipa-field-reorder.o \
ipa-cp.o \
ipa-sra.o \
ipa-devirt.o \
diff --git a/gcc/common.opt b/gcc/common.opt
index 85351738a29..7885d0f5c0c 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -3468,4 +3468,8 @@ Wdfa
 Common Var(warn_dfa) Init(1) Warning
 Warn about dead fields at link time.
 +fipa-field-reorder
+Common Report Var(flag_ipa_field_reorder) Optimization
+Reorder fields.
+
 ; This comment is to ensure we retain the blank line above.
diff --git a/gcc/ipa-dfe.c b/gcc/ipa-dfe.c
index 7c5e81bd6ac..7ab718c3628 100644
--- a/gcc/ipa-dfe.c
+++ b/gcc/ipa-dfe.c
@@ -185,7 +185,7 @@ get_types_replacement (record_field_offset_map_t 
record_field_offset_map,

 {
   type_stringifier stringifier;
 -  type_reconstructor reconstructor (record_field_offset_map);
+  type_reconstructor reconstructor (record_field_offset_map, "reorg");
   for (std::set::const_iterator i = to_modify.begin (),
e = to_modify.end ();
i != e; ++i)
@@ -245,9 +245,9 @@ get_types_replacement (record_field_offset_map_t 
record_field_offset_map,

  */
 void
 substitute_types_in_program (reorg_record_map_t map,
-reorg_field_map_t field_map)
+reorg_field_map_t field_map, bool _delete)
 {
-  gimple_type_rewriter rewriter (map, field_map);
+  gimple_type_rewriter rewriter (map, field_map, _delete);
   rewriter.walk ();
   rewriter._rewrite_function_decl ();
 }
@@ -361,8 +361,11 @@ type_reconstructor::set_is_not_modified_yet (tree t)
 return;
tree type = _reorg_map[tt];
-  const bool is_modified
+  bool is_modified
 = strstr (type_stringifier::get_type_identifier (type).c_str (), 
".reorg");

+  is_modified
+|= (bool) strstr (type_stringifier::get_type_identifier 
(type).c_str (),

+ ".reorder");
   if (!is_modified)
 return;
 @@ -408,14 +411,20 @@ type_reconstructor::is_memoized (tree t)
   return already_changed;
 }
 -static tree
-get_new_identifier (tree type)
+const char *
+type_reconstructor::get_new_suffix ()
+{
+  return _suffix;
+}
+
+tree
+get_new_identifier (tree type, const char *suffix)
 {
   const char *identifier = type_stringifier::get_type_identifier 
(type).c_str ();

-  const bool is_new_type = strstr (identifier, "reorg");
+  const bool is_new_type = strstr (identifier, suffix);
   gcc_assert (!is_new_type);
   char *new_name;
-  asprintf (_name, "%s.reorg", identifier);
+  asprintf (_name, "%s.%s", identifier, suffix);
   return get_identifier (new_name);
 }
 @@ -471,7 +480,9 @@ type_reconstructor::_walk_ARRAY_TYPE_post (tree t)
   TREE_TYPE (copy) = build_variant_type_copy (TREE_TYPE (copy));
   copy = is_modified ? build_distinct_type_copy (copy) : copy;
   TREE_TYPE (copy) = is_modified ? _reorg_map[TREE_TYPE (t)] : 
TREE_TYPE (copy);
-  TYPE_NAME (copy) = is_modified ? get_new_identifier (copy) : 
TYPE_NAME (copy);

+  TYPE_NAME (copy) = is_modified
+  ? get_new_identifier (copy, this->get_new_suffix ())
+  : TYPE_NAME (copy);
   // This is useful so that we go again through type layout
   TYPE_SIZE (copy) = is_modified ? NULL : TYPE_SIZE (copy);
   tree domain = TYPE_DOMAIN (t);
@@ -524,7 +535,9 @@ type_reconstructor::_walk_POINTER_TYPE_post (tree t)
copy = is_modified ? build_variant_type_copy (copy) : copy;
   TREE_TYPE (copy) = is_modified ? _reorg_map[TREE_TYPE (t)] : 
TREE_TYPE (copy);
-  TYPE_NAME (copy) = is_modified ? get_new_identifier (copy) : 
TYPE_NAME (copy);

+  TYPE_NAME (copy) = is_modified
+  ? get_new_identifier (copy, this->get_new_suffix ())
+  : TYPE_NAME (copy);
   TYPE_CACHED_VALUES_P (copy) = false;
tree _t = tree_to_tree (t);
@@ -619,7 +632,8 @@ type_reconstructor::_walk

[PATCH 2/8 v4] Add Dead Field Elimination

2020-12-04 Thread Erick Ochoa



Using the Dead Field Analysis, Dead Field Elimination
automatically transforms gimple to eliminate fields that
are never read.

2020-11-04  Erick Ochoa  

* Makefile.in: Add file to list of sources.
* ipa-dfe.c: New.
* ipa-dfe.h: Same.
* ipa-type-escape-analysis.h: Export code used in dfe.
* ipa-type-escape-analysis.c: Call transformation.
---
 gcc/Makefile.in|1 +
 gcc/ipa-dfe.c  | 1284 
 gcc/ipa-dfe.h  |  247 ++
 gcc/ipa-type-escape-analysis.c |   24 +-
 gcc/ipa-type-escape-analysis.h |   14 +-
 5 files changed, 1557 insertions(+), 13 deletions(-)
 create mode 100644 gcc/ipa-dfe.c
 create mode 100644 gcc/ipa-dfe.h

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 8b18c9217a2..8ef6047870b 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1416,6 +1416,7 @@ OBJS = \
init-regs.o \
internal-fn.o \
ipa-type-escape-analysis.o \
+   ipa-dfe.o \
ipa-cp.o \
ipa-sra.o \
ipa-devirt.o \
diff --git a/gcc/ipa-dfe.c b/gcc/ipa-dfe.c
new file mode 100644
index 000..7c5e81bd6ac
--- /dev/null
+++ b/gcc/ipa-dfe.c
@@ -0,0 +1,1284 @@
+/* IPA Type Escape Analysis and Dead Field Elimination
+   Copyright (C) 2019-2020 Free Software Foundation, Inc.
+
+  Contributed by Erick Ochoa 
+
+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 elimination (IPA-DFE)
+
+   The goal of this transformation is to
+
+   1) Create new types to replace RECORD_TYPEs which hold dead fields.
+   2) Substitute instances of old RECORD_TYPEs for new RECORD_TYPEs.
+   3) Substitute instances of old FIELD_DECLs for new FIELD_DECLs.
+   4) Fix some instances of pointer arithmetic.
+   5) Relayout where needed.
+
+   First stage - DFA
+   =
+
+   Use DFA to compute the set of FIELD_DECLs which can be deleted.
+
+   Second stage - Reconstruct Types
+   
+
+   This stage is done by two family of classes, the SpecificTypeCollector
+   and the TypeReconstructor.
+
+   The SpecificTypeCollector collects all TYPE_P trees which point to
+   RECORD_TYPE trees returned by DFA.  The TypeReconstructor will create
+   new RECORD_TYPE trees and new TYPE_P trees replacing the old RECORD_TYPE
+   trees with the new RECORD_TYPE trees.
+
+   Third stage - Substitute Types and Relayout
+   ===
+
+   This stage is handled by ExprRewriter and GimpleRewriter.
+   Some pointer arithmetic is fixed here to take into account those 
eliminated

+   FIELD_DECLS.
+ */
+
+#include "config.h"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#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"

[PATCH 1/8 v4] Dead-field warning in structs at LTO-time

2020-12-04 Thread Erick Ochoa



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  

* Makefile.in: Add file to list of new sources.
* common.opt: Add new flags.
* ipa-type-escape-analysis.c: New file.
---
 gcc/Makefile.in|1 +
 gcc/common.opt |8 +
 gcc/ipa-type-escape-analysis.c | 3428 
 gcc/ipa-type-escape-analysis.h | 1152 +++
 gcc/passes.def |1 +
 gcc/timevar.def|1 +
 gcc/tree-pass.h|2 +
 7 files changed, 4593 insertions(+)
 create mode 100644 gcc/ipa-type-escape-analysis.c
 create mode 100644 gcc/ipa-type-escape-analysis.h

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 978a08f7b04..8b18c9217a2 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1415,6 +1415,7 @@ OBJS = \
incpath.o \
init-regs.o \
internal-fn.o \
+   ipa-type-escape-analysis.o \
ipa-cp.o \
ipa-sra.o \
ipa-devirt.o \
diff --git a/gcc/common.opt b/gcc/common.opt
index d4cbb2f86a5..85351738a29 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -3460,4 +3460,12 @@ fipa-ra
 Common Report Var(flag_ipa_ra) Optimization
 Use caller save register across calls if possible.
 +fipa-type-escape-analysis
+Common Report Var(flag_ipa_type_escape_analysis) Optimization
+This flag is only used for debugging the type escape analysis
+
+Wdfa
+Common Var(warn_dfa) Init(1) Warning
+Warn about dead fields at link time.
+
 ; 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 000..32c8bf997fb
--- /dev/null
+++ b/gcc/ipa-type-escape-analysis.c
@@ -0,0 +1,3428 @@
+/* IPA Type Escape Analysis and Dead Field Elimination
+   Copyright (C) 2019-2020 Free Software Foundation, Inc.
+
+  Contributed by Erick Ochoa 
+
+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

[PATCH 0/8 v4] LTO Dead Field Elimination and Field Reordering

2020-12-04 Thread Erick Ochoa

Hello,

I'm sharing the most recent version of dead-field elimination. In this 
patchset the following issues have been addressed:


* CamelCase -> snake_case
* STL -> GCC specific data structures
* Fixed the commit messages (the last two commits will be squashed in 
future patchset so the commit messages are not really relevant.)


The only criticism that I have not addressed is the use of my own 
visitors for trees and gimple instructions. My position is still that 
the current visitor (for trees) is not enough to address our needs. The 
visitor implemented here has pre and post traversal hooks. Furthermore, 
there is a visitor exclusively for tree expressions and another for tree 
types, which can allow users to focus on a specific tree traversal.


There is one single STL use and that is std::string which is used when 
serializing tree types. I'd would love to keep this since preppending 
and appending std::strings is so easy and it is really only used when 
dumping debug information. (Well, technically two uses of STL, but I 
have seen std::pair being used elsewhere in the repo, so I believe it is 
ok?)


The last two commits will be squashed across the other commits (i.e., no 
patch will ever include references to STL beyond std::string and 
std::pair) and some small issues will be fixed (i.e., some names will 
change and I will remove the use of auto).


I will be running tests this weekend to make sure nothing broke, but 
initial (fast) testing seems to indicate that everything is working 
correctly.


So, why am I sharing this now? I am hoping to provide a follow up to 
those interested in this transformation and I am hoping to receive more 
feedback in order to make this pass something which the community 
values. Please, let me know your comments, questions, concerns, etc...


-Erick


Re: [PATCH 2/6 v3] Add Dead Field Elimination

2020-11-11 Thread Erick Ochoa




On 11.11.20 03:25, Jakub Jelinek wrote:

On Wed, Nov 11, 2020 at 03:14:59AM -0800, Erick Ochoa wrote:


Using the Dead Field Analysis, Dead Field Elimination
automatically transforms gimple to eliminate fields that
are never read.

2020-11-04  Erick Ochoa  

 * gcc/Makefile.in: add file to list of sources
 * gcc/ipa-dfe.c: New
 * gcc/ipa-dfe.h: Same
 * gcc/ipa-type-escape-analysis.h: Export code used in dfe.
 * gcc/ipa-type-escape-analysis.c: Call transformation


Just random general nits, not a review.
The gcc/ prefix shouldn't be in the filenames, paths are relative
to the ChangeLog file into which it goes and gcc/ directory has a ChangeLog.
All entries should start with a capital letter, so Add above, and all should
end with a period (missing in all but one place).


---
  gcc/Makefile.in|1 +
  gcc/ipa-dfe.c  | 1284 
  gcc/ipa-dfe.h  |  247 ++
  gcc/ipa-type-escape-analysis.c |   22 +-
  gcc/ipa-type-escape-analysis.h |   10 +
  5 files changed, 1554 insertions(+), 10 deletions(-)
  create mode 100644 gcc/ipa-dfe.c
  create mode 100644 gcc/ipa-dfe.h

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 8b18c9217a2..8ef6047870b 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1416,6 +1416,7 @@ OBJS = \
init-regs.o \
internal-fn.o \
ipa-type-escape-analysis.o \
+   ipa-dfe.o \
ipa-cp.o \
ipa-sra.o \
ipa-devirt.o \
diff --git a/gcc/ipa-dfe.c b/gcc/ipa-dfe.c
new file mode 100644
index 000..5ba68332ad2
--- /dev/null
+++ b/gcc/ipa-dfe.c
@@ -0,0 +1,1284 @@
+/* IPA Type Escape Analysis and Dead Field Elimination
+   Copyright (C) 2019-2020 Free Software Foundation, Inc.
+
+  Contributed by Erick Ochoa 
+
+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 elimination (IPA-DFE)
+
+   The goal of this transformation is to
+
+   1) Create new types to replace RECORD_TYPEs which hold dead fields.
+   2) Substitute instances of old RECORD_TYPEs for new RECORD_TYPEs.
+   3) Substitute instances of old FIELD_DECLs for new FIELD_DECLs.
+   4) Fix some instances of pointer arithmetic.
+   5) Relayout where needed.
+
+   First stage - DFA
+   =
+
+   Use DFA to compute the set of FIELD_DECLs which can be deleted.
+
+   Second stage - Reconstruct Types
+   
+
+   This stage is done by two family of classes, the SpecificTypeCollector
+   and the TypeReconstructor.
+
+   The SpecificTypeCollector collects all TYPE_P trees which point to
+   RECORD_TYPE trees returned by DFA.  The TypeReconstructor will create
+   new RECORD_TYPE trees and new TYPE_P trees replacing the old RECORD_TYPE
+   trees with the new RECORD_TYPE trees.
+
+   Third stage - Substitute Types and Relayout
+   ===
+
+   This stage is handled by ExprRewriter and GimpleRewriter.
+   Some pointer arithmetic is fixed here to take into account those
eliminated
+   FIELD_DECLS.
+ */
+
+#include "config.h"
+
+#include 
+#include 
+#include 
+#include 
+#include 


We really do not want to use STL in GCC sources that much, we have our own
vectors and hash_sets/maps.  If something is still needed after that,
the standard way to include STL header is define INCLUDE_ALGORITHM etc.
macros before including system.h.


Ah, I thought that just including them before was enough. Sure, I can 
change this, however, my next version of this patch will remove the STL 
from this pass.



+
+#include "system.h"



+  TypeStringifier stringifier;


GCC is not a CamelCase shop, so types etc. should use lower-case
only and underscores instead.  This is everywhere in the patch.


Understood. Thanks!


+
+  // Here we are just placing the types of interest in a set.
+  for (std::map::const_iterator i
+   = record_field_offset_map.begin (),
+   e = record_field_offset_map.end ();
+   i != e; ++i)


This should just use hash_map.


Ditto.




+  for (std::set::const_iterator i = non_escaping.begin (),
+   e = non_escaping.end ();
+   i != e; ++i)
+{
+  tree type = *i;
+  specifier.walk (type);
+}
+
+  // These are all the types which need modifications.
+  std::set to_modify = specifier.get_set ();


And hash_set.


Dit

[PATCH 3/6 v3] Add Field Reordering

2020-11-11 Thread Erick Ochoa



Field reordering of structs at link-time

2020-11-04  Erick Ochoa  

* gcc/Makefile.in: add new file to list of sources
* gcc/common.opt: add new flag for field reordering
* gcc/passes.def: add new pass
* gcc/tree-pass.h: same
* gcc/ipa-field-reorder.c: New file
* gcc/ipa-type-escape-analysis.c: Export common functions
* gcc/ipa-type-escape-analysis.h: Same
---
 gcc/Makefile.in|   1 +
 gcc/common.opt |   4 +
 gcc/ipa-dfe.c  |  86 -
 gcc/ipa-dfe.h  |  26 +-
 gcc/ipa-field-reorder.c| 622 +
 gcc/ipa-type-escape-analysis.c |  44 ++-
 gcc/ipa-type-escape-analysis.h |  12 +-
 gcc/passes.def |   1 +
 gcc/tree-pass.h|   2 +
 9 files changed, 749 insertions(+), 49 deletions(-)
 create mode 100644 gcc/ipa-field-reorder.c

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 8ef6047870b..2184bd0fc3d 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1417,6 +1417,7 @@ OBJS = \
internal-fn.o \
ipa-type-escape-analysis.o \
ipa-dfe.o \
+   ipa-field-reorder.o \
ipa-cp.o \
ipa-sra.o \
ipa-devirt.o \
diff --git a/gcc/common.opt b/gcc/common.opt
index 85351738a29..7885d0f5c0c 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -3468,4 +3468,8 @@ Wdfa
 Common Var(warn_dfa) Init(1) Warning
 Warn about dead fields at link time.
 +fipa-field-reorder
+Common Report Var(flag_ipa_field_reorder) Optimization
+Reorder fields.
+
 ; This comment is to ensure we retain the blank line above.
diff --git a/gcc/ipa-dfe.c b/gcc/ipa-dfe.c
index 5ba68332ad2..b4a3698f0dc 100644
--- a/gcc/ipa-dfe.c
+++ b/gcc/ipa-dfe.c
@@ -185,7 +185,7 @@ get_types_replacement (record_field_offset_map_t 
record_field_offset_map,

 {
   TypeStringifier stringifier;
 -  TypeReconstructor reconstructor (record_field_offset_map);
+  TypeReconstructor reconstructor (record_field_offset_map, "reorg");
   for (std::set::const_iterator i = to_modify.begin (),
e = to_modify.end ();
i != e; ++i)
@@ -245,9 +245,9 @@ get_types_replacement (record_field_offset_map_t 
record_field_offset_map,

  */
 void
 substitute_types_in_program (reorg_record_map_t map,
-reorg_field_map_t field_map)
+reorg_field_map_t field_map, bool _delete)
 {
-  GimpleTypeRewriter rewriter (map, field_map);
+  GimpleTypeRewriter rewriter (map, field_map, _delete);
   rewriter.walk ();
   rewriter._rewrite_function_decl ();
 }
@@ -361,8 +361,11 @@ TypeReconstructor::set_is_not_modified_yet (tree t)
 return;
tree type = _reorg_map[tt];
-  const bool is_modified
+  bool is_modified
 = strstr (TypeStringifier::get_type_identifier (type).c_str (), 
".reorg");

+  is_modified
+|= (bool) strstr (TypeStringifier::get_type_identifier (type).c_str (),
+ ".reorder");
   if (!is_modified)
 return;
 @@ -408,14 +411,20 @@ TypeReconstructor::is_memoized (tree t)
   return already_changed;
 }
 -static tree
-get_new_identifier (tree type)
+const char *
+TypeReconstructor::get_new_suffix ()
+{
+  return _suffix;
+}
+
+tree
+get_new_identifier (tree type, const char *suffix)
 {
   const char *identifier = TypeStringifier::get_type_identifier 
(type).c_str ();

-  const bool is_new_type = strstr (identifier, "reorg");
+  const bool is_new_type = strstr (identifier, suffix);
   gcc_assert (!is_new_type);
   char *new_name;
-  asprintf (_name, "%s.reorg", identifier);
+  asprintf (_name, "%s.%s", identifier, suffix);
   return get_identifier (new_name);
 }
 @@ -471,7 +480,9 @@ TypeReconstructor::_walk_ARRAY_TYPE_post (tree t)
   TREE_TYPE (copy) = build_variant_type_copy (TREE_TYPE (copy));
   copy = is_modified ? build_distinct_type_copy (copy) : copy;
   TREE_TYPE (copy) = is_modified ? _reorg_map[TREE_TYPE (t)] : 
TREE_TYPE (copy);
-  TYPE_NAME (copy) = is_modified ? get_new_identifier (copy) : 
TYPE_NAME (copy);

+  TYPE_NAME (copy) = is_modified
+  ? get_new_identifier (copy, this->get_new_suffix ())
+  : TYPE_NAME (copy);
   // This is useful so that we go again through type layout
   TYPE_SIZE (copy) = is_modified ? NULL : TYPE_SIZE (copy);
   tree domain = TYPE_DOMAIN (t);
@@ -524,7 +535,9 @@ TypeReconstructor::_walk_POINTER_TYPE_post (tree t)
copy = is_modified ? build_variant_type_copy (copy) : copy;
   TREE_TYPE (copy) = is_modified ? _reorg_map[TREE_TYPE (t)] : 
TREE_TYPE (copy);
-  TYPE_NAME (copy) = is_modified ? get_new_identifier (copy) : 
TYPE_NAME (copy);

+  TYPE_NAME (copy) = is_modified
+  ? get_new_identifier (copy, this->get_new_suffix ())
+  : TYPE_NAME (copy);
   TYPE_CACHED_VALUES_P (copy) = false;
tree _t = tree_to_tree (t);
@@ -619,7 +632,8 @@ TypeReconstructor::_walk

[PATCH 2/6 v3] Add Dead Field Elimination

2020-11-11 Thread Erick Ochoa



Using the Dead Field Analysis, Dead Field Elimination
automatically transforms gimple to eliminate fields that
are never read.

2020-11-04  Erick Ochoa  

* gcc/Makefile.in: add file to list of sources
* gcc/ipa-dfe.c: New
* gcc/ipa-dfe.h: Same
* gcc/ipa-type-escape-analysis.h: Export code used in dfe.
* gcc/ipa-type-escape-analysis.c: Call transformation
---
 gcc/Makefile.in|1 +
 gcc/ipa-dfe.c  | 1284 
 gcc/ipa-dfe.h  |  247 ++
 gcc/ipa-type-escape-analysis.c |   22 +-
 gcc/ipa-type-escape-analysis.h |   10 +
 5 files changed, 1554 insertions(+), 10 deletions(-)
 create mode 100644 gcc/ipa-dfe.c
 create mode 100644 gcc/ipa-dfe.h

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 8b18c9217a2..8ef6047870b 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1416,6 +1416,7 @@ OBJS = \
init-regs.o \
internal-fn.o \
ipa-type-escape-analysis.o \
+   ipa-dfe.o \
ipa-cp.o \
ipa-sra.o \
ipa-devirt.o \
diff --git a/gcc/ipa-dfe.c b/gcc/ipa-dfe.c
new file mode 100644
index 000..5ba68332ad2
--- /dev/null
+++ b/gcc/ipa-dfe.c
@@ -0,0 +1,1284 @@
+/* IPA Type Escape Analysis and Dead Field Elimination
+   Copyright (C) 2019-2020 Free Software Foundation, Inc.
+
+  Contributed by Erick Ochoa 
+
+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 elimination (IPA-DFE)
+
+   The goal of this transformation is to
+
+   1) Create new types to replace RECORD_TYPEs which hold dead fields.
+   2) Substitute instances of old RECORD_TYPEs for new RECORD_TYPEs.
+   3) Substitute instances of old FIELD_DECLs for new FIELD_DECLs.
+   4) Fix some instances of pointer arithmetic.
+   5) Relayout where needed.
+
+   First stage - DFA
+   =
+
+   Use DFA to compute the set of FIELD_DECLs which can be deleted.
+
+   Second stage - Reconstruct Types
+   
+
+   This stage is done by two family of classes, the SpecificTypeCollector
+   and the TypeReconstructor.
+
+   The SpecificTypeCollector collects all TYPE_P trees which point to
+   RECORD_TYPE trees returned by DFA.  The TypeReconstructor will create
+   new RECORD_TYPE trees and new TYPE_P trees replacing the old RECORD_TYPE
+   trees with the new RECORD_TYPE trees.
+
+   Third stage - Substitute Types and Relayout
+   ===
+
+   This stage is handled by ExprRewriter and GimpleRewriter.
+   Some pointer arithmetic is fixed here to take into account those 
eliminated

+   FIELD_DECLS.
+ */
+
+#include "config.h"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#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-sum

[PATCH 4/6 v3] Add documentation for dead field elimination

2020-11-11 Thread Erick Ochoa



2020-11-04  Erick Ochoa  

* gcc/Makefile.in: Add file to documentation sources
* gcc/doc/dfe.texi: New section
* gcc/doc/gccint.texi: Include new section
---
 gcc/Makefile.in |   3 +-
 gcc/doc/dfe.texi| 187 
 gcc/doc/gccint.texi |   2 +
 3 files changed, 191 insertions(+), 1 deletion(-)
 create mode 100644 gcc/doc/dfe.texi

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 2184bd0fc3d..7e4c442416d 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -3275,7 +3275,8 @@ TEXI_GCCINT_FILES = gccint.texi gcc-common.texi 
gcc-vers.texi		\

 gnu.texi gpl_v3.texi fdl.texi contrib.texi languages.texi  \
 sourcebuild.texi gty.texi libgcc.texi cfg.texi tree-ssa.texi   \
 loop.texi generic.texi gimple.texi plugins.texi optinfo.texi   \
-match-and-simplify.texi analyzer.texi ux.texi poly-int.texi
+match-and-simplify.texi analyzer.texi ux.texi poly-int.texi\
+dfe.texi
  TEXI_GCCINSTALL_FILES = install.texi install-old.texi fdl.texi
\
 gcc-common.texi gcc-vers.texi
diff --git a/gcc/doc/dfe.texi b/gcc/doc/dfe.texi
new file mode 100644
index 000..e8d01d817d3
--- /dev/null
+++ b/gcc/doc/dfe.texi
@@ -0,0 +1,187 @@
+@c Copyright (C) 2001 Free Software Foundation, Inc.
+@c This is part of the GCC manual.
+@c For copying conditions, see the file gcc.texi.
+
+@node Dead Field Elimination
+@chapter Dead Field Elimination
+
+@node Dead Field Elimination Internals
+@section Dead Field Elimination Internals
+
+@subsection Introduction
+
+Dead field elimination is a compiler transformation that removes fields 
from structs. There are several challenges to removing fields from 
structs at link time but, depending on the workload of the compiled 
program and the architecture where the program runs, dead field 
elimination might be a worthwhile transformation to apply. Generally 
speaking, when the bottle-neck of an application is given by the memory 
bandwidth of the host system and the memory requested is of a struct 
which can be reduced in size, then that combination of workload, program 
and architecture can benefit from applying dead field elimination. The 
benefits come from removing unnecessary fields from structures and thus 
reducing the memory/cache requirements to represent a structure.  +

+ +
+While challenges exist to fully automate a dead field elimination 
transformation, similar and more powerful optimizations have been 
implemented in the past. Chakrabarti et al [0] implement struct peeling, 
splitting into hot and cold parts of a structure, and field reordering. 
Golovanevsky et al [1] also shows efforts to implement data layout 
optimizations at link time. Unlike the work of Chakrabarti and 
Golovanesky, this text only talks about dead field elimination. This 
doesn't mean that the implementation can't be expanded to perform other 
link-time layout optimizations, it just means that dead field 
elimination is the only transformation that is implemented at the time 
of this writing. +
+[0] Chakrabarti, Gautam, Fred Chow, and L. PathScale. "Structure layout 
optimizations in the open64 compiler: Design, implementation and 
measurements." Open64 Workshop at the International Symposium on Code 
Generation and Optimization. 2008.  +
+[1] Golovanevsky, Olga, and Ayal Zaks. "Struct-reorg: current status 
and future perspectives." Proceedings of the GCC Developers’ Summit. 
2007.  +

+@subsection Overview
+
+The dead field implementation is structured in the following way:  +
+ +@itemize @bullet
+@item
+Collect all types which can refer to a @code{RECORD_TYPE}. This means 
that if we have a pointer to a record, we also collect this pointer. Or 
an array, or a union. +@item

+Mark types as escaping. More of this in the following section.  +@item
+Find fields which can be deleted. (Iterate over all gimple code and 
find which fields are read.)  +@item
+Create new types with removed fields (and reference these types in 
pointers, arrays, etc.)  +@item

+Modify gimple to include these types.  +@end itemize
+
+
+Most of this code relies on the visitor pattern. Types, Expr, and 
Gimple statements are visited using this pattern. You can find the base 
classes in @file{type-walker.c} @file{expr-walker.c} and 
@file{gimple-walker.c}. There are assertions in place where a type, 
expr, or gimple code is encountered which has not been encountered 
before during the testing of this transformation. This facilitates 
fuzzying of the transformation.

+
+@subsubsection Implementation Details: Is a global variable escaping?
+
+How does the analysis determine whether a global variable is visible to 
code outside the current linking unit? In the file 
@file{gimple-escaper.c} we have a simple function called 
@code{is_variable_escaping} which checks whether a variable is visible 
to code outside the current linking unit by looking at the 
@code{varpool_node}’s @cod

[PATCH 5/6 v3] Abort if Gimple from C++ or Fortran sources is found.

2020-11-11 Thread Erick Ochoa



2020-11-04  Erick Ochoa  

* gcc/ipa-field-reorder: Add flag to exit transformation
* gcc/ipa-type-escape-analysis: Same
---
 gcc/ipa-field-reorder.c|  3 +-
 gcc/ipa-type-escape-analysis.c | 54 --
 gcc/ipa-type-escape-analysis.h |  2 ++
 3 files changed, 49 insertions(+), 10 deletions(-)

diff --git a/gcc/ipa-field-reorder.c b/gcc/ipa-field-reorder.c
index 4c1ddc6d0e3..9a28097b473 100644
--- a/gcc/ipa-field-reorder.c
+++ b/gcc/ipa-field-reorder.c
@@ -587,6 +587,7 @@ lto_fr_execute ()
 {
   log ("here in field reordering \n");
   // Analysis.
+  detected_incompatible_syntax = false;
   tpartitions_t escaping_nonescaping_sets
 = partition_types_into_escaping_nonescaping ();
   record_field_map_t record_field_map = find_fields_accessed ();
@@ -594,7 +595,7 @@ lto_fr_execute ()
 = obtain_nonescaping_unaccessed_fields (escaping_nonescaping_sets,
record_field_map, 0);
 -  if (record_field_offset_map.empty ())
+  if (detected_incompatible_syntax || record_field_offset_map.empty ())
 return 0;
// Prepare for transformation.
diff --git a/gcc/ipa-type-escape-analysis.c b/gcc/ipa-type-escape-analysis.c
index 31eb8b41ff0..df21500b61e 100644
--- a/gcc/ipa-type-escape-analysis.c
+++ b/gcc/ipa-type-escape-analysis.c
@@ -171,6 +171,10 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-type-escape-analysis.h"
 #include "ipa-dfe.h"
 +#define ABORT_IF_NOT_C true
+
+bool detected_incompatible_syntax = false;
+
 // Main function that drives dfe.
 static unsigned int
 lto_dfe_execute ();
@@ -262,13 +266,15 @@ lto_dead_field_elimination ()
 if (cnode->inlined_to) continue;
 cnode->get_body();
   }
+
+  detected_incompatible_syntax = false;
   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, OPT_Wdfa);
-  if (record_field_offset_map.empty ())
+  if (detected_incompatible_syntax || record_field_offset_map.empty ())
 return;
  // Prepare for transformation.
@@ -588,6 +594,7 @@ TypeWalker::_walk (tree type)
   // Improve, verify that having a type is an invariant.
   // I think there was a specific example which didn't
   // allow for it
+  if (detected_incompatible_syntax) return;
   if (!type)
 return;
 @@ -641,9 +648,9 @@ TypeWalker::_walk (tree type)
 case POINTER_TYPE:
   this->walk_POINTER_TYPE (type);
   break;
-case REFERENCE_TYPE:
-  this->walk_REFERENCE_TYPE (type);
-  break;
+//case REFERENCE_TYPE:
+//  this->walk_REFERENCE_TYPE (type);
+//  break;
 case ARRAY_TYPE:
   this->walk_ARRAY_TYPE (type);
   break;
@@ -653,18 +660,24 @@ TypeWalker::_walk (tree type)
 case FUNCTION_TYPE:
   this->walk_FUNCTION_TYPE (type);
   break;
-case METHOD_TYPE:
-  this->walk_METHOD_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 REFERENCE_TYPE:
+case METHOD_TYPE:
 case QUAL_UNION_TYPE:
 case LANG_TYPE:
 default:
   {
log ("missing %s\n", get_tree_code_name (code));
+#ifdef ABORT_IF_NOT_C
+   detected_incompatible_syntax = true;
+#else
gcc_unreachable ();
+#endif
   }
   break;
 }
@@ -847,6 +860,7 @@ TypeWalker::_walk_arg (tree t)
 void
 ExprWalker::walk (tree e)
 {
+  if (detected_incompatible_syntax) return;
   _walk_pre (e);
   _walk (e);
   _walk_post (e);
@@ -931,7 +945,11 @@ ExprWalker::_walk (tree e)
 default:
   {
log ("missing %s\n", get_tree_code_name (code));
+#ifdef ABORT_IF_NOT_C
+   detected_incompatible_syntax = true;
+#else
gcc_unreachable ();
+#endif
   }
   break;
 }
@@ -1164,6 +1182,7 @@ GimpleWalker::walk ()
   cgraph_node *node = NULL;
   FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
 {
+  if (detected_incompatible_syntax) return;
   node->get_untransformed_body ();
   tree decl = node->decl;
   gcc_assert (decl);
@@ -1410,7 +1429,11 @@ GimpleWalker::_walk_gimple (gimple *stmt)
   // Break if something is unexpected.
   const char *name = gimple_code_name[code];
   log ("gimple code name %s\n", name);
+#ifdef ABORT_IF_NOT_C
+  detected_incompatible_syntax = true;
+#else
   gcc_unreachable ();
+#endif
 }
  void
@@ -2960,6 +2983,8 @@ TypeStringifier::stringify (tree t)
 return std::string ("");
   _stringification.clear ();
   gcc_assert (t);
+  if (detected_incompatible_syntax)
+retur

[PATCH 6/6 v3] Add heuristic to take into account void* pattern.

2020-11-11 Thread Erick Ochoa



We add a heuristic in order to be able to transform functions which
receive void* arguments as a way to generalize over arguments. An
example of this is qsort. The heuristic works by first inspecting
leaves in the call graph. If the leaves only contain a reference
to a single RECORD_TYPE then we color the nodes in the call graph
as "casts are safe in this function and does not call external
visible functions". We propagate this property up the callgraph
until a fixed point is reached. This will later be changed to
use ipa-modref.

2020-11-04  Erick Ochoa  

* ipa-type-escape-analysis.c : Add new heuristic
* ipa-field-reorder.c : Use heuristic
* ipa-type-escape-analysis.h : Change signatures
---
 gcc/ipa-field-reorder.c|   3 +-
 gcc/ipa-type-escape-analysis.c | 193 +++--
 gcc/ipa-type-escape-analysis.h |  78 +++--
 3 files changed, 259 insertions(+), 15 deletions(-)

diff --git a/gcc/ipa-field-reorder.c b/gcc/ipa-field-reorder.c
index 9a28097b473..2f694cff7ea 100644
--- a/gcc/ipa-field-reorder.c
+++ b/gcc/ipa-field-reorder.c
@@ -588,8 +588,9 @@ lto_fr_execute ()
   log ("here in field reordering \n");
   // Analysis.
   detected_incompatible_syntax = false;
+  std::map whitelisted = get_whitelisted_nodes();
   tpartitions_t escaping_nonescaping_sets
-= partition_types_into_escaping_nonescaping ();
+= partition_types_into_escaping_nonescaping (whitelisted);
   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,
diff --git a/gcc/ipa-type-escape-analysis.c b/gcc/ipa-type-escape-analysis.c
index df21500b61e..ea993b8a6cc 100644
--- a/gcc/ipa-type-escape-analysis.c
+++ b/gcc/ipa-type-escape-analysis.c
@@ -104,6 +104,7 @@ along with GCC; see the file COPYING3.  If not see
 #include 
 #include 
 #include 
+#include 
  #include "config.h"
 #include "system.h"
@@ -249,6 +250,99 @@ lto_dfe_execute ()
   return 0;
 }
 +/* Heuristic to determine if casting is allowed in a function.
+ * This heuristic attempts to allow casting in functions which follow the
+ * pattern where a struct pointer or array pointer is casted to void* 
or + * char*.  The heuristic works as follows:

+ *
+ * There is a simple per-function analysis that determines whether there
+ * is more than 1 type of struct referenced in the body of the method.
+ * If there is more than 1 type of struct referenced in the body,
+ * then the layout of the structures referenced within the body
+ * cannot be casted.  However, if there's only one type of struct 
referenced

+ * in the body of the function, casting is allowed in the function itself.
+ * The logic behind this is that the if the code follows good programming
+ * practices, the only way the memory should be accessed is via a singular
+ * type. There is also another requisite to this per-function analysis, and
+ * that is that the function can only call colored functions or functions
+ * which are available in the linking unit.
+ *
+ * Using this per-function analysis, we then start coloring leaf nodes 
in the
+ * call graph as ``safe'' or ``unsafe''.  The color is propagated to 
the + * callers of the functions until a fixed point is reached.

+ */
+std::map
+get_whitelisted_nodes ()
+{
+  cgraph_node *node = NULL;
+  std::set nodes;
+  std::set leaf_nodes;
+  std::set leaf_nodes_decl;
+  FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
+  {
+node->get_untransformed_body ();
+nodes.insert(node);
+if (node->callees) continue;
+
+leaf_nodes.insert (node);
+leaf_nodes_decl.insert (node->decl);
+  }
+
+  std::queue worklist;
+  for (std::set::iterator i = leaf_nodes.begin (),
+e = leaf_nodes.end (); i != e; ++i)
+  {
+if (dump_file) fprintf (dump_file, "is a leaf node %s\n", 
(*i)->name ());

+worklist.push (*i);
+  }
+
+  for (std::set::iterator i = nodes.begin (),
+e = nodes.end (); i != e; ++i)
+  {
+worklist.push (*i);
+  }
+
+  std::map map;
+  while (!worklist.empty ())
+  {
+
+if (detected_incompatible_syntax) return map;
+cgraph_node *i = worklist.front ();
+worklist.pop ();
+if (dump_file) fprintf (dump_file, "analyzing %s %p\n", i->name (), 
(void*)i);

+GimpleWhiteLister whitelister;
+whitelister._walk_cnode (i);
+bool no_external = whitelister.does_not_call_external_functions (i, 
map);

+bool before_in_map = map.find (i->decl) != map.end ();
+bool place_callers_in_worklist = !before_in_map;
+if (!before_in_map)
+{
+  map.insert(std::pair(i->decl, no_external));
+} else
+{
+  map[i->decl] = no_external;
+}
+bool previous_value = map[i->decl];
+place_callers_in_worklist |= previous_value != no_external;
+if (previous_value != no_external)
+{
+   // This ensures we are having a tota

[PATCH 3/6] Add Field Reordering

2020-11-06 Thread Erick Ochoa

From 72e6ea57b04ca2bf223faef262b478dc407cdca7 Mon Sep 17 00:00:00 2001
From: Erick Ochoa 
Date: Sun, 9 Aug 2020 10:22:49 +0200
Subject: [PATCH 3/6] Add Field Reordering

Field reordering of structs at link-time

2020-11-04  Erick Ochoa  

* gcc/Makefile.in: add new file to list of sources
* gcc/common.opt: add new flag for field reordering
* gcc/passes.def: add new pass
* gcc/tree-pass.h: same
* gcc/ipa-field-reorder.c: New file
* gcc/ipa-type-escape-analysis.c: Export common functions
* gcc/ipa-type-escape-analysis.h: Same
---
 gcc/Makefile.in|   1 +
 gcc/common.opt |   4 +
 gcc/ipa-dfe.c  |  86 -
 gcc/ipa-dfe.h  |  26 +-
 gcc/ipa-field-reorder.c| 622 +
 gcc/ipa-type-escape-analysis.c |  44 ++-
 gcc/ipa-type-escape-analysis.h |  12 +-
 gcc/passes.def |   1 +
 gcc/tree-pass.h|   2 +
 9 files changed, 749 insertions(+), 49 deletions(-)
 create mode 100644 gcc/ipa-field-reorder.c

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 8ef6047870b..2184bd0fc3d 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1417,6 +1417,7 @@ OBJS = \
internal-fn.o \
ipa-type-escape-analysis.o \
ipa-dfe.o \
+   ipa-field-reorder.o \
ipa-cp.o \
ipa-sra.o \
ipa-devirt.o \
diff --git a/gcc/common.opt b/gcc/common.opt
index 85351738a29..7885d0f5c0c 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -3468,4 +3468,8 @@ Wdfa
 Common Var(warn_dfa) Init(1) Warning
 Warn about dead fields at link time.

+fipa-field-reorder
+Common Report Var(flag_ipa_field_reorder) Optimization
+Reorder fields.
+
 ; This comment is to ensure we retain the blank line above.
diff --git a/gcc/ipa-dfe.c b/gcc/ipa-dfe.c
index 31a5066f1b5..5602ee667d4 100644
--- a/gcc/ipa-dfe.c
+++ b/gcc/ipa-dfe.c
@@ -185,7 +185,7 @@ get_types_replacement (record_field_offset_map_t 
record_field_offset_map,

 {
   TypeStringifier stringifier;

-  TypeReconstructor reconstructor (record_field_offset_map);
+  TypeReconstructor reconstructor (record_field_offset_map, "reorg");
   for (std::set::const_iterator i = to_modify.begin (),
e = to_modify.end ();
i != e; ++i)
@@ -245,9 +245,9 @@ get_types_replacement (record_field_offset_map_t 
record_field_offset_map,

  */
 void
 substitute_types_in_program (reorg_record_map_t map,
-reorg_field_map_t field_map)
+reorg_field_map_t field_map, bool _delete)
 {
-  GimpleTypeRewriter rewriter (map, field_map);
+  GimpleTypeRewriter rewriter (map, field_map, _delete);
   rewriter.walk ();
   rewriter._rewrite_function_decl ();
 }
@@ -361,8 +361,11 @@ TypeReconstructor::set_is_not_modified_yet (tree t)
 return;

   tree type = _reorg_map[tt];
-  const bool is_modified
+  bool is_modified
 = strstr (TypeStringifier::get_type_identifier (type).c_str (), 
".reorg");

+  is_modified
+|= (bool) strstr (TypeStringifier::get_type_identifier (type).c_str (),
+ ".reorder");
   if (!is_modified)
 return;

@@ -408,14 +411,20 @@ TypeReconstructor::is_memoized (tree t)
   return already_changed;
 }

-static tree
-get_new_identifier (tree type)
+const char *
+TypeReconstructor::get_new_suffix ()
+{
+  return _suffix;
+}
+
+tree
+get_new_identifier (tree type, const char *suffix)
 {
   const char *identifier = TypeStringifier::get_type_identifier 
(type).c_str ();

-  const bool is_new_type = strstr (identifier, "reorg");
+  const bool is_new_type = strstr (identifier, suffix);
   gcc_assert (!is_new_type);
   char *new_name;
-  asprintf (_name, "%s.reorg", identifier);
+  asprintf (_name, "%s.%s", identifier, suffix);
   return get_identifier (new_name);
 }

@@ -471,7 +480,9 @@ TypeReconstructor::_walk_ARRAY_TYPE_post (tree t)
   TREE_TYPE (copy) = build_variant_type_copy (TREE_TYPE (copy));
   copy = is_modified ? build_distinct_type_copy (copy) : copy;
   TREE_TYPE (copy) = is_modified ? _reorg_map[TREE_TYPE (t)] : 
TREE_TYPE (copy);
-  TYPE_NAME (copy) = is_modified ? get_new_identifier (copy) : 
TYPE_NAME (copy);

+  TYPE_NAME (copy) = is_modified
+  ? get_new_identifier (copy, this->get_new_suffix ())
+  : TYPE_NAME (copy);
   // This is useful so that we go again through type layout
   TYPE_SIZE (copy) = is_modified ? NULL : TYPE_SIZE (copy);
   tree domain = TYPE_DOMAIN (t);
@@ -524,7 +535,9 @@ TypeReconstructor::_walk_POINTER_TYPE_post (tree t)

   copy = is_modified ? build_variant_type_copy (copy) : copy;
   TREE_TYPE (copy) = is_modified ? _reorg_map[TREE_TYPE (t)] : 
TREE_TYPE (copy);
-  TYPE_NAME (copy) = is_modified ? get_new_identifier (copy) : 
TYPE_NAME (copy);

+  TYPE_NAME (copy) = is_modified
+  ? get_new_identifier (copy, this->get_new_suffix ())

[PATCH 6/6] Add heuristic to take into account void* pattern.

2020-11-06 Thread Erick Ochoa

From ccd82a7e484d9e4562c23f1b9cbebf3f47e2a822 Mon Sep 17 00:00:00 2001
From: Erick Ochoa 
Date: Fri, 16 Oct 2020 08:49:08 +0200
Subject: [PATCH 6/6] Add heuristic to take into account void* pattern.

We add a heuristic in order to be able to transform functions which
receive void* arguments as a way to generalize over arguments. An
example of this is qsort. The heuristic works by first inspecting
leaves in the call graph. If the leaves only contain a reference
to a single RECORD_TYPE then we color the nodes in the call graph
as "casts are safe in this function and does not call external
visible functions". We propagate this property up the callgraph
until a fixed point is reached. This will later be changed to
use ipa-modref.

2020-11-04  Erick Ochoa  

* ipa-type-escape-analysis.c : Add new heuristic
* ipa-field-reorder.c : Use heuristic
* ipa-type-escape-analysis.h : Change signatures
---
 gcc/ipa-field-reorder.c|   3 +-
 gcc/ipa-type-escape-analysis.c | 182 +++--
 gcc/ipa-type-escape-analysis.h |  72 -
 3 files changed, 243 insertions(+), 14 deletions(-)

diff --git a/gcc/ipa-field-reorder.c b/gcc/ipa-field-reorder.c
index 9a28097b473..2f694cff7ea 100644
--- a/gcc/ipa-field-reorder.c
+++ b/gcc/ipa-field-reorder.c
@@ -588,8 +588,9 @@ lto_fr_execute ()
   log ("here in field reordering \n");
   // Analysis.
   detected_incompatible_syntax = false;
+  std::map whitelisted = get_whitelisted_nodes();
   tpartitions_t escaping_nonescaping_sets
-= partition_types_into_escaping_nonescaping ();
+= partition_types_into_escaping_nonescaping (whitelisted);
   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,
diff --git a/gcc/ipa-type-escape-analysis.c b/gcc/ipa-type-escape-analysis.c
index 40dc89c51a2..2fc504ce6f5 100644
--- a/gcc/ipa-type-escape-analysis.c
+++ b/gcc/ipa-type-escape-analysis.c
@@ -104,6 +104,7 @@ along with GCC; see the file COPYING3.  If not see
 #include 
 #include 
 #include 
+#include 

 #include "config.h"
 #include "system.h"
@@ -249,6 +250,99 @@ lto_dfe_execute ()
   return 0;
 }

+/* Heuristic to determine if casting is allowed in a function.
+ * This heuristic attempts to allow casting in functions which follow the
+ * pattern where a struct pointer or array pointer is casted to void* or
+ * char*.  The heuristic works as follows:
+ *
+ * There is a simple per-function analysis that determines whether there
+ * is more than 1 type of struct referenced in the body of the method.
+ * If there is more than 1 type of struct referenced in the body,
+ * then the layout of the structures referenced within the body
+ * cannot be casted.  However, if there's only one type of struct 
referenced

+ * in the body of the function, casting is allowed in the function itself.
+ * The logic behind this is that the if the code follows good programming
+ * practices, the only way the memory should be accessed is via a singular
+ * type. There is also another requisite to this per-function analysis, and
+ * that is that the function can only call colored functions or functions
+ * which are available in the linking unit.
+ *
+ * Using this per-function analysis, we then start coloring leaf nodes 
in the

+ * call graph as ``safe'' or ``unsafe''.  The color is propagated to the
+ * callers of the functions until a fixed point is reached.
+ */
+std::map
+get_whitelisted_nodes ()
+{
+  cgraph_node *node = NULL;
+  std::set nodes;
+  std::set leaf_nodes;
+  std::set leaf_nodes_decl;
+  FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
+  {
+node->get_untransformed_body ();
+nodes.insert(node);
+if (node->callees) continue;
+
+leaf_nodes.insert (node);
+leaf_nodes_decl.insert (node->decl);
+  }
+
+  std::queue worklist;
+  for (std::set::iterator i = leaf_nodes.begin (),
+e = leaf_nodes.end (); i != e; ++i)
+  {
+if (dump_file) fprintf (dump_file, "is a leaf node %s\n", 
(*i)->name ());

+worklist.push (*i);
+  }
+
+  for (std::set::iterator i = nodes.begin (),
+e = nodes.end (); i != e; ++i)
+  {
+worklist.push (*i);
+  }
+
+  std::map map;
+  while (!worklist.empty ())
+  {
+
+if (detected_incompatible_syntax) return map;
+cgraph_node *i = worklist.front ();
+worklist.pop ();
+if (dump_file) fprintf (dump_file, "analyzing %s %p\n", i->name (), 
(void*)i);

+GimpleWhiteLister whitelister;
+whitelister._walk_cnode (i);
+bool no_external = whitelister.does_not_call_external_functions (i, 
map);

+bool before_in_map = map.find (i->decl) != map.end ();
+bool place_callers_in_worklist = !before_in_map;
+if (!before_in_map)
+{
+  map.insert(std::pair(i->decl, no_external));
+} else
+{
+  map[i->decl] = no_external;
+}
+bool previous_v

[PATCH 5/6] Abort if Gimple from C++ or Fortran sources is found.

2020-11-06 Thread Erick Ochoa

From f5dbfa73962d5443013d0193b2f91ea112a6d2d1 Mon Sep 17 00:00:00 2001
From: Erick Ochoa 
Date: Sun, 30 Aug 2020 10:21:35 +0200
Subject: [PATCH 5/6] Abort if Gimple from C++ or Fortran sources is found.

2020-11-04  Erick Ochoa  

* gcc/ipa-field-reorder: Add flag to exit transformation
* gcc/ipa-type-escape-analysis: Same
---
 gcc/ipa-field-reorder.c|  3 +-
 gcc/ipa-type-escape-analysis.c | 53 --
 gcc/ipa-type-escape-analysis.h |  2 ++
 3 files changed, 48 insertions(+), 10 deletions(-)

diff --git a/gcc/ipa-field-reorder.c b/gcc/ipa-field-reorder.c
index 4c1ddc6d0e3..9a28097b473 100644
--- a/gcc/ipa-field-reorder.c
+++ b/gcc/ipa-field-reorder.c
@@ -587,6 +587,7 @@ lto_fr_execute ()
 {
   log ("here in field reordering \n");
   // Analysis.
+  detected_incompatible_syntax = false;
   tpartitions_t escaping_nonescaping_sets
 = partition_types_into_escaping_nonescaping ();
   record_field_map_t record_field_map = find_fields_accessed ();
@@ -594,7 +595,7 @@ lto_fr_execute ()
 = obtain_nonescaping_unaccessed_fields (escaping_nonescaping_sets,
record_field_map, 0);

-  if (record_field_offset_map.empty ())
+  if (detected_incompatible_syntax || record_field_offset_map.empty ())
 return 0;

   // Prepare for transformation.
diff --git a/gcc/ipa-type-escape-analysis.c b/gcc/ipa-type-escape-analysis.c
index aec7b924533..40dc89c51a2 100644
--- a/gcc/ipa-type-escape-analysis.c
+++ b/gcc/ipa-type-escape-analysis.c
@@ -171,6 +171,10 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-type-escape-analysis.h"
 #include "ipa-dfe.h"

+#define ABORT_IF_NOT_C true
+
+bool detected_incompatible_syntax = false;
+
 // Main function that drives dfe.
 static unsigned int
 lto_dfe_execute ();
@@ -256,13 +260,14 @@ static void
 lto_dead_field_elimination ()
 {
   // Analysis.
+  detected_incompatible_syntax = false;
   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, OPT_Wdfa);
-  if (record_field_offset_map.empty ())
+  if (detected_incompatible_syntax || record_field_offset_map.empty ())
 return;

 // Prepare for transformation.
@@ -581,6 +586,7 @@ TypeWalker::_walk (tree type)
   // Improve, verify that having a type is an invariant.
   // I think there was a specific example which didn't
   // allow for it
+  if (detected_incompatible_syntax) return;
   if (!type)
 return;

@@ -634,9 +640,9 @@ TypeWalker::_walk (tree type)
 case POINTER_TYPE:
   this->walk_POINTER_TYPE (type);
   break;
-case REFERENCE_TYPE:
-  this->walk_REFERENCE_TYPE (type);
-  break;
+//case REFERENCE_TYPE:
+//  this->walk_REFERENCE_TYPE (type);
+//  break;
 case ARRAY_TYPE:
   this->walk_ARRAY_TYPE (type);
   break;
@@ -646,18 +652,24 @@ TypeWalker::_walk (tree type)
 case FUNCTION_TYPE:
   this->walk_FUNCTION_TYPE (type);
   break;
-case METHOD_TYPE:
-  this->walk_METHOD_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 REFERENCE_TYPE:
+case METHOD_TYPE:
 case QUAL_UNION_TYPE:
 case LANG_TYPE:
 default:
   {
log ("missing %s\n", get_tree_code_name (code));
+#ifdef ABORT_IF_NOT_C
+   detected_incompatible_syntax = true;
+#else
gcc_unreachable ();
+#endif
   }
   break;
 }
@@ -840,6 +852,7 @@ TypeWalker::_walk_arg (tree t)
 void
 ExprWalker::walk (tree e)
 {
+  if (detected_incompatible_syntax) return;
   _walk_pre (e);
   _walk (e);
   _walk_post (e);
@@ -924,7 +937,11 @@ ExprWalker::_walk (tree e)
 default:
   {
log ("missing %s\n", get_tree_code_name (code));
+#ifdef ABORT_IF_NOT_C
+   detected_incompatible_syntax = true;
+#else
gcc_unreachable ();
+#endif
   }
   break;
 }
@@ -1157,6 +1174,7 @@ GimpleWalker::walk ()
   cgraph_node *node = NULL;
   FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
 {
+  if (detected_incompatible_syntax) return;
   node->get_untransformed_body ();
   tree decl = node->decl;
   gcc_assert (decl);
@@ -1403,7 +1421,11 @@ GimpleWalker::_walk_gimple (gimple *stmt)
   // Break if something is unexpected.
   const char *name = gimple_code_name[code];
   log ("gimple code name %s\n", name);
+#ifdef ABORT_IF_NOT_C
+  detected_incompatible_syntax = true;
+#else
   gcc_unreachable ();
+#endif
 }

 void
@@ -2935,6 +2957,8 @@ TypeStringifier::stringif

[PATCH 2/6] Add Dead Field Elimination

2020-11-06 Thread Erick Ochoa

From 2cd94824269e94babedd2a963e4b9ee96889ec82 Mon Sep 17 00:00:00 2001
From: Erick Ochoa 
Date: Thu, 6 Aug 2020 14:07:20 +0200
Subject: [PATCH 2/6] Add Dead Field Elimination

Using the Dead Field Analysis, Dead Field Elimination
automatically transforms gimple to eliminate fields that
are never read.

2020-11-04  Erick Ochoa  

* gcc/Makefile.in: add file to list of sources
* gcc/ipa-dfe.c: New
* gcc/ipa-dfe.h: Same
* gcc/ipa-type-escape-analysis.h: Export code used in dfe.
* gcc/ipa-type-escape-analysis.c: Call transformation
---
 gcc/Makefile.in|1 +
 gcc/ipa-dfe.c  | 1283 
 gcc/ipa-dfe.h  |  247 ++
 gcc/ipa-type-escape-analysis.c |   22 +-
 gcc/ipa-type-escape-analysis.h |   10 +
 5 files changed, 1553 insertions(+), 10 deletions(-)
 create mode 100644 gcc/ipa-dfe.c
 create mode 100644 gcc/ipa-dfe.h

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 8b18c9217a2..8ef6047870b 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1416,6 +1416,7 @@ OBJS = \
init-regs.o \
internal-fn.o \
ipa-type-escape-analysis.o \
+   ipa-dfe.o \
ipa-cp.o \
ipa-sra.o \
ipa-devirt.o \
diff --git a/gcc/ipa-dfe.c b/gcc/ipa-dfe.c
new file mode 100644
index 000..31a5066f1b5
--- /dev/null
+++ b/gcc/ipa-dfe.c
@@ -0,0 +1,1283 @@
+/* IPA Type Escape Analysis and Dead Field Elimination
+   Copyright (C) 2019-2020 Free Software Foundation, Inc.
+
+  Contributed by Erick Ochoa 
+
+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 elimination (IPA-DFE)
+
+   The goal of this transformation is to
+
+   1) Create new types to replace RECORD_TYPEs which hold dead fields.
+   2) Substitute instances of old RECORD_TYPEs for new RECORD_TYPEs.
+   3) Substitute instances of old FIELD_DECLs for new FIELD_DECLs.
+   4) Fix some instances of pointer arithmetic.
+   5) Relayout where needed.
+
+   First stage - DFA
+   =
+
+   Use DFA to compute the set of FIELD_DECLs which can be deleted.
+
+   Second stage - Reconstruct Types
+   
+
+   This stage is done by two family of classes, the SpecificTypeCollector
+   and the TypeReconstructor.
+
+   The SpecificTypeCollector collects all TYPE_P trees which point to
+   RECORD_TYPE trees returned by DFA.  The TypeReconstructor will create
+   new RECORD_TYPE trees and new TYPE_P trees replacing the old RECORD_TYPE
+   trees with the new RECORD_TYPE trees.
+
+   Third stage - Substitute Types and Relayout
+   ===
+
+   This stage is handled by ExprRewriter and GimpleRewriter.
+   Some pointer arithmetic is fixed here to take into account those 
eliminated

+   FIELD_DECLS.
+ */
+
+#include "config.h"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#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&

[PATCH 0/6] Dead Field Elimination and Field Reorder

2020-11-06 Thread Erick Ochoa

Just submitting changes to the previously submitted patches.

* I have removed all non-essential flags I introduced
* I have placed the standard headers before config
* I have squashed some changes that I sent to the patches mailing list 
and make sure that the transformation bootstraps on every commit


[PATCH 4/6] Add documentation for dead field elimination

2020-11-06 Thread Erick Ochoa

From 015634bee522cf6224b0d4bcfd3adaf3a6a38fa0 Mon Sep 17 00:00:00 2001
From: Erick Ochoa 
Date: Mon, 10 Aug 2020 09:10:37 +0200
Subject: [PATCH 4/6] Add documentation for dead field elimination

2020-11-04  Erick Ochoa  

* gcc/Makefile.in: Add file to documentation sources
* gcc/doc/dfe.texi: New section
* gcc/doc/gccint.texi: Include new section
---
 gcc/Makefile.in |   3 +-
 gcc/doc/dfe.texi| 187 
 gcc/doc/gccint.texi |   2 +
 3 files changed, 191 insertions(+), 1 deletion(-)
 create mode 100644 gcc/doc/dfe.texi

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 2184bd0fc3d..7e4c442416d 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -3275,7 +3275,8 @@ TEXI_GCCINT_FILES = gccint.texi gcc-common.texi 
gcc-vers.texi		\

 gnu.texi gpl_v3.texi fdl.texi contrib.texi languages.texi  \
 sourcebuild.texi gty.texi libgcc.texi cfg.texi tree-ssa.texi   \
 loop.texi generic.texi gimple.texi plugins.texi optinfo.texi   \
-match-and-simplify.texi analyzer.texi ux.texi poly-int.texi
+match-and-simplify.texi analyzer.texi ux.texi poly-int.texi\
+dfe.texi

 TEXI_GCCINSTALL_FILES = install.texi install-old.texi fdl.texi \
 gcc-common.texi gcc-vers.texi
diff --git a/gcc/doc/dfe.texi b/gcc/doc/dfe.texi
new file mode 100644
index 000..e8d01d817d3
--- /dev/null
+++ b/gcc/doc/dfe.texi
@@ -0,0 +1,187 @@
+@c Copyright (C) 2001 Free Software Foundation, Inc.
+@c This is part of the GCC manual.
+@c For copying conditions, see the file gcc.texi.
+
+@node Dead Field Elimination
+@chapter Dead Field Elimination
+
+@node Dead Field Elimination Internals
+@section Dead Field Elimination Internals
+
+@subsection Introduction
+
+Dead field elimination is a compiler transformation that removes fields 
from structs. There are several challenges to removing fields from 
structs at link time but, depending on the workload of the compiled 
program and the architecture where the program runs, dead field 
elimination might be a worthwhile transformation to apply. Generally 
speaking, when the bottle-neck of an application is given by the memory 
bandwidth of the host system and the memory requested is of a struct 
which can be reduced in size, then that combination of workload, program 
and architecture can benefit from applying dead field elimination. The 
benefits come from removing unnecessary fields from structures and thus 
reducing the memory/cache requirements to represent a structure.

+
+
+
+While challenges exist to fully automate a dead field elimination 
transformation, similar and more powerful optimizations have been 
implemented in the past. Chakrabarti et al [0] implement struct peeling, 
splitting into hot and cold parts of a structure, and field reordering. 
Golovanevsky et al [1] also shows efforts to implement data layout 
optimizations at link time. Unlike the work of Chakrabarti and 
Golovanesky, this text only talks about dead field elimination. This 
doesn't mean that the implementation can't be expanded to perform other 
link-time layout optimizations, it just means that dead field 
elimination is the only transformation that is implemented at the time 
of this writing.

+
+[0] Chakrabarti, Gautam, Fred Chow, and L. PathScale. "Structure layout 
optimizations in the open64 compiler: Design, implementation and 
measurements." Open64 Workshop at the International Symposium on Code 
Generation and Optimization. 2008.

+
+[1] Golovanevsky, Olga, and Ayal Zaks. "Struct-reorg: current status 
and future perspectives." Proceedings of the GCC Developers’ Summit. 2007.

+
+@subsection Overview
+
+The dead field implementation is structured in the following way:
+
+
+@itemize @bullet
+@item
+Collect all types which can refer to a @code{RECORD_TYPE}. This means 
that if we have a pointer to a record, we also collect this pointer. Or 
an array, or a union.

+@item
+Mark types as escaping. More of this in the following section.
+@item
+Find fields which can be deleted. (Iterate over all gimple code and 
find which fields are read.)

+@item
+Create new types with removed fields (and reference these types in 
pointers, arrays, etc.)

+@item
+Modify gimple to include these types.
+@end itemize
+
+
+Most of this code relies on the visitor pattern. Types, Expr, and 
Gimple statements are visited using this pattern. You can find the base 
classes in @file{type-walker.c} @file{expr-walker.c} and 
@file{gimple-walker.c}. There are assertions in place where a type, 
expr, or gimple code is encountered which has not been encountered 
before during the testing of this transformation. This facilitates 
fuzzying of the transformation.

+
+@subsubsection Implementation Details: Is a global variable escaping?
+
+How does the analysis determine whether a global variable is visible to 
code outside the current linking unit? In the file 
@file{gimple-escaper.c} we have a si

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

2020-11-04 Thread Erick Ochoa

From bad08833616e9dd7a212e55b93503200393da942 Mon Sep 17 00:00:00 2001
From: Erick Ochoa 
Date: Sun, 30 Aug 2020 10:21:35 +0200
Subject: [PATCH 5/7] Abort if Gimple produced from C++ or Fortran sources is
 found.

2020-11-04  Erick Ochoa  

* gcc/ipa-field-reorder: Add flag to exit transformation
* gcc/ipa-type-escape-analysis: Same

---
 gcc/ipa-field-reorder.c|  3 +-
 gcc/ipa-type-escape-analysis.c | 53 --
 gcc/ipa-type-escape-analysis.h |  2 ++
 3 files changed, 48 insertions(+), 10 deletions(-)

diff --git a/gcc/ipa-field-reorder.c b/gcc/ipa-field-reorder.c
index 611089ecf24..c23e6a3f818 100644
--- a/gcc/ipa-field-reorder.c
+++ b/gcc/ipa-field-reorder.c
@@ -590,6 +590,7 @@ lto_fr_execute ()
 {
   log ("here in field reordering \n");
   // Analysis.
+  detected_incompatible_syntax = false;
   tpartitions_t escaping_nonescaping_sets
 = partition_types_into_escaping_nonescaping ();
   record_field_map_t record_field_map = find_fields_accessed ();
@@ -597,7 +598,7 @@ lto_fr_execute ()
 = obtain_nonescaping_unaccessed_fields (escaping_nonescaping_sets,
record_field_map, 0);

-  if (record_field_offset_map.empty ())
+  if (detected_incompatible_syntax || record_field_offset_map.empty ())
 return 0;

   // Prepare for transformation.
diff --git a/gcc/ipa-type-escape-analysis.c b/gcc/ipa-type-escape-analysis.c
index 9944580da6c..b06f33e24fb 100644
--- a/gcc/ipa-type-escape-analysis.c
+++ b/gcc/ipa-type-escape-analysis.c
@@ -170,6 +170,10 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-type-escape-analysis.h"
 #include "ipa-dfe.h"

+#define ABORT_IF_NOT_C true
+
+bool detected_incompatible_syntax = false;
+
 // Main function that drives dfe.
 static unsigned int
 lto_dfe_execute ();
@@ -256,13 +260,14 @@ static void
 lto_dead_field_elimination ()
 {
   // Analysis.
+  detected_incompatible_syntax = false;
   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, OPT_Wdfa);
-  if (record_field_offset_map.empty ())
+  if (detected_incompatible_syntax || record_field_offset_map.empty ())
 return;

 // Prepare for transformation.
@@ -589,6 +594,7 @@ 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 (detected_incompatible_syntax) return;
   if (!type)
 return;

@@ -642,9 +648,9 @@ TypeWalker::_walk (const_tree type)
 case POINTER_TYPE:
   this->walk_POINTER_TYPE (type);
   break;
-case REFERENCE_TYPE:
-  this->walk_REFERENCE_TYPE (type);
-  break;
+//case REFERENCE_TYPE:
+//  this->walk_REFERENCE_TYPE (type);
+//  break;
 case ARRAY_TYPE:
   this->walk_ARRAY_TYPE (type);
   break;
@@ -654,18 +660,24 @@ TypeWalker::_walk (const_tree type)
 case FUNCTION_TYPE:
   this->walk_FUNCTION_TYPE (type);
   break;
-case METHOD_TYPE:
-  this->walk_METHOD_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 REFERENCE_TYPE:
+case METHOD_TYPE:
 case QUAL_UNION_TYPE:
 case LANG_TYPE:
 default:
   {
log ("missing %s\n", get_tree_code_name (code));
+#ifdef ABORT_IF_NOT_C
+   detected_incompatible_syntax = true;
+#else
gcc_unreachable ();
+#endif
   }
   break;
 }
@@ -848,6 +860,7 @@ TypeWalker::_walk_arg (const_tree t)
 void
 ExprWalker::walk (const_tree e)
 {
+  if (detected_incompatible_syntax) return;
   _walk_pre (e);
   _walk (e);
   _walk_post (e);
@@ -932,7 +945,11 @@ ExprWalker::_walk (const_tree e)
 default:
   {
log ("missing %s\n", get_tree_code_name (code));
+#ifdef ABORT_IF_NOT_C
+   detected_incompatible_syntax = true;
+#else
gcc_unreachable ();
+#endif
   }
   break;
 }
@@ -1165,6 +1182,7 @@ GimpleWalker::walk ()
   cgraph_node *node = NULL;
   FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
 {
+  if (detected_incompatible_syntax) return;
   node->get_untransformed_body ();
   tree decl = node->decl;
   gcc_assert (decl);
@@ -1411,7 +1429,11 @@ GimpleWalker::_walk_gimple (gimple *stmt)
   // Break if something is unexpected.
   const char *name = gimple_code_name[code];
   log ("gimple code name %s\n", name);
+#ifdef ABORT_IF_NOT_C
+  detected_incompatible_syntax = true;
+#else
   gcc_unreachable ();
+#endif
 }

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

2020-11-04 Thread Erick Ochoa

From 09feb1cc82a5d9851a6b524e37c32554b923b1c4 Mon Sep 17 00:00:00 2001
From: Erick Ochoa 
Date: Thu, 6 Aug 2020 14:07:20 +0200
Subject: [PATCH 2/7] Add Dead Field Elimination

Using the Dead Field Analysis, Dead Field Elimination
automatically transforms gimple to eliminate fields that
are never read.

2020-11-04  Erick Ochoa  

* gcc/Makefile.in: add file to list of sources
* gcc/ipa-dfe.c: New
* gcc/ipa-dfe.h: Same
* gcc/ipa-type-escape-analysis.h: Export code used in dfe.
* gcc/ipa-type-escape-analysis.c: Call transformation

---
 gcc/Makefile.in|1 +
 gcc/ipa-dfe.c  | 1280 
 gcc/ipa-dfe.h  |  250 +++
 gcc/ipa-type-escape-analysis.c |   21 +-
 gcc/ipa-type-escape-analysis.h |   10 +
 5 files changed, 1553 insertions(+), 9 deletions(-)
 create mode 100644 gcc/ipa-dfe.c
 create mode 100644 gcc/ipa-dfe.h

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 8b18c9217a2..8ef6047870b 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1416,6 +1416,7 @@ OBJS = \
init-regs.o \
internal-fn.o \
ipa-type-escape-analysis.o \
+   ipa-dfe.o \
ipa-cp.o \
ipa-sra.o \
ipa-devirt.o \
diff --git a/gcc/ipa-dfe.c b/gcc/ipa-dfe.c
new file mode 100644
index 000..c048fac8621
--- /dev/null
+++ b/gcc/ipa-dfe.c
@@ -0,0 +1,1280 @@
+/* IPA Type Escape Analysis and Dead Field Elimination
+   Copyright (C) 2019-2020 Free Software Foundation, Inc.
+
+  Contributed by Erick Ochoa 
+
+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 elimination (IPA-DFE)
+
+   The goal of this transformation is to
+
+   1) Create new types to replace RECORD_TYPEs which hold dead fields.
+   2) Substitute instances of old RECORD_TYPEs for new RECORD_TYPEs.
+   3) Substitute instances of old FIELD_DECLs for new FIELD_DECLs.
+   4) Fix some instances of pointer arithmetic.
+   5) Relayout where needed.
+
+   First stage - DFA
+   =
+
+   Use DFA to compute the set of FIELD_DECLs which can be deleted.
+
+   Second stage - Reconstruct Types
+   
+
+   This stage is done by two family of classes, the SpecificTypeCollector
+   and the TypeReconstructor.
+
+   The SpecificTypeCollector collects all TYPE_P trees which point to
+   RECORD_TYPE trees returned by DFA.  The TypeReconstructor will create
+   new RECORD_TYPE trees and new TYPE_P trees replacing the old RECORD_TYPE
+   trees with the new RECORD_TYPE trees.
+
+   Third stage - Substitute Types and Relayout
+   ===
+
+   This stage is handled by ExprRewriter and GimpleRewriter.
+   Some pointer arithmetic is fixed here to take into account those 
eliminated

+   FIELD_DECLS.
+ */
+
+#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&q

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

2020-11-04 Thread Erick Ochoa

From 1609f4713b6d0ab2e84e52b4fbd6f645f10a95e7 Mon Sep 17 00:00:00 2001
From: Erick Ochoa 
Date: Fri, 16 Oct 2020 08:49:08 +0200
Subject: [PATCH 6/7] Add heuristic to take into account void* pattern.

We add a heuristic in order to be able to transform functions which
receive void* arguments as a way to generalize over arguments. An
example of this is qsort. The heuristic works by first inspecting
leaves in the call graph. If the leaves only contain a reference
to a single RECORD_TYPE then we color the nodes in the call graph
as "casts are safe in this function and does not call external
visible functions". We propagate this property up the callgraph
until a fixed point is reached. This will later be changed to
use ipa-modref.

2020-11-04  Erick Ochoa  

* ipa-type-escape-analysis.c : Add new heuristic
* ipa-field-reorder.c : Use heuristic
* ipa-type-escape-analysis.h : Change signatures
---
 gcc/ipa-field-reorder.c|   3 +-
 gcc/ipa-type-escape-analysis.c | 186 +++--
 gcc/ipa-type-escape-analysis.h |  72 -
 3 files changed, 246 insertions(+), 15 deletions(-)

diff --git a/gcc/ipa-field-reorder.c b/gcc/ipa-field-reorder.c
index c23e6a3f818..5dcc5a38958 100644
--- a/gcc/ipa-field-reorder.c
+++ b/gcc/ipa-field-reorder.c
@@ -591,8 +591,9 @@ lto_fr_execute ()
   log ("here in field reordering \n");
   // Analysis.
   detected_incompatible_syntax = false;
+  std::map whitelisted = get_whitelisted_nodes();
   tpartitions_t escaping_nonescaping_sets
-= partition_types_into_escaping_nonescaping ();
+= partition_types_into_escaping_nonescaping (whitelisted);
   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,
diff --git a/gcc/ipa-type-escape-analysis.c b/gcc/ipa-type-escape-analysis.c
index b06f33e24fb..fe68eaf70c7 100644
--- a/gcc/ipa-type-escape-analysis.c
+++ b/gcc/ipa-type-escape-analysis.c
@@ -166,6 +166,7 @@ along with GCC; see the file COPYING3.  If not see
 #include 
 #include 
 #include 
+#include 

 #include "ipa-type-escape-analysis.h"
 #include "ipa-dfe.h"
@@ -249,6 +250,99 @@ lto_dfe_execute ()
   return 0;
 }

+/* Heuristic to determine if casting is allowed in a function.
+ * This heuristic attempts to allow casting in functions which follow the
+ * pattern where a struct pointer or array pointer is casted to void* or
+ * char*.  The heuristic works as follows:
+ *
+ * There is a simple per-function analysis that determines whether there
+ * is more than 1 type of struct referenced in the body of the method.
+ * If there is more than 1 type of struct referenced in the body,
+ * then the layout of the structures referenced within the body
+ * cannot be casted.  However, if there's only one type of struct 
referenced

+ * in the body of the function, casting is allowed in the function itself.
+ * The logic behind this is that the if the code follows good programming
+ * practices, the only way the memory should be accessed is via a singular
+ * type. There is also another requisite to this per-function analysis, and
+ * that is that the function can only call colored functions or functions
+ * which are available in the linking unit.
+ *
+ * Using this per-function analysis, we then start coloring leaf nodes 
in the

+ * call graph as ``safe'' or ``unsafe''.  The color is propagated to the
+ * callers of the functions until a fixed point is reached.
+ */
+std::map
+get_whitelisted_nodes ()
+{
+  cgraph_node *node = NULL;
+  std::set nodes;
+  std::set leaf_nodes;
+  std::set leaf_nodes_decl;
+  FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
+  {
+node->get_untransformed_body ();
+nodes.insert(node);
+if (node->callees) continue;
+
+leaf_nodes.insert (node);
+leaf_nodes_decl.insert (node->decl);
+  }
+
+  std::queue worklist;
+  for (std::set::iterator i = leaf_nodes.begin (),
+e = leaf_nodes.end (); i != e; ++i)
+  {
+if (dump_file) fprintf (dump_file, "is a leaf node %s\n", 
(*i)->name ());

+worklist.push (*i);
+  }
+
+  for (std::set::iterator i = nodes.begin (),
+e = nodes.end (); i != e; ++i)
+  {
+worklist.push (*i);
+  }
+
+  std::map map;
+  while (!worklist.empty ())
+  {
+
+if (detected_incompatible_syntax) return map;
+cgraph_node *i = worklist.front ();
+worklist.pop ();
+if (dump_file) fprintf (dump_file, "analyzing %s %p\n", i->name (), i);
+GimpleWhiteLister whitelister;
+whitelister._walk_cnode (i);
+bool no_external = whitelister.does_not_call_external_functions (i, 
map);

+bool before_in_map = map.find (i->decl) != map.end ();
+bool place_callers_in_worklist = !before_in_map;
+if (!before_in_map)
+{
+  map.insert(std::pair(i->decl, no_external));
+} else
+{
+  map[i->decl] = no_exte

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

2020-11-04 Thread Erick Ochoa

From 747b13bf2c6f5b17bc46316998f01483f8039548 Mon Sep 17 00:00:00 2001
From: Erick Ochoa 
Date: Wed, 4 Nov 2020 13:42:35 +0100
Subject: [PATCH 7/7] Getting rid of warnings


2020-11-04  Erick Ochoa  

* gcc/ipa-dfe.c : Change const_tree to tree
* gcc/ipa-dfe.h : same
* gcc/ipa-field-reorder.h : same
* gcc/ipa-type-escape-analysis.c : same, add unused attribute
* gcc/ipa-type-escape-analysis.h : same, add unused attribute

---
 gcc/ipa-dfe.c  | 164 -
 gcc/ipa-dfe.h  |  80 ++---
 gcc/ipa-field-reorder.c|  72 ++--
 gcc/ipa-type-escape-analysis.c | 612 -
 gcc/ipa-type-escape-analysis.h | 312 -
 5 files changed, 621 insertions(+), 619 deletions(-)

diff --git a/gcc/ipa-dfe.c b/gcc/ipa-dfe.c
index 16f594a36b9..e163a32617c 100644
--- a/gcc/ipa-dfe.c
+++ b/gcc/ipa-dfe.c
@@ -126,22 +126,22 @@ along with GCC; see the file COPYING3.  If not see
  * Find all non_escaping types which point to RECORD_TYPEs in
  * record_field_offset_map.
  */
-std::set
+std::set
 get_all_types_pointing_to (record_field_offset_map_t 
record_field_offset_map,

   tpartitions_t casting)
 {
   const tset_t _escaping = casting.non_escaping;

-  std::set specific_types;
+  std::set specific_types;
   TypeStringifier stringifier;

   // Here we are just placing the types of interest in a set.
-  for (std::map::const_iterator i
+  for (std::map::const_iterator i
= record_field_offset_map.begin (),
e = record_field_offset_map.end ();
i != e; ++i)
 {
-  const_tree record = i->first;
+  tree record = i->first;
   std::string name = stringifier.stringify (record);
   specific_types.insert (record);
 }
@@ -150,16 +150,16 @@ get_all_types_pointing_to 
(record_field_offset_map_t record_field_offset_map,


   // SpecificTypeCollector will collect all types which point to the 
types in

   // the set.
-  for (std::set::const_iterator i = non_escaping.begin (),
+  for (std::set::const_iterator i = non_escaping.begin (),
e = non_escaping.end ();
i != e; ++i)
 {
-  const_tree type = *i;
+  tree type = *i;
   specifier.walk (type);
 }

   // These are all the types which need modifications.
-  std::set to_modify = specifier.get_set ();
+  std::set to_modify = specifier.get_set ();
   return to_modify;
 }

@@ -178,24 +178,24 @@ get_all_types_pointing_to 
(record_field_offset_map_t record_field_offset_map,

  */
 reorg_maps_t
 get_types_replacement (record_field_offset_map_t record_field_offset_map,
-  std::set to_modify)
+  std::set to_modify)
 {
   TypeStringifier stringifier;

   TypeReconstructor reconstructor (record_field_offset_map, "reorg");
-  for (std::set::const_iterator i = to_modify.begin (),
+  for (std::set::const_iterator i = to_modify.begin (),
e = to_modify.end ();
i != e; ++i)
 {
-  const_tree record = *i;
+  tree record = *i;
   reconstructor.walk (TYPE_MAIN_VARIANT (record));
 }

-  for (std::set::const_iterator i = to_modify.begin (),
+  for (std::set::const_iterator i = to_modify.begin (),
e = to_modify.end ();
i != e; ++i)
 {
-  const_tree record = *i;
+  tree record = *i;
   reconstructor.walk (record);
 }

@@ -205,11 +205,11 @@ get_types_replacement (record_field_offset_map_t 
record_field_offset_map,
   // Here, we are just making sure that we are not doing anything too 
crazy.

   // Also, we found some types for which TYPE_CACHED_VALUES_P is not being
   // rewritten.  This is probably indicative of a bug in 
TypeReconstructor.

-  for (std::map::const_iterator i = map.begin (),
+  for (std::map::const_iterator i = map.begin (),
  e = map.end ();
i != e; ++i)
 {
-  const_tree o_record = i->first;
+  tree o_record = i->first;
   std::string o_name = stringifier.stringify (o_record);
   log ("original: %s\n", o_name.c_str ());
   tree r_record = i->second;
@@ -220,7 +220,7 @@ get_types_replacement (record_field_offset_map_t 
record_field_offset_map,

continue;
   tree m_record = TYPE_MAIN_VARIANT (r_record);
   // Info: We had a bug where some TYPED_CACHED_VALUES were preserved?
-  tree _o_record = const_tree_to_tree (o_record);
+  tree _o_record = tree_to_tree (o_record);
   TYPE_CACHED_VALUES_P (_o_record) = false;
   TYPE_CACHED_VALUES_P (m_record) = false;

@@ -252,44 +252,44 @@ substitute_types_in_program (reorg_record_map_t map,
 /* Return a set of trees which point to the set of trees
  * that can be modified.
  */
-std::set
+std::set
 SpecificTypeCollector::get_set ()
 {
   return to_return;
 }

 void
-SpecificTy

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

2020-11-04 Thread Erick Ochoa

From 91947eea01a41bd7b17e501ad7d53dfb6499eefc Mon Sep 17 00:00:00 2001
From: Erick Ochoa 
Date: Sun, 9 Aug 2020 10:22:49 +0200
Subject: [PATCH 3/7] Add Field Reordering

Field reordering of structs at link-time

2020-11-04  Erick Ochoa  

* gcc/Makefile.in: add new file to list of sources
* gcc/common.opt: add new flag for field reordering
* gcc/passes.def: add new pass
* gcc/tree-pass.h: same
* gcc/ipa-field-reorder.c: New file
* gcc/ipa-type-escape-analysis.c: Export common functions
* gcc/ipa-type-escape-analysis.h: Same

---
 gcc/Makefile.in|   1 +
 gcc/common.opt |   4 +
 gcc/ipa-dfe.c  |  84 -
 gcc/ipa-dfe.h  |  26 +-
 gcc/ipa-field-reorder.c| 625 +
 gcc/ipa-type-escape-analysis.c |  44 ++-
 gcc/ipa-type-escape-analysis.h |  12 +-
 gcc/passes.def |   1 +
 gcc/tree-pass.h|   2 +
 9 files changed, 751 insertions(+), 48 deletions(-)
 create mode 100644 gcc/ipa-field-reorder.c

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 8ef6047870b..2184bd0fc3d 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1417,6 +1417,7 @@ OBJS = \
internal-fn.o \
ipa-type-escape-analysis.o \
ipa-dfe.o \
+   ipa-field-reorder.o \
ipa-cp.o \
ipa-sra.o \
ipa-devirt.o \
diff --git a/gcc/common.opt b/gcc/common.opt
index 39bb6e100c3..035c1e8850f 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -3484,4 +3484,8 @@ 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).


+fipa-field-reorder
+Common Report Var(flag_ipa_field_reorder) Optimization
+Reorder fields.
+
 ; This comment is to ensure we retain the blank line above.
diff --git a/gcc/ipa-dfe.c b/gcc/ipa-dfe.c
index c048fac8621..16f594a36b9 100644
--- a/gcc/ipa-dfe.c
+++ b/gcc/ipa-dfe.c
@@ -242,9 +242,9 @@ get_types_replacement (record_field_offset_map_t 
record_field_offset_map,

  */
 void
 substitute_types_in_program (reorg_record_map_t map,
-reorg_field_map_t field_map)
+reorg_field_map_t field_map, bool _delete)
 {
-  GimpleTypeRewriter rewriter (map, field_map);
+  GimpleTypeRewriter rewriter (map, field_map, _delete);
   rewriter.walk ();
   rewriter._rewrite_function_decl ();
 }
@@ -358,8 +358,11 @@ TypeReconstructor::set_is_not_modified_yet 
(const_tree t)

 return;

   tree type = _reorg_map[tt];
-  const bool is_modified
+  bool is_modified
 = strstr (TypeStringifier::get_type_identifier (type).c_str (), 
".reorg");

+  is_modified
+|= (bool) strstr (TypeStringifier::get_type_identifier (type).c_str (),
+ ".reorder");
   if (!is_modified)
 return;

@@ -405,14 +408,20 @@ TypeReconstructor::is_memoized (const_tree t)
   return already_changed;
 }

-static tree
-get_new_identifier (const_tree type)
+const char *
+TypeReconstructor::get_new_suffix ()
+{
+  return _suffix;
+}
+
+tree
+get_new_identifier (const_tree type, const char *suffix)
 {
   const char *identifier = TypeStringifier::get_type_identifier 
(type).c_str ();

-  const bool is_new_type = strstr (identifier, "reorg");
+  const bool is_new_type = strstr (identifier, suffix);
   gcc_assert (!is_new_type);
   char *new_name;
-  asprintf (_name, "%s.reorg", identifier);
+  asprintf (_name, "%s.%s", identifier, suffix);
   return get_identifier (new_name);
 }

@@ -468,7 +477,9 @@ TypeReconstructor::_walk_ARRAY_TYPE_post (const_tree t)
   TREE_TYPE (copy) = build_variant_type_copy (TREE_TYPE (copy));
   copy = is_modified ? build_distinct_type_copy (copy) : copy;
   TREE_TYPE (copy) = is_modified ? _reorg_map[TREE_TYPE (t)] : 
TREE_TYPE (copy);
-  TYPE_NAME (copy) = is_modified ? get_new_identifier (copy) : 
TYPE_NAME (copy);

+  TYPE_NAME (copy) = is_modified
+  ? get_new_identifier (copy, this->get_new_suffix ())
+  : TYPE_NAME (copy);
   // This is useful so that we go again through type layout
   TYPE_SIZE (copy) = is_modified ? NULL : TYPE_SIZE (copy);
   tree domain = TYPE_DOMAIN (t);
@@ -521,7 +532,9 @@ TypeReconstructor::_walk_POINTER_TYPE_post 
(const_tree t)


   copy = is_modified ? build_variant_type_copy (copy) : copy;
   TREE_TYPE (copy) = is_modified ? _reorg_map[TREE_TYPE (t)] : 
TREE_TYPE (copy);
-  TYPE_NAME (copy) = is_modified ? get_new_identifier (copy) : 
TYPE_NAME (copy);

+  TYPE_NAME (copy) = is_modified
+  ? get_new_identifier (copy, this->get_new_suffix ())
+  : TYPE_NAME (copy);
   TYPE_CACHED_VALUES_P (copy) = false;

   tree _t = const_tree_to_tree (t);
@@ -616,7 +629,8 @@ TypeReconstructor::_walk_RECORD_TYPE_post (const_tree t)
   tree main = TYPE_MAIN_VARIANT (t);
   tree

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

2020-11-04 Thread Erick Ochoa

From a8c4d5b99d5c4168ede79054396cba514fdf23b5 Mon Sep 17 00:00:00 2001
From: Erick Ochoa 
Date: Mon, 10 Aug 2020 09:10:37 +0200
Subject: [PATCH 4/7] Add documentation for dead field elimination

2020-11-04  Erick Ochoa  

* gcc/Makefile.in: Add file to documentation sources
* gcc/doc/dfe.texi: New section
* gcc/doc/gccint.texi: Include new section

---
 gcc/Makefile.in |   3 +-
 gcc/doc/dfe.texi| 187 
 gcc/doc/gccint.texi |   2 +
 3 files changed, 191 insertions(+), 1 deletion(-)
 create mode 100644 gcc/doc/dfe.texi

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 2184bd0fc3d..7e4c442416d 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -3275,7 +3275,8 @@ TEXI_GCCINT_FILES = gccint.texi gcc-common.texi 
gcc-vers.texi		\

 gnu.texi gpl_v3.texi fdl.texi contrib.texi languages.texi  \
 sourcebuild.texi gty.texi libgcc.texi cfg.texi tree-ssa.texi   \
 loop.texi generic.texi gimple.texi plugins.texi optinfo.texi   \
-match-and-simplify.texi analyzer.texi ux.texi poly-int.texi
+match-and-simplify.texi analyzer.texi ux.texi poly-int.texi\
+dfe.texi

 TEXI_GCCINSTALL_FILES = install.texi install-old.texi fdl.texi \
 gcc-common.texi gcc-vers.texi
diff --git a/gcc/doc/dfe.texi b/gcc/doc/dfe.texi
new file mode 100644
index 000..e8d01d817d3
--- /dev/null
+++ b/gcc/doc/dfe.texi
@@ -0,0 +1,187 @@
+@c Copyright (C) 2001 Free Software Foundation, Inc.
+@c This is part of the GCC manual.
+@c For copying conditions, see the file gcc.texi.
+
+@node Dead Field Elimination
+@chapter Dead Field Elimination
+
+@node Dead Field Elimination Internals
+@section Dead Field Elimination Internals
+
+@subsection Introduction
+
+Dead field elimination is a compiler transformation that removes fields 
from structs. There are several challenges to removing fields from 
structs at link time but, depending on the workload of the compiled 
program and the architecture where the program runs, dead field 
elimination might be a worthwhile transformation to apply. Generally 
speaking, when the bottle-neck of an application is given by the memory 
bandwidth of the host system and the memory requested is of a struct 
which can be reduced in size, then that combination of workload, program 
and architecture can benefit from applying dead field elimination. The 
benefits come from removing unnecessary fields from structures and thus 
reducing the memory/cache requirements to represent a structure.

+
+
+
+While challenges exist to fully automate a dead field elimination 
transformation, similar and more powerful optimizations have been 
implemented in the past. Chakrabarti et al [0] implement struct peeling, 
splitting into hot and cold parts of a structure, and field reordering. 
Golovanevsky et al [1] also shows efforts to implement data layout 
optimizations at link time. Unlike the work of Chakrabarti and 
Golovanesky, this text only talks about dead field elimination. This 
doesn't mean that the implementation can't be expanded to perform other 
link-time layout optimizations, it just means that dead field 
elimination is the only transformation that is implemented at the time 
of this writing.

+
+[0] Chakrabarti, Gautam, Fred Chow, and L. PathScale. "Structure layout 
optimizations in the open64 compiler: Design, implementation and 
measurements." Open64 Workshop at the International Symposium on Code 
Generation and Optimization. 2008.

+
+[1] Golovanevsky, Olga, and Ayal Zaks. "Struct-reorg: current status 
and future perspectives." Proceedings of the GCC Developers’ Summit. 2007.

+
+@subsection Overview
+
+The dead field implementation is structured in the following way:
+
+
+@itemize @bullet
+@item
+Collect all types which can refer to a @code{RECORD_TYPE}. This means 
that if we have a pointer to a record, we also collect this pointer. Or 
an array, or a union.

+@item
+Mark types as escaping. More of this in the following section.
+@item
+Find fields which can be deleted. (Iterate over all gimple code and 
find which fields are read.)

+@item
+Create new types with removed fields (and reference these types in 
pointers, arrays, etc.)

+@item
+Modify gimple to include these types.
+@end itemize
+
+
+Most of this code relies on the visitor pattern. Types, Expr, and 
Gimple statements are visited using this pattern. You can find the base 
classes in @file{type-walker.c} @file{expr-walker.c} and 
@file{gimple-walker.c}. There are assertions in place where a type, 
expr, or gimple code is encountered which has not been encountered 
before during the testing of this transformation. This facilitates 
fuzzying of the transformation.

+
+@subsubsection Implementation Details: Is a global variable escaping?
+
+How does the analysis determine whether a global variable is visible to 
code outside the current linking unit? In the file 
@file{gimple-escaper

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

2020-11-04 Thread Erick Ochoa

Hi,

I've been working on several implementations of data layout 
optimizations for GCC, and I am again kindly requesting for a review of 
the type escape based dead field elimination and field reorg.


This patchset is organized in the following way:

* Adds a link-time warning if dead fields are detected
* Allows for the dead-field elimination transformation to be applied
* Reorganizes fields in structures.
* Adds some documentation
* Gracefully does not apply transformation if unknown syntax is detected.
* Adds a heuristic to handle void* casts

I have tested this transformations as extensively as I can. The way to 
trigger these transformations are:


-fipa-field-reorder and -fipa-type-escape-analysis

Having said that, I welcome all criticisms and will try to address those 
criticisms which I can. Please let me know if you have any questions or 
comments, I will try to answer in a timely manner.


There has been some initial discussion on the GCC mailing list but I'm 
submitting the patches to the patches mailing list now. Some of the 
initial criticisms mentioned on the GCC mailing list previously will be 
addressed in the following days, and I believe there is definitely 
enough time to address them all during Stage 1.


I had to add one last commit to account to some differences in the build 
script on master. I will be working today to squash it, but I still 
wanted to submit these patches in order to start the review process.


I have bootstrapped on aarch64-linux


Re: [PATCH 2/5] Add function tree_code_in_cst.

2020-06-02 Thread Erick Ochoa




On 02/06/2020 14:29, Richard Biener wrote:

On Sat, May 30, 2020 at 12:18 AM Jan Hubicka  wrote:




---
  gcc/tree.h | 11 +++
  1 file changed, 11 insertions(+)

diff --git a/gcc/tree.h b/gcc/tree.h
index bd0c51b2a18..86a4542f58b 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -6156,6 +6156,17 @@ int_bit_position (const_tree field)
 + wi::to_offset (DECL_FIELD_BIT_OFFSET (field))).to_shwi ();
  }

+/* Determine if tree code is a constant */
+inline bool
+tree_code_is_cst (tree op)
+{
+  int code = TREE_CODE (op);
+  if (code == INTEGER_CST || code == REAL_CST || code == COMPLEX_CST
+  || code == VECTOR_CST)
+return true;
+  return false;


We have is_gimple_ip_invariant which I think should suit your purpose -
it return true if tree is a constant, it also accepts things like
addresses of (global) variables, functions and labels.


And otherwise there's CONSTANT_CLASS_P ().

Richard.


Thanks, I'll check these suggestions and remove unnecessary code!




+}
+
  /* Return true if it makes sense to consider alias set for a type T.  */

  inline bool
--
2.18.1



[PATCH 4/5] Export cgraph_externally_visible_p.

2020-05-29 Thread Erick Ochoa




---
 gcc/ipa-ref.h| 2 +-
 gcc/ipa-visibility.c | 5 ++---
 2 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/gcc/ipa-ref.h b/gcc/ipa-ref.h
index 95e29605548..9ff26e2693c 100644
--- a/gcc/ipa-ref.h
+++ b/gcc/ipa-ref.h
@@ -139,5 +139,5 @@ public:

 const char *
 stringify_ipa_ref_use (const ipa_ref_use use);
-
+bool cgraph_externally_visible_p (struct cgraph_node *, bool);
 #endif /* GCC_IPA_REF_H */
diff --git a/gcc/ipa-visibility.c b/gcc/ipa-visibility.c
index 7c854f471e8..8397cc9d61d 100644
--- a/gcc/ipa-visibility.c
+++ b/gcc/ipa-visibility.c
@@ -186,9 +186,8 @@ comdat_can_be_unshared_p (symtab_node *node)

 /* Return true when function NODE should be considered externally 
visible.  */


-static bool
-cgraph_externally_visible_p (struct cgraph_node *node,
-bool whole_program)
+bool
+cgraph_externally_visible_p (struct cgraph_node *node, bool whole_program)
 {
   while (node->transparent_alias && node->definition)
 node = node->get_alias_target ();
--
2.18.1



[PATCH 5/5] Adds ipa-initcall-cp pass.

2020-05-29 Thread Erick Ochoa




This pass is a variant of constant propagation where global
primitive constants with a single write are propagated to multiple
read statements.

ChangeLog:

2020-05-20  Erick Ochoa 

gcc/Makefile.in: Adds new pass
gcc/passes.def: Same
gcc/tree-pass.h: Same
gcc/common.opt: Same
gcc/cgraph.h: Adds new field to cgraph_node
gcc/cgraph.c: Same
gcc/ipa-cp.c: May skip ipa-cp for a function
if initcall-cp has constants to propagate
in that same function
gcc/ipa-initcall-cp.c: New file
---
 gcc/Makefile.in   |1 +
 gcc/cgraph.h  |5 +-
 gcc/common.opt|8 +
 gcc/ipa-cp.c  |2 +-
 gcc/ipa-initcall-cp.c | 1199 +
 gcc/passes.def|1 +
 gcc/tree-pass.h   |1 +
 7 files changed, 1215 insertions(+), 2 deletions(-)
 create mode 100644 gcc/ipa-initcall-cp.c

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 543b477ff18..b94fb633d78 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1401,6 +1401,7 @@ OBJS = \
internal-fn.o \
ipa-cp.o \
ipa-sra.o \
+   ipa-initcall-cp.o \
ipa-devirt.o \
ipa-fnsummary.o \
ipa-polymorphic-call.o \
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index 5ddeb65269b..532b4671609 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -937,7 +937,7 @@ struct GTY((tag ("SYMTAB_FUNCTION"))) cgraph_node : 
public symtab_node

   split_part (false), indirect_call_target (false), local (false),
   versionable (false), can_change_signature (false),
   redefined_extern_inline (false), tm_may_enter_irr (false),
-  ipcp_clone (false), m_uid (uid), m_summary_id (-1)
+  ipcp_clone (false), skip_ipa_cp (false), m_uid (uid), 
m_summary_id (-1)

   {}

   /* Remove the node from cgraph and all inline clones inlined into it.
@@ -1539,6 +1539,9 @@ struct GTY((tag ("SYMTAB_FUNCTION"))) cgraph_node 
: public symtab_node

   unsigned tm_may_enter_irr : 1;
   /* True if this was a clone created by ipa-cp.  */
   unsigned ipcp_clone : 1;
+  /* True if ipa-initcall-cp and therefore we need to skip ipa-cp for 
cgraph

+   * node.  */
+  unsigned skip_ipa_cp : 1;

 private:
   /* Unique id of the node.  */
diff --git a/gcc/common.opt b/gcc/common.opt
index d33383b523c..b2d8d1b0958 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -3408,4 +3408,12 @@ fipa-ra
 Common Report Var(flag_ipa_ra) Optimization
 Use caller save register across calls if possible.

+fipa-initcall-cp-dryrun
+Common Report Var(flag_initcall_cp_dryrun)
+Run analysis for propagating constants across initialization functions.
+
+fipa-initcall-cp
+Common Report Var(flag_initcall_cp) Optimization
+Run transformation for propagation constants across initialization 
functions.

+
 ; This comment is to ensure we retain the blank line above.
diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index c64e9104a94..1036cb0684e 100644
--- a/gcc/ipa-cp.c
+++ b/gcc/ipa-cp.c
@@ -1188,7 +1188,7 @@ initialize_node_lattices (struct cgraph_node *node)

   gcc_checking_assert (node->has_gimple_body_p ());

-  if (!ipa_get_param_count (info))
+  if (!ipa_get_param_count (info) || node->skip_ipa_cp)
 disable = true;
   else if (node->local)
 {
diff --git a/gcc/ipa-initcall-cp.c b/gcc/ipa-initcall-cp.c
new file mode 100644
index 000..02f70b7a908
--- /dev/null
+++ b/gcc/ipa-initcall-cp.c
@@ -0,0 +1,1199 @@
+/* Initcall constant propagation pass.
+   Copyright (C) 2019-2020 Free Software Foundation, Inc.
+
+   Contributed by Erick Ochoa 
+
+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/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "tree.h"
+#include "tree-eh.h"
+#include "gimple.h"
+#include "gimple-expr.h"
+#include "gimple-iterator.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-fnsumma

[PATCH 3/5] Add function path_exists

2020-05-29 Thread Erick Ochoa




---
 gcc/ipa-utils.c | 33 +
 gcc/ipa-utils.h |  4 +++-
 2 files changed, 36 insertions(+), 1 deletion(-)

diff --git a/gcc/ipa-utils.c b/gcc/ipa-utils.c
index 23e7f714306..bd3e79bd2e2 100644
--- a/gcc/ipa-utils.c
+++ b/gcc/ipa-utils.c
@@ -781,3 +781,36 @@ recursive_call_p (tree func, tree dest)
   return false;
   return true;
 }
+
+static bool
+path_exists_dfs (hash_set *visited,
+const cgraph_node *current, const cgraph_node *target)
+{
+  if (current == target)
+return true;
+
+  visited->add (current);
+
+  cgraph_edge *cs;
+  for (cs = current->callees; cs; cs = cs->next_callee)
+{
+  cgraph_node *callee = cs->callee->function_symbol ();
+  if (visited->contains (callee))
+   continue;
+  if (!path_exists_dfs (visited, callee, target))
+   continue;
+
+  return true;
+}
+  return false;
+}
+
+/* Determine if there's a path between two cgraph_nodes */
+bool
+path_exists (const cgraph_node *from, const cgraph_node *to)
+{
+  hash_set visited;
+  bool found_path = path_exists_dfs (, from, to);
+  visited.empty ();
+  return found_path;
+}
diff --git a/gcc/ipa-utils.h b/gcc/ipa-utils.h
index 98edc383461..1706deaee0a 100644
--- a/gcc/ipa-utils.h
+++ b/gcc/ipa-utils.h
@@ -263,4 +263,6 @@ get_odr_name_for_type (tree type)
   return IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (type_name));
 }

-#endif  /* GCC_IPA_UTILS_H  */
+extern bool
+path_exists (const cgraph_node *from, const cgraph_node *to);
+#endif /* GCC_IPA_UTILS_H  */
--
2.18.1



[PATCH 2/5] Add function tree_code_in_cst.

2020-05-29 Thread Erick Ochoa



---
 gcc/tree.h | 11 +++
 1 file changed, 11 insertions(+)

diff --git a/gcc/tree.h b/gcc/tree.h
index bd0c51b2a18..86a4542f58b 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -6156,6 +6156,17 @@ int_bit_position (const_tree field)
  + wi::to_offset (DECL_FIELD_BIT_OFFSET (field))).to_shwi ();
 }

+/* Determine if tree code is a constant */
+inline bool
+tree_code_is_cst (tree op)
+{
+  int code = TREE_CODE (op);
+  if (code == INTEGER_CST || code == REAL_CST || code == COMPLEX_CST
+  || code == VECTOR_CST)
+return true;
+  return false;
+}
+
 /* Return true if it makes sense to consider alias set for a type T.  */

 inline bool
--
2.18.1



[PATCH 1/5] Add stringify_ipa_ref_use function.

2020-05-29 Thread Erick Ochoa




---
 gcc/ipa-ref.c | 22 ++
 gcc/ipa-ref.h |  3 +++
 2 files changed, 25 insertions(+)

diff --git a/gcc/ipa-ref.c b/gcc/ipa-ref.c
index 241828ee973..76459e9cc3d 100644
--- a/gcc/ipa-ref.c
+++ b/gcc/ipa-ref.c
@@ -103,3 +103,25 @@ ipa_ref::referred_ref_list (void)
 {
   return >ref_list;
 }
+
+const char *
+stringify_ipa_ref_use (const ipa_ref_use use)
+{
+  switch (use)
+{
+case IPA_REF_LOAD:
+  return "IPA_REF_LOAD";
+  break;
+case IPA_REF_STORE:
+  return "IPA_REF_STORE";
+  break;
+case IPA_REF_ADDR:
+  return "IPA_REF_ADDR";
+  break;
+case IPA_REF_ALIAS:
+  return "IPA_REF_ALIAS";
+  break;
+default:
+  return "";
+}
+}
diff --git a/gcc/ipa-ref.h b/gcc/ipa-ref.h
index 1de5bd34b82..95e29605548 100644
--- a/gcc/ipa-ref.h
+++ b/gcc/ipa-ref.h
@@ -137,4 +137,7 @@ public:
   vec  GTY((skip)) referring;
 };

+const char *
+stringify_ipa_ref_use (const ipa_ref_use use);
+
 #endif /* GCC_IPA_REF_H */
--
2.18.1



[patch 0/5] ipa-initcall-cp

2020-05-29 Thread Erick Ochoa

Hello everyone,

I wanted to highlight this ticket on bugzilla [0]. It is a missed 
optimization that I worked on. It involves propagating constants across 
function calls at link-time. I am relatively new to GCC and this would 
be my first significant contribution. I have developed a prototype of 
the solution that seems to work well enough to compile and run CPU2017 
intrate benchmarks correctly. I am now in the process of running the 
full suite. Feedback would be appreciated.


Here's an overview of how it works:

ipa-initcall-cp collects all variables with static lifetime that contain 
only a single constant write. Then, for each read of the variable, we 
determine (statically) if the write occurs before read. In order to do 
this, we use both the dominators graph and the static call graph. If the 
write occurs before all reads, then we can safely substitute the read 
with the constant being written to the variable. ipa-initcall-cp works 
across function calls so the read and write do not need to occur on the 
same function.


There are some issues which still need to be addressed, particularly, 
ipa-initcall-cp is at the moment just a prototype and as such it will 
stream in functions and modify them during WPA. I would like to fix 
this, however I am not sure how to properly use clones when modifying 
the function body.


I have tested this against applied my patch to GCC version 10.1. If you 
have any questions, comments, let me know.


[0] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92538


Re: [PATCH] Fixes documentation for gimple_assign functions

2020-05-18 Thread Erick Ochoa

Hi,

I do not have write permissions. I was wondering if I could get write 
after approval permissions. I'm new to GCC but I would like to 
contribute as much as I can, even if it is just small fixes on 
documentations like the ones discussed here.


Thanks!

On 16/05/2020 19:57, Richard Biener wrote:

On May 16, 2020 11:42:02 AM GMT+02:00, Erick Ochoa 
 wrote:

Fixes documentation for gimple_assign functions

This patch corrects the documented function signatures of
gimple_assign*
functions.


OK.

Richard.


ChangeLog:

2020-05-16  Erick Ochoa 

* gcc/gimple.h (gimple_assign_rhs_code): Fix signature
(gimple_assign_rhs_class): same
(gimple_assign_lhs): same
(gimple_assign_lhs_ptr): same
(gimple_assign_rhs): same
(gimple_assign_rhs_ptr): same
(gimple_assign_rhs2): same
(gimple_assign_rh2_ptr): same
(gimple_assign_rhs3): same
(gimple_assign_rh3_ptr): same
(gimple_assign_set_lhs): same
(gimple_assign_set_rhs1): same
(gimple_assign_set_rhs2): same
(gimple_assign_set_rhs3): same
(gimple_assign_cast_p): same

diff --git a/gcc/doc/gimple.texi b/gcc/doc/gimple.texi
index 5e0fc2e0dc5..18264871e88 100644
--- a/gcc/doc/gimple.texi
+++ b/gcc/doc/gimple.texi
@@ -1184,73 +1184,73 @@ case they will be converted to a gimple operand

if necessary.

  This function returns the newly created @code{GIMPLE_ASSIGN} tuple.

-@deftypefn {GIMPLE function} {enum tree_code} gimple_assign_rhs_code
(gimple g)
+@deftypefn {GIMPLE function} {enum tree_code} gimple_assign_rhs_code
(const gimple *g)
  Return the code of the expression computed on the @code{RHS} of
  assignment statement @code{G}.
  @end deftypefn


-@deftypefn {GIMPLE function} {enum gimple_rhs_class}
gimple_assign_rhs_class (gimple g)
+@deftypefn {GIMPLE function} {enum gimple_rhs_class}
gimple_assign_rhs_class (const gimple *g)
  Return the gimple rhs class of the code for the expression
computed on the rhs of assignment statement @code{G}.  This will never
  return @code{GIMPLE_INVALID_RHS}.
  @end deftypefn

-@deftypefn {GIMPLE function} tree gimple_assign_lhs (gimple g)
+@deftypefn {GIMPLE function} tree gimple_assign_lhs (const gimple *g)
  Return the @code{LHS} of assignment statement @code{G}.
  @end deftypefn

-@deftypefn {GIMPLE function} {tree *} gimple_assign_lhs_ptr (gimple g)
+@deftypefn {GIMPLE function} {tree *} gimple_assign_lhs_ptr (gimple
*g)
  Return a pointer to the @code{LHS} of assignment statement @code{G}.
  @end deftypefn

-@deftypefn {GIMPLE function} tree gimple_assign_rhs1 (gimple g)
+@deftypefn {GIMPLE function} tree gimple_assign_rhs1 (const gimple *g)
  Return the first operand on the @code{RHS} of assignment statement
@code{G}.
  @end deftypefn

-@deftypefn {GIMPLE function} {tree *} gimple_assign_rhs1_ptr (gimple
g)
+@deftypefn {GIMPLE function} {tree *} gimple_assign_rhs1_ptr (gimple
*g)
Return the address of the first operand on the @code{RHS} of assignment
  statement @code{G}.
  @end deftypefn

-@deftypefn {GIMPLE function} tree gimple_assign_rhs2 (gimple g)
+@deftypefn {GIMPLE function} tree gimple_assign_rhs2 (const gimple *g)
  Return the second operand on the @code{RHS} of assignment statement
@code{G}.
  @end deftypefn

-@deftypefn {GIMPLE function} {tree *} gimple_assign_rhs2_ptr (gimple
g)
+@deftypefn {GIMPLE function} {tree *} gimple_assign_rhs2_ptr (gimple
*g)
Return the address of the second operand on the @code{RHS} of
assignment
  statement @code{G}.
  @end deftypefn

-@deftypefn {GIMPLE function} tree gimple_assign_rhs3 (gimple g)
+@deftypefn {GIMPLE function} tree gimple_assign_rhs3 (const gimple *g)
  Return the third operand on the @code{RHS} of assignment statement
@code{G}.
  @end deftypefn

-@deftypefn {GIMPLE function} {tree *} gimple_assign_rhs3_ptr (gimple
g)
+@deftypefn {GIMPLE function} {tree *} gimple_assign_rhs3_ptr (gimple
*g)
Return the address of the third operand on the @code{RHS} of assignment
  statement @code{G}.
  @end deftypefn

-@deftypefn {GIMPLE function} void gimple_assign_set_lhs (gimple g,
tree
lhs)
+@deftypefn {GIMPLE function} void gimple_assign_set_lhs (gimple *g,
tree lhs)
  Set @code{LHS} to be the @code{LHS} operand of assignment statement
@code{G}.
  @end deftypefn

-@deftypefn {GIMPLE function} void gimple_assign_set_rhs1 (gimple g,
tree rhs)
+@deftypefn {GIMPLE function} void gimple_assign_set_rhs1 (gimple *g,
tree rhs)
Set @code{RHS} to be the first operand on the @code{RHS} of assignment
  statement @code{G}.
  @end deftypefn

-@deftypefn {GIMPLE function} void gimple_assign_set_rhs2 (gimple g,
tree rhs)
+@deftypefn {GIMPLE function} void gimple_assign_set_rhs2 (gimple *g,
tree rhs)
Set @code{RHS} to be the second operand on the @code{RHS} of assignment
  statement @code{G}.
  @end deftypefn

-@deftypefn {GIMPLE function} void gimple_assign_set_rhs3 (gimple g,
tree rhs)
+@deftypefn {GIMPLE function} void gimple_assign_set_rhs3 (gimple *g,
tree rhs)
Set @code{RHS

[PATCH] Fixes documentation for gimple_assign functions

2020-05-16 Thread Erick Ochoa

Fixes documentation for gimple_assign functions

This patch corrects the documented function signatures of gimple_assign* 
functions.


ChangeLog:

2020-05-16  Erick Ochoa 

* gcc/gimple.h (gimple_assign_rhs_code): Fix signature
(gimple_assign_rhs_class): same
(gimple_assign_lhs): same
(gimple_assign_lhs_ptr): same
(gimple_assign_rhs): same
(gimple_assign_rhs_ptr): same
(gimple_assign_rhs2): same
(gimple_assign_rh2_ptr): same
(gimple_assign_rhs3): same
(gimple_assign_rh3_ptr): same
(gimple_assign_set_lhs): same
(gimple_assign_set_rhs1): same
(gimple_assign_set_rhs2): same
(gimple_assign_set_rhs3): same
(gimple_assign_cast_p): same

diff --git a/gcc/doc/gimple.texi b/gcc/doc/gimple.texi
index 5e0fc2e0dc5..18264871e88 100644
--- a/gcc/doc/gimple.texi
+++ b/gcc/doc/gimple.texi
@@ -1184,73 +1184,73 @@ case they will be converted to a gimple operand 
if necessary.


 This function returns the newly created @code{GIMPLE_ASSIGN} tuple.

-@deftypefn {GIMPLE function} {enum tree_code} gimple_assign_rhs_code 
(gimple g)
+@deftypefn {GIMPLE function} {enum tree_code} gimple_assign_rhs_code 
(const gimple *g)

 Return the code of the expression computed on the @code{RHS} of
 assignment statement @code{G}.
 @end deftypefn


-@deftypefn {GIMPLE function} {enum gimple_rhs_class} 
gimple_assign_rhs_class (gimple g)
+@deftypefn {GIMPLE function} {enum gimple_rhs_class} 
gimple_assign_rhs_class (const gimple *g)

 Return the gimple rhs class of the code for the expression
 computed on the rhs of assignment statement @code{G}.  This will never
 return @code{GIMPLE_INVALID_RHS}.
 @end deftypefn

-@deftypefn {GIMPLE function} tree gimple_assign_lhs (gimple g)
+@deftypefn {GIMPLE function} tree gimple_assign_lhs (const gimple *g)
 Return the @code{LHS} of assignment statement @code{G}.
 @end deftypefn

-@deftypefn {GIMPLE function} {tree *} gimple_assign_lhs_ptr (gimple g)
+@deftypefn {GIMPLE function} {tree *} gimple_assign_lhs_ptr (gimple *g)
 Return a pointer to the @code{LHS} of assignment statement @code{G}.
 @end deftypefn

-@deftypefn {GIMPLE function} tree gimple_assign_rhs1 (gimple g)
+@deftypefn {GIMPLE function} tree gimple_assign_rhs1 (const gimple *g)
 Return the first operand on the @code{RHS} of assignment statement 
@code{G}.

 @end deftypefn

-@deftypefn {GIMPLE function} {tree *} gimple_assign_rhs1_ptr (gimple g)
+@deftypefn {GIMPLE function} {tree *} gimple_assign_rhs1_ptr (gimple *g)
 Return the address of the first operand on the @code{RHS} of assignment
 statement @code{G}.
 @end deftypefn

-@deftypefn {GIMPLE function} tree gimple_assign_rhs2 (gimple g)
+@deftypefn {GIMPLE function} tree gimple_assign_rhs2 (const gimple *g)
 Return the second operand on the @code{RHS} of assignment statement 
@code{G}.

 @end deftypefn

-@deftypefn {GIMPLE function} {tree *} gimple_assign_rhs2_ptr (gimple g)
+@deftypefn {GIMPLE function} {tree *} gimple_assign_rhs2_ptr (gimple *g)
 Return the address of the second operand on the @code{RHS} of assignment
 statement @code{G}.
 @end deftypefn

-@deftypefn {GIMPLE function} tree gimple_assign_rhs3 (gimple g)
+@deftypefn {GIMPLE function} tree gimple_assign_rhs3 (const gimple *g)
 Return the third operand on the @code{RHS} of assignment statement 
@code{G}.

 @end deftypefn

-@deftypefn {GIMPLE function} {tree *} gimple_assign_rhs3_ptr (gimple g)
+@deftypefn {GIMPLE function} {tree *} gimple_assign_rhs3_ptr (gimple *g)
 Return the address of the third operand on the @code{RHS} of assignment
 statement @code{G}.
 @end deftypefn

-@deftypefn {GIMPLE function} void gimple_assign_set_lhs (gimple g, tree 
lhs)
+@deftypefn {GIMPLE function} void gimple_assign_set_lhs (gimple *g, 
tree lhs)
 Set @code{LHS} to be the @code{LHS} operand of assignment statement 
@code{G}.

 @end deftypefn

-@deftypefn {GIMPLE function} void gimple_assign_set_rhs1 (gimple g, 
tree rhs)
+@deftypefn {GIMPLE function} void gimple_assign_set_rhs1 (gimple *g, 
tree rhs)

 Set @code{RHS} to be the first operand on the @code{RHS} of assignment
 statement @code{G}.
 @end deftypefn

-@deftypefn {GIMPLE function} void gimple_assign_set_rhs2 (gimple g, 
tree rhs)
+@deftypefn {GIMPLE function} void gimple_assign_set_rhs2 (gimple *g, 
tree rhs)

 Set @code{RHS} to be the second operand on the @code{RHS} of assignment
 statement @code{G}.
 @end deftypefn

-@deftypefn {GIMPLE function} void gimple_assign_set_rhs3 (gimple g, 
tree rhs)
+@deftypefn {GIMPLE function} void gimple_assign_set_rhs3 (gimple *g, 
tree rhs)

 Set @code{RHS} to be the third operand on the @code{RHS} of assignment
 statement @code{G}.
 @end deftypefn

-@deftypefn {GIMPLE function} bool gimple_assign_cast_p (const_gimple s)
+@deftypefn {GIMPLE function} bool gimple_assign_cast_p (const gimple *s)
 Return true if @code{S} is a type-cast assignment.
 @end deftypefn



[PATCH] Adds wrapper for gimple_return_retval to accept gimple*

2020-05-16 Thread Erick Ochoa

Adds wrapper for gimple_return_retval to accept gimple*

Most functions interact with GIMPLE IL using arguments of type gimple*. 
Functions interacting with GIMPLE_RETURN instructions still use greturn* 
types as arguments. This patch adds wrappers around functions taking 
greturn* as inputs. The wrapper takes gimple* as arguments.


ChangeLog:

2020-05-16  Erick Ochoa 

* gcc/gimple.h (gimple_return_retval): New function
(gimple_return_retval_ptr): same
(gimple_return_set_retval): same
* gcc/gimple.texi (gimple_return_retval): Fix documentation
(gimple_return_retval_ptr): same
(gimple_return_set_retval): same

diff --git a/gcc/doc/gimple.texi b/gcc/doc/gimple.texi
index 5e0fc2e0dc5..d4a73b8397c 100644
--- a/gcc/doc/gimple.texi
+++ b/gcc/doc/gimple.texi
@@ -2234,11 +2234,15 @@ Set @code{REGION} to be the region number for 
@code{GIMPLE_RESX} @code{G}.

 Build a @code{GIMPLE_RETURN} statement whose return value is retval.
 @end deftypefn

-@deftypefn {GIMPLE function} tree gimple_return_retval (const greturn *g)
+@deftypefn {GIMPLE function} tree gimple_return_retval (const gimple *g)
 Return the return value for @code{GIMPLE_RETURN} @code{G}.
 @end deftypefn

-@deftypefn {GIMPLE function} void gimple_return_set_retval (greturn *g, @
+@deftypefn {GIMPLE function} {tree *} gimple_return_retval_ptr (gimple *g)
+Return the return value for @code{GIMPLE_RETURN} @code{G}.
+@end deftypefn
+
+@deftypefn {GIMPLE function} void gimple_return_set_retval (gimple *g, @
 tree retval)
 Set @code{RETVAL} to be the return value for @code{GIMPLE_RETURN} 
@code{G}.

 @end deftypefn
diff --git a/gcc/gimple.h b/gcc/gimple.h
index ca7fec6247e..730803f0924 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -6502,6 +6502,14 @@ gimple_return_retval_ptr (greturn *gs)
   return >op[0];
 }

+static inline tree *
+gimple_return_retval_ptr (gimple *gs)
+{
+  GIMPLE_CHECK (gs, GIMPLE_RETURN);
+  greturn *gr = dyn_cast  (gs);
+  return gimple_return_retval_ptr (gr);
+}
+
 /* Return the return value for GIMPLE_RETURN GS.  */

 static inline tree
@@ -6510,6 +6518,15 @@ gimple_return_retval (const greturn *gs)
   return gs->op[0];
 }

+static inline tree
+gimple_return_retval (const gimple *gs)
+{
+  GIMPLE_CHECK (gs, GIMPLE_RETURN);
+  const greturn *gr = dyn_cast  (gs);
+  return gimple_return_retval (gr);
+}
+
+

 /* Set RETVAL to be the return value for GIMPLE_RETURN GS.  */

@@ -6519,6 +6536,14 @@ gimple_return_set_retval (greturn *gs, tree retval)
   gs->op[0] = retval;
 }

+static inline void
+gimple_return_set_retval (gimple *gs, tree retval)
+{
+  GIMPLE_CHECK (gs, GIMPLE_RETURN);
+  greturn *gr = dyn_cast  (gs);
+  gimple_return_set_retval (gr, retval);
+}
+

 /* Returns true when the gimple statement STMT is any of the OMP 
types.  */





[PATCH] tree-ssa-structalias.c: Fix comments

2020-05-06 Thread Erick Ochoa
This patch fixes some quotations inside comments. The change in syntax 
highlighting was bothering me. I also found a typo.


ChangeLog:

2020-05-06  Erick Ochoa 

* gcc/tree-ssa-struct-alias.c: Fix comments


diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c
index 416a26c996c..37c9b8c26a1 100644
--- a/gcc/tree-ssa-structalias.c
+++ b/gcc/tree-ssa-structalias.c
@@ -57,11 +57,11 @@
as a consequence.

See  "Efficient Field-sensitive pointer analysis for C" by "David
-   J. Pearce and Paul H. J. Kelly and Chris Hankin, at
+   J. Pearce and Paul H. J. Kelly and Chris Hankin", at
http://citeseer.ist.psu.edu/pearce04efficient.html

Also see "Ultra-fast Aliasing Analysis using CLA: A Million Lines
-   of C Code in a Second" by ""Nevin Heintze and Olivier Tardieu" at
+   of C Code in a Second" by "Nevin Heintze and Olivier Tardieu" at
http://citeseer.ist.psu.edu/heintze01ultrafast.html

There are three types of real constraint expressions, DEREF,
@@ -84,7 +84,7 @@
Each variable for a structure field has

1. "size", that tells the size in bits of that field.
-   2. "fullsize, that tells the size in bits of the entire structure.
+   2. "fullsize", that tells the size in bits of the entire structure.
3. "offset", that tells the offset in bits from the beginning of the
structure to this field.

@@ -188,7 +188,7 @@

We probably should compute a per-function unit-ESCAPE solution
propagating it simply like the clobber / uses solutions.  The
-   solution can go alongside the non-IPA espaced solution and be
+   solution can go alongside the non-IPA escaped solution and be
used to query which vars escape the unit through a function.
This is also required to make the escaped-HEAP trick work in IPA mode.



[PATCH] Update documentation on optimizations turned on by O3

2020-04-22 Thread Erick Ochoa

Hello,

I noted that the optimizations turned on by O3 was outdated in the 
documentation. Here is the discussion that brought it to my attention:

https://gcc.gnu.org/pipermail/gcc/2020-April/232164.html

diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index e2bc2559218..a28001a5adf 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -9241,14 +9241,14 @@ by @option{-O2} and also turns on the following 
optimization flags:

 -floop-unroll-and-jam @gol
 -fpeel-loops @gol
 -fpredictive-commoning @gol
+-fsplit-loops @gol
 -fsplit-paths @gol
--ftree-loop-distribute-patterns @gol
 -ftree-loop-distribution @gol
 -ftree-loop-vectorize @gol
 -ftree-partial-pre @gol
 -ftree-slp-vectorize @gol
 -funswitch-loops @gol
--fvect-cost-model @gol
+-fvect-cost-model=dynamic @gol
 -fversion-loops-for-strides}

 @item -O0


Re: [PATCH] Proposal for IPA init() constant propagation

2020-01-23 Thread Erick Ochoa
Forgot to attach the test cases.

On 2020-01-23 10:20 a.m., Erick Ochoa wrote:
> Hi Jan,
> 
> Here is a patch I just rebased against
> 
> commit 2589beb1d1a065f75a5515c9e2698de12a421913 (origin/master, origin/HEAD, 
> master)
> Author: GCC Administrator 
> Date:   Sun Jan 19 00:16:30 2020 +
> 
> I also include some test cases.
> To run test cases, just set your path for the gcc
> executable compiled with the patch and run make all.
> The test verify the semantics of C code haven't changed.
> 
> If ./test $number prints out several "SUCCESS", we haven't
> changed the semantics.
> If there is at least 1 FAILURE, the semantics have changed.
> I just ran and there is all "SUCCESS".
> 
> To verify that the variables have indeed been propagated,
> you can do: grep -n -R 'Eliminated' and it should eliminate
> variables prefixed with "SUCCESS_{0,1,2,3}".
> Eliminating variables prefixed with "FAILURE_" is indicative
> of unsound changes. After running the tests, I confirm the
> patch eliminated the variables targeted.
> 
> 
> Please let me know if you have any questions.
> 
> diff --git a/gcc/Makefile.in b/gcc/Makefile.in
> index b1423d1dbfd..a9bdc162e63 100644
> --- a/gcc/Makefile.in
> +++ b/gcc/Makefile.in
> @@ -1400,6 +1400,7 @@ OBJS = \
>   internal-fn.o \
>   ipa-cp.o \
>   ipa-sra.o \
> + ipa-initcall-cp.o \
>   ipa-devirt.o \
>   ipa-fnsummary.o \
>   ipa-polymorphic-call.o \
> diff --git a/gcc/cgraph.c b/gcc/cgraph.c
> index 95b523d6be5..82cdf660f07 100644
> --- a/gcc/cgraph.c
> +++ b/gcc/cgraph.c
> @@ -3626,6 +3626,7 @@ cgraph_node::get_untransformed_body (void)
>name = lto_get_decl_name_mapping (file_data, name);
>struct lto_in_decl_state *decl_state
>= lto_get_function_in_decl_state (file_data, decl);
> +  //gcc_assert (decl_state != NULL);
>  
>cgraph_node *origin = this;
>while (origin->clone_of)
> diff --git a/gcc/cgraph.h b/gcc/cgraph.h
> index 0ace13df1f9..e9c96fc5d32 100644
> --- a/gcc/cgraph.h
> +++ b/gcc/cgraph.h
> @@ -937,9 +937,11 @@ struct GTY((tag ("SYMTAB_FUNCTION"))) cgraph_node : 
> public symtab_node
>split_part (false), indirect_call_target (false), local (false),
>versionable (false), can_change_signature (false),
>redefined_extern_inline (false), tm_may_enter_irr (false),
> -  ipcp_clone (false), m_uid (uid), m_summary_id (-1)
> +  ipcp_clone (false), m_uid (uid), m_summary_id (-1), skip_ipa_cp(false)
>{}
>  
> +  bool skip_ipa_cp;
> +
>/* Remove the node from cgraph and all inline clones inlined into it.
>   Skip however removal of FORBIDDEN_NODE and return true if it needs to be
>   removed.  This allows to call the function from outer loop walking clone
> diff --git a/gcc/common.opt b/gcc/common.opt
> index 5692cd04374..6ee9852d6b4 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -3376,4 +3376,10 @@ fipa-ra
>  Common Report Var(flag_ipa_ra) Optimization
>  Use caller save register across calls if possible.
>  
> +finitcall-cp
> +Common Report Var(flag_initcall_cp) TBD.
> +
> +finitcall-cp-dryrun
> +Common Report Var(flag_initcall_cp_dryrun) TBD.
> +
>  ; This comment is to ensure we retain the blank line above.
> diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
> index 17da1d8e8a7..13311c24e43 100644
> --- a/gcc/ipa-cp.c
> +++ b/gcc/ipa-cp.c
> @@ -1188,7 +1188,7 @@ initialize_node_lattices (struct cgraph_node *node)
>  
>gcc_checking_assert (node->has_gimple_body_p ());
>  
> -  if (!ipa_get_param_count (info))
> +  if (!ipa_get_param_count (info) || node->skip_ipa_cp)
>  disable = true;
>else if (node->local)
>  {
> diff --git a/gcc/ipa-initcall-cp.c b/gcc/ipa-initcall-cp.c
> new file mode 100644
> index 000..264bf38549d
> --- /dev/null
> +++ b/gcc/ipa-initcall-cp.c
> @@ -0,0 +1,1467 @@
> +/* Initcall constant propagation pass.  */
> +
> +#include "config.h"
> +#include "system.h"
> +#include "coretypes.h"
> +#include "backend.h"
> +#include "tree.h"
> +#include "tree-eh.h"
> +#include "gimple.h"
> +#include "gimple-expr.h"
> +#include "gimple-iterator.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 "

Re: [PATCH] Proposal for IPA init() constant propagation

2020-01-23 Thread Erick Ochoa
Hi Jan,

Here is a patch I just rebased against

commit 2589beb1d1a065f75a5515c9e2698de12a421913 (origin/master, origin/HEAD, 
master)
Author: GCC Administrator 
Date:   Sun Jan 19 00:16:30 2020 +

I also include some test cases.
To run test cases, just set your path for the gcc
executable compiled with the patch and run make all.
The test verify the semantics of C code haven't changed.

If ./test $number prints out several "SUCCESS", we haven't
changed the semantics.
If there is at least 1 FAILURE, the semantics have changed.
I just ran and there is all "SUCCESS".

To verify that the variables have indeed been propagated,
you can do: grep -n -R 'Eliminated' and it should eliminate
variables prefixed with "SUCCESS_{0,1,2,3}".
Eliminating variables prefixed with "FAILURE_" is indicative
of unsound changes. After running the tests, I confirm the
patch eliminated the variables targeted.


Please let me know if you have any questions.

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index b1423d1dbfd..a9bdc162e63 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1400,6 +1400,7 @@ OBJS = \
internal-fn.o \
ipa-cp.o \
ipa-sra.o \
+   ipa-initcall-cp.o \
ipa-devirt.o \
ipa-fnsummary.o \
ipa-polymorphic-call.o \
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index 95b523d6be5..82cdf660f07 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -3626,6 +3626,7 @@ cgraph_node::get_untransformed_body (void)
   name = lto_get_decl_name_mapping (file_data, name);
   struct lto_in_decl_state *decl_state
 = lto_get_function_in_decl_state (file_data, decl);
+  //gcc_assert (decl_state != NULL);
 
   cgraph_node *origin = this;
   while (origin->clone_of)
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index 0ace13df1f9..e9c96fc5d32 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -937,9 +937,11 @@ struct GTY((tag ("SYMTAB_FUNCTION"))) cgraph_node : public 
symtab_node
   split_part (false), indirect_call_target (false), local (false),
   versionable (false), can_change_signature (false),
   redefined_extern_inline (false), tm_may_enter_irr (false),
-  ipcp_clone (false), m_uid (uid), m_summary_id (-1)
+  ipcp_clone (false), m_uid (uid), m_summary_id (-1), skip_ipa_cp(false)
   {}
 
+  bool skip_ipa_cp;
+
   /* Remove the node from cgraph and all inline clones inlined into it.
  Skip however removal of FORBIDDEN_NODE and return true if it needs to be
  removed.  This allows to call the function from outer loop walking clone
diff --git a/gcc/common.opt b/gcc/common.opt
index 5692cd04374..6ee9852d6b4 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -3376,4 +3376,10 @@ fipa-ra
 Common Report Var(flag_ipa_ra) Optimization
 Use caller save register across calls if possible.
 
+finitcall-cp
+Common Report Var(flag_initcall_cp) TBD.
+
+finitcall-cp-dryrun
+Common Report Var(flag_initcall_cp_dryrun) TBD.
+
 ; This comment is to ensure we retain the blank line above.
diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index 17da1d8e8a7..13311c24e43 100644
--- a/gcc/ipa-cp.c
+++ b/gcc/ipa-cp.c
@@ -1188,7 +1188,7 @@ initialize_node_lattices (struct cgraph_node *node)
 
   gcc_checking_assert (node->has_gimple_body_p ());
 
-  if (!ipa_get_param_count (info))
+  if (!ipa_get_param_count (info) || node->skip_ipa_cp)
 disable = true;
   else if (node->local)
 {
diff --git a/gcc/ipa-initcall-cp.c b/gcc/ipa-initcall-cp.c
new file mode 100644
index 000..264bf38549d
--- /dev/null
+++ b/gcc/ipa-initcall-cp.c
@@ -0,0 +1,1467 @@
+/* Initcall constant propagation pass.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "tree.h"
+#include "tree-eh.h"
+#include "gimple.h"
+#include "gimple-expr.h"
+#include "gimple-iterator.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 "gimple-pretty-print.h"
+#include "ssa.h"
+
+bool
+reach_nodes_via_bb1 (cgraph_node *n2);
+static bool
+bb1_dominates_bb2 (basic_block, basic_block, cgraph_node *);
+static bool
+write_before_call (struct ipa_ref *, struct ipa_ref *);
+static bool
+call_before_read (struct ipa_ref *, struct ipa_ref *);
+static hash_map *clone_num_suffixes1;
+static hash_map *func_to_clone;
+static vec
+get_nondominated_callees (cgraph_node *caller, cgraph_node *callee,
+ bool *exitEarly = NULL);
+
+static bool
+comdat_can_be_unshared_p_1 (symtab_node *node)
+{
+  if (!node->externally_visible)
+return true;
+  if (node->address_can_be_compared_p ())
+{
+  struct ipa_ref *ref;
+
+  for (unsigned int i = 0; node->iterate_referring (i, ref); 

[PATCH] Proposal for IPA init() constant propagation

2019-11-15 Thread erick . ochoa

Hello,

we've been working on an lto optimization and would like to receive some 
feedback on this candidate patch.

At the moment the patch compiles correctly when applied to master.
We have some initial test cases in a separate repository and have 
compiled and ran a small subset of CPU 2017 benchmarks with comparable 
results.


The proposed transformation (ipa-initcall-cp) is a variant of 
interprocedural constant propagation.
ip-initcall-cp collects all variables with static lifetime that contain 
only a single write (like in the cases of initialization functions) and 
propagates it to reads across the whole link unit.


In order to run, apply the patch and compile with `-lto -finitcall-cp`.

In order for this transformation to be sound
* writes that can be reached from a function pointer,
* writes that can be reached from a function with outside visibility, 
and

* writes that may happen after any read
are not taken into account.

In order to determine that no read happens before the write, we have to:
* find the main function
* find the function and basic block of the write
*   for each read in another function
* make sure that call to write dominates all callees of the read 
function

*   for each read in the same function
* make sure that write dominates read

Some initial drawbacks:
* We've noticed that we have to disable ipa-cp in order for 
ipa-initcall-cp to run successfully.
This is most likely due to some issue with clones and we will need to 
make some design changes.

The function materialize all clones fails after ipa-initcall-cp.
Suggestions are welcomed.
* At the moment, I still need to clean the code a bit, since it doesn't 
pass the standards.
* I still need to add tests using the testsuite as opposed to running 
them myself.


Some future work:
* At the moment, ipa-initcall-cp only propagates values from a single 
write.
However, we could conceivably improve this work to propagate the first 
n-writes and specialize functions based on the constants.


Here is a link to the bugzilla ticket: 
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92538


2019-11-15  Erick Ochoa 

Proposal for IPA init() constant propagation
* gcc/Makefile.in: Add pass to the build process
* gcc/cgraph.c: Add assertion.
* gcc/common.opt: Add pass
* gcc/ipa-initcall-cp.c: new
* gcc/passes.def: Place pass in opt plan
* gcc/tree-pass.h: Add pass

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 597dc01..f6b11f7 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1369,6 +1369,7 @@ OBJS = \
init-regs.o \
internal-fn.o \
ipa-cp.o \
+   ipa-initcall-cp.o \
ipa-devirt.o \
ipa-fnsummary.o \
ipa-polymorphic-call.o \
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index ea8ab38..e7aa63f 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -3602,6 +3602,8 @@ cgraph_node::get_untransformed_body (void)
   struct lto_in_decl_state *decl_state
 = lto_get_function_in_decl_state (file_data, decl);

+  gcc_assert (decl_state != NULL);
+
   data = lto_get_section_data (file_data, LTO_section_function_body,
   name, , decl_state->compressed);
   if (!data)
diff --git a/gcc/common.opt b/gcc/common.opt
index c160538..31c98f7 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -3320,4 +3320,7 @@ fipa-ra
 Common Report Var(flag_ipa_ra) Optimization
 Use caller save register across calls if possible.

+finitcall-cp
+Common Report Var(flag_initcall_cp) TBD.
+
 ; This comment is to ensure we retain the blank line above.
diff --git a/gcc/ipa-initcall-cp.c b/gcc/ipa-initcall-cp.c
new file mode 100644
index 000..b3f8e0a
--- /dev/null
+++ b/gcc/ipa-initcall-cp.c
@@ -0,0 +1,1149 @@
+/* Initcall constant propagation pass.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "tree.h"
+#include "gimple.h"
+#include "gimple-expr.h"
+#include "gimple-iterator.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 "params.h"
+#include "ipa-fnsummary.h"
+#include "ipa-utils.h"
+#include "tree-ssa-ccp.h"
+#include "stringpool.h"
+#include "attribs.h"
+#include "gimple-pretty-print.h"
+#include "ssa.h"
+
+static bool bb1_dominates_bb2 (basic_block bb1, basic_block bb2, 
cgraph_node *cnode);
+static bool write_before_call (struct ipa_ref *write, struct ipa_ref 
*read);
+static bool call_before_read(struct ipa_ref *write, str