summaryrefslogtreecommitdiff
path: root/gcc/ipa-hello-world.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/ipa-hello-world.c')
-rw-r--r--gcc/ipa-hello-world.c569
1 files changed, 0 insertions, 569 deletions
diff --git a/gcc/ipa-hello-world.c b/gcc/ipa-hello-world.c
deleted file mode 100644
index 20c122f3a16..00000000000
--- a/gcc/ipa-hello-world.c
+++ /dev/null
@@ -1,569 +0,0 @@
-#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 "tree-cfg.h"
-#include "gimple.h"
-#include "cfg.h" // needed for gimple-iterator.h
-#include "gimple-iterator.h"
-
-#include <map>
-#include <set>
-
-#include "ipa-type-escape-analysis.h"
-#include "ipa-str-reorg-utils.h"
-#include "ipa-hello-world.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);
-}
-
-//TODO: do not use pair.
-//This names are unintelligible
-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;
- gcc_assert(is_left_record_type);
- gcc_assert(is_right_record_type);
- 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;
-
-enum access_code { READ_ACCESS, WRITE_ACCESS };
-
-void count_access_for_types_in_expr(const_tree expr, const record_set &non_escaping_records, field_access_counter &counter, const enum access_code access);
-
-void
-count_access_for_type_in_component_ref(const_tree component_ref, const record_set &non_escaping_records, field_access_counter &counter, const enum access_code access)
-{
- log("types in component_ref\n");
- gcc_assert(component_ref);
- enum tree_code tree_code_component_ref = TREE_CODE(component_ref);
- const bool is_component_ref = COMPONENT_REF == tree_code_component_ref;
- gcc_assert(is_component_ref);
-
- const_tree _struct = TREE_OPERAND(component_ref, 0);
- gcc_assert(_struct);
-
- log ("going in recursion\n");
- count_access_for_types_in_expr(_struct, non_escaping_records, counter, READ_ACCESS);
- const_tree tree_type_struct = TREE_TYPE(_struct);
- gcc_assert(tree_type_struct);
- enum tree_code tree_type_struct_code = TREE_CODE(tree_type_struct);
- const bool is_record_type = RECORD_TYPE == tree_type_struct_code;
- //TODO: Also write something for UNION_TYPE
- switch (tree_type_struct_code)
- {
- case UNION_TYPE: return; break;
- case RECORD_TYPE: break;
- default: gcc_unreachable(); break;
- }
- gcc_assert(is_record_type);
-
- //FIXME: Future proofing or making things more difficult to read?
- bool in_set =
-#if __cplusplus > 201703L
- non_escaping_records.contains(tree_type_struct)
-#else
- non_escaping_records.find(tree_type_struct) != non_escaping_records.end()
-#endif
- ;
-
- in_set |=
-#if __cplusplus > 201703L
- non_escaping_records.contains(TYPE_MAIN_VARIANT(tree_type_struct))
-#else
- non_escaping_records.find(TYPE_MAIN_VARIANT(tree_type_struct)) != non_escaping_records.end()
-#endif
- ;
-
-
- log("%s is in non_escaping_records ? %s\n", get_type_name(tree_type_struct), in_set ? "true" : "false");
- log("access is %s\n", access == READ_ACCESS ? "read_access" : "write_access");
- log("%s is escaping %s\n", get_type_name(tree_type_struct), in_set ? "true" : "false");
- if (!in_set) return;
-
- const_tree field = TREE_OPERAND(component_ref, 1);
- gcc_assert(field);
- enum tree_code tree_code_field = TREE_CODE(field);
- const bool is_field_decl = FIELD_DECL == tree_code_field;
- gcc_assert(is_field_decl);
-
- const std::pair<const_tree, const_tree> struct_field_pair = std::make_pair(tree_type_struct, field);
- accesses &access_counter = counter[struct_field_pair];
-
- switch (access)
- {
- case READ_ACCESS:
- //TODO: do not use pair.
- //This names are unintelligible
- access_counter.first++;
- log("%s.%s read %d\n", get_type_name(tree_type_struct), get_field_name(field), access_counter.first);
- break;
- case WRITE_ACCESS:
- //TODO: do not use pair.
- //This names are unintelligible
- access_counter.second++;
- log("%s.%s write %d\n", get_type_name(tree_type_struct), get_field_name(field), access_counter.second);
- break;
- default:
- gcc_unreachable();
- break;
- }
-}
-
-static inline void
-is_addr_expr_p(const_tree expr)
-{
- gcc_assert(expr);
- const enum tree_code code = TREE_CODE(expr);
- const bool is_addr_expr = ADDR_EXPR == code;
- gcc_assert(is_addr_expr);
-}
-
-
-void
-count_access_for_type_in_addr_expr(const_tree expr, const record_set &non_escaping_records, field_access_counter &counter, const enum access_code access)
-{
- is_addr_expr_p(expr);
- const_tree op0 = TREE_OPERAND(expr, 0);
- count_access_for_types_in_expr(op0, non_escaping_records, counter, access);
-}
-
-static inline void
-is_array_expr_p(const_tree expr)
-{
- gcc_assert(expr);
- const enum tree_code code = TREE_CODE(expr);
- const bool is_addr_expr = ARRAY_REF == code;
- gcc_assert(is_addr_expr);
-}
-
-void
-count_access_for_type_in_array_expr(const_tree expr, const record_set &non_escaping_records, field_access_counter &counter, const enum access_code access)
-{
- is_array_expr_p(expr);
- const_tree op0 = TREE_OPERAND(expr, 0);
- const_tree op1 = TREE_OPERAND(expr, 1);
- count_access_for_types_in_expr(op0, non_escaping_records, counter, READ_ACCESS);
- count_access_for_types_in_expr(op1, non_escaping_records, counter, READ_ACCESS);
-}
-
-void
-count_access_for_types_in_expr(const_tree expr, const record_set &non_escaping_records, field_access_counter &counter, const enum access_code access)
-{
- log("types in expr\n");
- gcc_assert(expr);
- enum tree_code tree_code_expr = TREE_CODE(expr);
- switch (tree_code_expr)
- {
- case COMPONENT_REF: count_access_for_type_in_component_ref(expr, non_escaping_records, counter, access); break;
- case ADDR_EXPR: count_access_for_type_in_addr_expr(expr, non_escaping_records, counter, access); break;
- case ARRAY_REF : count_access_for_type_in_array_expr(expr, non_escaping_records, counter, access); break;
- default: break;
- }
-}
-
-void
-count_access_for_types_in_lhs(gimple *stmt, const record_set &non_escaping_records, field_access_counter &counter)
-{
- gcc_assert(stmt);
- const enum gimple_code gimple_code_stmt = gimple_code(stmt);
- const bool is_assign = GIMPLE_ASSIGN == gimple_code_stmt;
- const bool is_call = GIMPLE_CALL == gimple_code_stmt;
- const bool is_valid = is_assign || is_call;
- gcc_assert(is_valid);
-
-
- const_tree lhs = is_assign ? gimple_assign_lhs (stmt) : gimple_call_lhs (stmt);
- /* GIMPLE_CALL might have a lhs null.
- * E.g.
- * foo()
- */
- if (!lhs) return;
-
- count_access_for_types_in_expr(lhs, non_escaping_records, counter, WRITE_ACCESS);
-}
-
-void
-count_access_for_types_in_rhs(gimple *stmt, const record_set &non_escaping_records, field_access_counter &counter)
-{
- gcc_assert(stmt);
- const enum gimple_code gimple_code_stmt = gimple_code(stmt);
- const bool is_assign = GIMPLE_ASSIGN == gimple_code_stmt;
- gcc_assert(is_assign);
-
- log("types in rhs\n");
- const enum gimple_rhs_class gimple_rhs_class_stmt = gimple_assign_rhs_class(stmt);
- switch (gimple_rhs_class_stmt)
- {
- case GIMPLE_TERNARY_RHS:
- {
- log("gimple_ternary_rhs\n");
- }
- /* fall through */
- case GIMPLE_BINARY_RHS:
- {
- log("gimple_binary_rhs\n");
- }
- /* fall through */
- case GIMPLE_SINGLE_RHS:
- case GIMPLE_UNARY_RHS:
- {
- const_tree rhs1 = gimple_assign_rhs1(stmt);
- gcc_assert(rhs1);
- count_access_for_types_in_expr(rhs1, non_escaping_records, counter, READ_ACCESS);
- log("gimple_single_rhs\n");
- }
- break;
- default:
- gcc_unreachable();
- break;
- }
-}
-
-inline static void
-is_gimple_assign_p(gimple *stmt)
-{
- gcc_assert(stmt);
- const enum gimple_code code = gimple_code(stmt);
- const bool is_assign = GIMPLE_ASSIGN == code;
- gcc_assert(is_assign);
-}
-
-inline static void
-is_gimple_call_p(gimple *stmt)
-{
- gcc_assert(stmt);
- const enum gimple_code code = gimple_code(stmt);
- const bool is_call = GIMPLE_CALL == code;
- gcc_assert(is_call);
-
-}
-
-void
-count_access_for_types_in_assign(gimple *stmt, const record_set &non_escaping_records, field_access_counter &counter)
-{
- is_gimple_assign_p(stmt);
-
- count_access_for_types_in_rhs(stmt, non_escaping_records, counter);
- count_access_for_types_in_lhs(stmt, non_escaping_records, counter);
-}
-
-static void
-count_access_for_types_in_call_rhs(gimple *stmt, const record_set &non_escaping_records, field_access_counter &counter)
-{
- is_gimple_call_p(stmt);
- unsigned args = gimple_call_num_args (stmt);
-
-
-
- for (unsigned i = 0; i < args; i++)
- {
- const_tree arg = gimple_call_arg (stmt, i);
- count_access_for_types_in_expr(arg, non_escaping_records, counter, READ_ACCESS);
- }
-
-}
-
-void
-count_access_for_types_in_call(gimple *stmt, const record_set &non_escaping_records, field_access_counter &counter)
-{
- is_gimple_call_p(stmt);
- count_access_for_types_in_lhs(stmt, non_escaping_records, counter);
-
- /* TODO: We need to iterate over each argument and find out if it is a read */
- count_access_for_types_in_call_rhs(stmt, non_escaping_records, counter);
-}
-
-void
-count_access_for_types_in_stmt(gimple *stmt, const record_set &non_escaping_records, field_access_counter &counter)
-{
- gcc_assert(stmt);
- const enum gimple_code gimple_code_stmt = gimple_code(stmt);
- switch(gimple_code_stmt)
- {
- case GIMPLE_ASSIGN:
- count_access_for_types_in_assign(stmt, non_escaping_records, counter);
- break;
- case GIMPLE_CALL:
- count_access_for_types_in_call(stmt, non_escaping_records, counter);
- break;
- default:
- break;
- }
-}
-
-void
-count_access_for_types_in_bb(basic_block bb, const record_set &non_escaping_records, field_access_counter &counter)
-{
- gcc_assert(bb);
- for (gimple_stmt_iterator gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi))
- {
- gimple *stmt = gsi_stmt(gsi);
- count_access_for_types_in_stmt(stmt, non_escaping_records, counter);
- }
-}
-
-void
-count_access_for_types_in_function(cgraph_node *cnode, const record_set &non_escaping_records, field_access_counter &counter)
-{
- gcc_assert(cnode);
- tree decl = cnode->decl;
- gcc_assert(decl);
- function *func = DECL_STRUCT_FUNCTION (decl);
- gcc_assert(func);
- push_cfun(func);
- basic_block bb = NULL;
- FOR_EACH_BB_FN (bb, func)
- {
- gcc_assert(bb);
- count_access_for_types_in_bb(bb, non_escaping_records, counter);
- }
- pop_cfun();
-}
-
-void
-init_field_access_counter(field_access_counter &counter, const record_set &non_escaping_records)
-{
- for (auto it = non_escaping_records.cbegin(); it != non_escaping_records.cend(); ++it)
- {
- const_tree record = *it;
- gcc_assert(record);
- enum tree_code tree_code_record_type = TREE_CODE(record);
- const bool is_record_type = RECORD_TYPE == tree_code_record_type;
- gcc_assert(is_record_type);
-
- for (tree field = TYPE_FIELDS (record); field; field = DECL_CHAIN (field))
- {
- gcc_assert(field);
- const std::pair<const_tree, const_tree> struct_field_pair = std::make_pair(record, field);
- counter[struct_field_pair] = { 0, 0 };
- }
- }
-}
-
-/* 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_in_linking_unit(const record_set &non_escaping_records)
-{
- field_access_counter counter;
- init_field_access_counter(counter, non_escaping_records);
- cgraph_node *cnode = NULL;
- FOR_EACH_DEFINED_FUNCTION(cnode)
- {
- gcc_assert(cnode);
- log("printing a defined function\n");
- print_function(cnode);
- count_access_for_types_in_function(cnode, non_escaping_records, counter);
- }
- return counter;
-}
-
-bool
-_calculate_non_escaping_records(const_tree const &type, escaping_info *info, record_set *non_escaping_records)
-{
-
- gcc_assert(info);
- log("NOW: %s is escaping %s\n", get_type_name(type), info->is_escaping ? "true" : "false");
- if (info->is_escaping) return true;
- gcc_assert(non_escaping_records);
-
- enum tree_code tree_code_type = TREE_CODE(type);
- const bool is_record_type = RECORD_TYPE == tree_code_type;
- log("NOW: %s is record %s\n", get_type_name(type), is_record_type ? "true" : "false");
- 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 field_access_counter
-count_field_accesses()
-{
-
- type_map escaping_types;
- calculate_escaping_types(escaping_types);
- const record_set non_escaping_records = calculate_non_escaping_records(escaping_types);
- field_access_counter counter = count_access_for_types_in_linking_unit(non_escaping_records);
- return counter;
-}
-
-record_field_set
-get_fields_to_reorg()
-{
- const field_access_counter counter = count_field_accesses();
- record_field_set records_and_fields_to_reorg;
- for (auto it = counter.cbegin(); it != counter.cend(); ++it)
- {
- fields record_field_pair = it->first;
- accesses counter = it->second;
- const_tree record = record_field_pair.first;
- const_tree field = record_field_pair.second;
- // We are interested in reads == 0;
- unsigned reads = counter.first;
- log("final count for %s.%s = %d\n", get_type_name(record), get_field_name(field), reads);
- if (0 != reads) continue;
-
- records_and_fields_to_reorg.insert(record_field_pair);
- }
-
- return records_and_fields_to_reorg;
-}
-
-static void
-print_record_field_set(const record_field_set &to_reorg)
-{
- log("I am about to print\n");
- for (auto it = to_reorg.cbegin(); it != to_reorg.cend(); ++it)
- {
- fields record_field_pair = *it;
- const_tree record = record_field_pair.first;
- const_tree field = record_field_pair.second;
- // TODO: Some fields / records might be anonymous
- log("will eliminate %s.%s\n", get_type_name(record), get_field_name(field));
- }
-}
-
-
-static unsigned int
-iphw_execute()
-{
- const record_field_set to_reorg = get_fields_to_reorg();
- log("I am about to enter print function\n");
- print_record_field_set(to_reorg);
- return 0;
-}
-
-namespace {
-const pass_data pass_data_ipa_hello_world =
-{
- SIMPLE_IPA_PASS,
- "hello-world",
- OPTGROUP_NONE,
- TV_NONE,
- (PROP_cfg | PROP_ssa),
- 0,
- 0,
- 0,
- 0,
-};
-
-class pass_ipa_hello_world : public simple_ipa_opt_pass
-{
-public:
- pass_ipa_hello_world (gcc::context *ctx)
- : simple_ipa_opt_pass(pass_data_ipa_hello_world, ctx)
- {}
-
- virtual bool gate(function*) { return flag_ipa_hello_world; }
- virtual unsigned execute (function*) { return iphw_execute(); }
-};
-} // anon namespace
-
-simple_ipa_opt_pass*
-make_pass_ipa_hello_world (gcc::context *ctx)
-{
- return new pass_ipa_hello_world (ctx);
-}