summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErick Ochoa <erick.ochoa@theobroma-systems.com>2020-03-10 14:57:28 +0100
committerErick Ochoa <erick.ochoa@theobroma-systems.com>2020-04-28 23:35:51 +0200
commitbae5500345704fe5fa7f883a418397379fce0553 (patch)
treebe103757ed0d056588ce34ea0d8c81b23b0f6c35
parentd719ddb69b9bc56b46f28689a7dc4d31f980f702 (diff)
Adds test to count field read
-rw-r--r--gcc/ipa-hello-world.c151
-rw-r--r--gcc/ipa-type-escape-analysis.c39
-rw-r--r--gcc/ipa-type-escape-analysis.h21
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-access-counter-00-simple-read-0.c17
4 files changed, 194 insertions, 34 deletions
diff --git a/gcc/ipa-hello-world.c b/gcc/ipa-hello-world.c
index 9040a9360a6..cb69b1ea713 100644
--- a/gcc/ipa-hello-world.c
+++ b/gcc/ipa-hello-world.c
@@ -21,29 +21,142 @@
#include "tree-ssa-ccp.h"
#include "stringpool.h"
#include "attribs.h"
+#include "tree-cfg.h"
+#include <map>
+#include <set>
-static unsigned int
-iphw_execute()
+#include "ipa-type-escape-analysis.h"
+
+
+//TODO: place in header file
+inline static void
+print_function (cgraph_node *cnode)
+{
+ if (!dump_file)
+ return;
+ gcc_assert (cnode);
+ cnode->get_untransformed_body ();
+ dump_function_to_file (cnode->decl, dump_file, TDF_NONE);
+}
+
+typedef std::pair<const_tree /* record */, const_tree /* field */> fields;
+typedef std::pair<unsigned /* reads */, unsigned /* writes */> accesses;
+struct field_comparator
+{
+ bool operator()(const fields &left, const fields &right) const
+ {
+ const_tree left_record = left.first;
+ gcc_assert(left_record);
+ const_tree right_record = right.first;
+ gcc_assert(right_record);
+ // Make sure that we are only comparing valid types...
+ const enum tree_code tree_code_left_record = TREE_CODE(left_record);
+ const enum tree_code tree_code_right_record = TREE_CODE(right_record);
+ const bool is_left_record_type = RECORD_TYPE == tree_code_left_record;
+ const bool is_right_record_type = RECORD_TYPE == tree_code_right_record;
+ const bool are_left_and_right_valid = is_left_record_type && is_right_record_type;
+ gcc_assert(are_left_and_right_valid);
+
+ // Handle typedefs:
+ // Get the main variants of the main types
+ const_tree main_variant_left = TYPE_MAIN_VARIANT(left_record);
+ gcc_assert(main_variant_left);
+ const_tree main_variant_right = TYPE_MAIN_VARIANT(right_record);
+ gcc_assert(main_variant_right);
+ // If they are not equal, we can do a comparison of the types here...
+ const bool are_main_variants_equal = main_variant_left == main_variant_right;
+ const bool left_type_less_than_right_type = main_variant_left < main_variant_right;
+ if (!are_main_variants_equal) return left_type_less_than_right_type;
+
+ // If they are equal, that means that we are comparing fields defined in the same record
+ const_tree left_field = left.second;
+ gcc_assert(left_field);
+ const_tree right_field = right.second;
+ gcc_assert(right_field);
+ // Make sure that they are valid
+ const enum tree_code tree_code_left_field = TREE_CODE(left_field);
+ const enum tree_code tree_code_right_field = TREE_CODE(right_field);
+ const bool is_left_field_field_decl = FIELD_DECL == tree_code_left_field;
+ const bool is_right_field_field_decl = FIELD_DECL == tree_code_right_field;
+ const bool are_left_and_right_field_decls = is_left_field_field_decl && is_right_field_field_decl;
+ gcc_assert(are_left_and_right_field_decls);
+
+ // Compare on the field offset.
+ const_tree left_constant = byte_position(left_field);
+ gcc_assert(left_constant);
+ const_tree right_constant = byte_position(right_field);
+ gcc_assert(right_constant);
+ unsigned left_offset = tree_to_uhwi(left_constant);
+ unsigned right_offset = tree_to_uhwi(right_constant);
+ const bool left_offset_less_than_right_offset = left_offset < right_offset;
+ return left_offset_less_than_right_offset;
+ }
+};
+
+typedef std::map<fields, accesses, field_comparator> field_access_counter;
+typedef std::set<const_tree> record_set;
+
+/* INFO:
+ * Yes, I know we are returning a std::map.
+ * Bad pattern? Maybe, but this will only be called once
+ * and I rather pass by value because that allows
+ * me to have a pure function and not worry about
+ * garbage collection
+ *
+ * TODO: I'd like to change type_map for a std::map
+ * TODO: I'd like to make this a template that can work
+ * for std::map and std::set
+ */
+field_access_counter
+count_access_for_types(record_set &non_escaping_records)
{
- cgraph_node *node;
- FOR_EACH_FUNCTION(node)
+ field_access_counter counter;
+ cgraph_node *cnode = NULL;
+ FOR_EACH_DEFINED_FUNCTION(cnode)
{
- if (dump_file) fprintf(dump_file, "the name of the function is %s\n", node->dump_asm_name());
-
- if (strcmp(node->dump_asm_name(), "bar/49") != 0) continue;
-
- node->get_untransformed_body();
- fprintf(dump_file, "we are where we need to be\n");
- cgraph_node *clone = node->create_version_clone_with_body(
- node->collect_callers(),
- NULL,
- NULL,
- NULL,
- NULL,
- "helloworld",
- NULL);
+ gcc_assert(cnode);
+ print_function(cnode);
}
+ return counter;
+}
+
+bool
+_calculate_non_escaping_records(const_tree const &type, escaping_info *info, record_set *non_escaping_records)
+{
+ gcc_assert(info);
+ gcc_assert(non_escaping_records);
+
+ enum tree_code tree_code_type = TREE_CODE(type);
+ const bool is_record_type = RECORD_TYPE == tree_code_type;
+ if (!is_record_type) return true;
+
+ non_escaping_records->insert(type);
+ return true;
+}
+
+/*
+ * Yes, again, we are passing a std::set
+ * as a value. I don\t care too much since
+ * this is only called once...
+ */
+static record_set
+calculate_non_escaping_records(type_map &escaping_type_info)
+{
+ // We are going to have to traverse the type_map...
+ // This is why I don't really like hash_set...
+ record_set non_escaping_records;
+ escaping_type_info.traverse<record_set*, _calculate_non_escaping_records>(&non_escaping_records);
+ return non_escaping_records;
+}
+
+static unsigned int
+iphw_execute()
+{
+ type_map escaping_types;
+ calculate_escaping_types(escaping_types);
+ record_set non_escaping_records = calculate_non_escaping_records(escaping_types);
+ field_access_counter counter = count_access_for_types(non_escaping_records);
return 0;
}
@@ -51,7 +164,7 @@ namespace {
const pass_data pass_data_ipa_hello_world =
{
SIMPLE_IPA_PASS,
- "hello_world",
+ "hello-world",
OPTGROUP_NONE,
TV_NONE,
(PROP_cfg | PROP_ssa),
diff --git a/gcc/ipa-type-escape-analysis.c b/gcc/ipa-type-escape-analysis.c
index a838f4d445f..b005fe362ec 100644
--- a/gcc/ipa-type-escape-analysis.c
+++ b/gcc/ipa-type-escape-analysis.c
@@ -30,6 +30,7 @@
#include <stdbool.h>
#include "ipa-str-reorg-utils.h"
+#include "ipa-type-escape-analysis.h"
// First we need to collect all types
void
@@ -44,17 +45,6 @@ log (const char * const format, ...)
}
-struct escaping_reason_s {
- unsigned global_is_visible : 1;
- unsigned parameter_is_visible : 1;
- unsigned return_is_visible : 1;
- unsigned type_is_casted : 1;
-};
-typedef struct escaping_reason_s escaping_reason;
-
-struct escaping_info_s { const_tree type; bool is_escaping; escaping_reason reason; };
-typedef struct escaping_info_s escaping_info;
-typedef hash_map<const_tree, escaping_info> type_map;
static bool filter_type (type_map &escape_map, const_tree type);
void update_escape_info (const_tree type, type_map &escape_map, bool is_escaping, escaping_reason reason);
@@ -458,7 +448,7 @@ collect_types(type_map &escape_map)
}
bool
-_print_types( const_tree const &type, escaping_info *info, __attribute((unused)) void*)
+_print_types( const_tree const &type, escaping_info *info, __attribute__((unused)) void*)
{
log("collected,%s\n", get_type_name(type));
bool is_escaping = info->is_escaping;
@@ -705,6 +695,7 @@ is_any_variable_escaping(type_map &escape_map)
}
}
+//TODO: place in header file
inline static void
print_function (cgraph_node *cnode)
{
@@ -847,15 +838,33 @@ cast_to_void_in_program(type_map &escape_map)
}
}
-static unsigned int
-iphw_execute()
+/* INFO:
+ * Yes, I know we are returning a std::map.
+ * Bad pattern? Maybe, but this will only be called once
+ * and I rather pass by value because that allows
+ * me to have a pure function and not worry about
+ * garbage collection
+ *
+ * TODO: I'd like to change type_map for a std::map
+ * TODO: I'd like to make this a template that can work
+ * for std::map and std::set
+ */
+void
+calculate_escaping_types(type_map &escape_map)
{
- type_map escape_map;
collect_types(escape_map);
is_any_variable_escaping(escape_map);
is_any_function_escaping(escape_map);
cast_to_void_in_program(escape_map);
print_types(escape_map);
+}
+
+static unsigned int
+iphw_execute()
+{
+ // We can ignore the return value here...
+ type_map escape_map;
+ calculate_escaping_types(escape_map);
return 0;
}
diff --git a/gcc/ipa-type-escape-analysis.h b/gcc/ipa-type-escape-analysis.h
new file mode 100644
index 00000000000..7dcda948189
--- /dev/null
+++ b/gcc/ipa-type-escape-analysis.h
@@ -0,0 +1,21 @@
+#ifndef GCC_IPA_TYPE_ESCAPE_ANALYSIS_H
+#define GCC_IPA_TYPE_ESCAPE_ANALYSIS_H
+#pragma once
+
+struct escaping_reason_s {
+ unsigned global_is_visible : 1;
+ unsigned parameter_is_visible : 1;
+ unsigned return_is_visible : 1;
+ unsigned type_is_casted : 1;
+};
+typedef struct escaping_reason_s escaping_reason;
+
+struct escaping_info_s { const_tree type; bool is_escaping; escaping_reason reason; };
+typedef struct escaping_info_s escaping_info;
+//TODO: Maybe change this to a std::map?
+//Can we get an idea of what conventions gcc want?
+//Maybe I should ask...
+typedef hash_map<const_tree, escaping_info> type_map;
+void calculate_escaping_types(type_map&);
+
+#endif
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-00-simple-read-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-00-simple-read-0.c
new file mode 100644
index 00000000000..c9e68989142
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-00-simple-read-0.c
@@ -0,0 +1,17 @@
+/* { dg-do link } */
+/* { dg-options "-flto -fipa-hello-world -fdump-ipa-hello-world" } */
+
+#include <stdio.h>
+
+struct astruct_s { _Bool a; _Bool b; _Bool c;};
+struct astruct_s astruct;
+
+
+int
+main ()
+{
+ printf("%d\n", astruct.a);
+}
+
+/* { dg-final { scan-wpa-ipa-dump "collected,astruct_s" "hello-world" } } */
+/* { dg-final { scan-wpa-ipa-dump "astruct_s.a read 1" "hello-world" } } */