summaryrefslogtreecommitdiff
path: root/gcc/ipa-str-reorg-dead-field-eliminate.c
diff options
context:
space:
mode:
authorErick Ochoa <erick.ochoa@theobroma-systems.com>2020-02-04 17:03:26 +0100
committerErick Ochoa <erick.ochoa@theobroma-systems.com>2020-05-14 14:45:30 +0200
commitc64247c9fa452ffc9d587fa98a07216700ae16ba (patch)
treef64075bea8e0bf4d59e066dd46b5921a70e2ba69 /gcc/ipa-str-reorg-dead-field-eliminate.c
parentbf8660842c4163d55a2f54ae179b157d8aa61fd8 (diff)
Initial merge
Diffstat (limited to 'gcc/ipa-str-reorg-dead-field-eliminate.c')
-rw-r--r--gcc/ipa-str-reorg-dead-field-eliminate.c1766
1 files changed, 1753 insertions, 13 deletions
diff --git a/gcc/ipa-str-reorg-dead-field-eliminate.c b/gcc/ipa-str-reorg-dead-field-eliminate.c
index 6ce0c377934..c7a3396a673 100644
--- a/gcc/ipa-str-reorg-dead-field-eliminate.c
+++ b/gcc/ipa-str-reorg-dead-field-eliminate.c
@@ -22,26 +22,1766 @@ along with GCC; see the file COPYING3. If not see
#include "config.h"
#include "system.h"
#include "coretypes.h"
-#include "backend.h"
#include "tree.h"
-#include "gimple.h"
-#include "tree-pass.h"
+#include "options.h"
#include "cgraph.h"
+#include "tree-pass.h"
+#include "tree-cfg.h"
+#include "tree-pretty-print.h"
+#include "gimple-pretty-print.h"
+#include "stringpool.h" //get_identifier
+#include "basic-block.h" //needed for gimple.h
+#include "function.h" //needed for gimple.h
+#include "gimple.h"
+#include "cfg.h" // needed for gimple-iterator.h
#include "gimple-iterator.h"
-#include "pretty-print.h"
-#include <vector>
+#include "stor-layout.h" // layout_type
+#include "fold-const.h" //build_fold_addr_expr
+#include "gimple-ssa.h" // update_stmt
+#include "attribs.h" // decl_attributes
+#include "gimplify.h" //unshare_expr
+#include "value-range.h" // make_ssa_name dependency
+#include "tree-ssanames.h" // make_ssa_name
+#include <vector> // needed for ipa-structure-reorg
#include <map>
#include <set>
-#include "ipa-structure-reorg.h"
-#include "dumpfile.h"
-#include "tree-pretty-print.h"
-#include "gimple-pretty-print.h"
-#include "langhooks.h"
+#include "ipa-structure-reorg.h"
+
+#define test_write(M, ...) \
+ if (dump_file) \
+ { \
+ fprintf(dump_file, M, \
+ ##__VA_ARGS__); \
+ }
+
+#define test_log(M, indent, ...) \
+ if (dump_file) \
+ { \
+ fprintf(dump_file, "%*c" M "\n", indent, ' ', \
+ ##__VA_ARGS__); \
+ }
+
+
+static const char* get_type_name(const_tree type);
+static const char* get_record_name(const_tree record);
+//INFO: cannot change
+//tree expr to const_tree expr
+static void
+log_expr_prologue(const int indent, const char* debug_str, tree expr)
+{
+ const char* expr_str = print_generic_expr_to_str(expr);
+ test_log("<%s \"%s\">", indent, debug_str, expr_str);
+ const_tree type = TREE_TYPE(expr);
+ if (TREE_CODE(type) == ARRAY_TYPE)
+ {
+ const_tree domain = TYPE_DOMAIN(type);
+ const_tree min = TYPE_MIN_VALUE(domain);
+ const_tree max = TYPE_MAX_VALUE(domain);
+ int _min = tree_to_uhwi(min);
+ int _max = tree_to_uhwi(max);
+ test_log("< domain = (%d,%d)>", indent, _min, _max);
+ }
+ test_log("< type = %s>", indent, get_type_name(type));
+}
+
+// This really should be inaccessible to anyone.
+static const_tree
+get_base_type_from_ptr_or_arr_type(const_tree old_pointer_type, const_tree pointer_type, unsigned int &indirection_level)
+{
+ if (pointer_type == NULL) {
+ gcc_assert(TREE_CODE(old_pointer_type) != POINTER_TYPE);
+ gcc_assert(TREE_CODE(old_pointer_type) != ARRAY_TYPE);
+ return old_pointer_type;
+ }
+ return get_base_type_from_ptr_or_arr_type(pointer_type, TREE_TYPE(pointer_type), ++indirection_level);
+}
+
+static const_tree
+get_base_type_from_ptr_or_arr_type(const_tree ptr_or_array, unsigned int &indirection_level)
+{
+ const bool is_array = TREE_CODE(ptr_or_array) == ARRAY_TYPE;
+ const bool is_ptr = TREE_CODE(ptr_or_array) == POINTER_TYPE;
+ const bool is_array_or_ptr = is_array || is_ptr;
+ gcc_assert(is_array_or_ptr);
+ indirection_level = 0;
+ return get_base_type_from_ptr_or_arr_type(ptr_or_array, TREE_TYPE(ptr_or_array), indirection_level);
+}
+
+
+static const_tree
+get_base_type_from_array_type(const_tree array_type, unsigned int &indirection_level)
+{
+ gcc_assert(TREE_CODE(array_type) == ARRAY_TYPE);
+ return get_base_type_from_ptr_or_arr_type(array_type, indirection_level);
+}
+
+static const_tree
+get_base_type_from_array_type(const_tree array_type)
+{
+ gcc_assert(TREE_CODE(array_type) == ARRAY_TYPE);
+ unsigned int indirection_level;
+ return get_base_type_from_array_type(array_type, indirection_level);
+}
+
+static const_tree
+get_base_type_from_pointer_type(const_tree pointer_type, unsigned int &indirection_level)
+{
+ gcc_assert(TREE_CODE(pointer_type) == POINTER_TYPE);
+ return get_base_type_from_ptr_or_arr_type(pointer_type, indirection_level);
+}
+
+static const_tree
+get_base_type_from_pointer_type(const_tree pointer_type)
+{
+ gcc_assert(TREE_CODE(pointer_type) == POINTER_TYPE);
+ unsigned int indirection_level;
+ return get_base_type_from_pointer_type(pointer_type, indirection_level);
+}
+
+// This function should be hidden
+static const_tree
+get_base_type_from_ptr_or_arr_var(const_tree var, unsigned int &indirection_level)
+{
+ tree ptr_or_array = TREE_TYPE(var);
+ const bool is_array = TREE_CODE(ptr_or_array) == ARRAY_TYPE;
+ const bool is_ptr = TREE_CODE(ptr_or_array) == POINTER_TYPE;
+ const bool is_array_or_ptr = is_array || is_ptr;
+ gcc_assert(is_array_or_ptr);
+ const_tree retval = get_base_type_from_ptr_or_arr_type(ptr_or_array, indirection_level);
+ return retval;
+}
+
+static const_tree
+get_base_type_from_array_var(const_tree var, unsigned int &indirection_level)
+{
+ gcc_assert(TREE_CODE(var) != ARRAY_TYPE);
+ tree array_type = TREE_TYPE(var);
+ gcc_assert(TREE_CODE(array_type) == ARRAY_TYPE);
+ const_tree retval = get_base_type_from_ptr_or_arr_var(array_type, indirection_level);
+ return retval;
+}
+
+
+static const_tree
+get_base_type_from_pointer_var(const_tree var, unsigned int &indirection_level)
+{
+ gcc_assert(TREE_CODE(var) != POINTER_TYPE);
+ tree pointer_type = TREE_TYPE(var);
+ gcc_assert(TREE_CODE(pointer_type) == POINTER_TYPE);
+ const_tree retval = get_base_type_from_ptr_or_arr_type(pointer_type, indirection_level);
+ return retval;
+}
+
+//INFO: cannot change
+//tree expr to const_tree expr
+static void
+log_expr_epilogue(const int indent, const char* debug_str, tree expr)
+{
+ const char* expr_str = print_generic_expr_to_str(expr);
+ const_tree type = TREE_TYPE(expr);
+ if (TREE_CODE(type) == ARRAY_TYPE)
+ {
+ const_tree domain = TYPE_DOMAIN(type);
+ const_tree min = TYPE_MIN_VALUE(domain);
+ const_tree max = TYPE_MAX_VALUE(domain);
+ int _min = tree_to_uhwi(min);
+ int _max = tree_to_uhwi(max);
+ test_log("< domain = (%d,%d)>", indent, _min, _max);
+ }
+ test_log("< type = %s>", indent, get_type_name(type));
+ test_log("</%s \"%s\">", indent, debug_str, expr_str);
+}
+
+static const char*
+make_array_postfix(unsigned int indirection_level)
+{
+ gcc_assert(indirection_level > 0);
+ static const char* max_indirection_level_str_array = "[][][][][][][][][][][][][]";
+ static const size_t size_array = strlen(max_indirection_level_str_array );
+ static const size_t postfix_size_array = 2;
+ static const size_t max_indirection_level_array = size_array / postfix_size_array;
+ gcc_assert(indirection_level < max_indirection_level_array);
+ return max_indirection_level_str_array + size_array - (indirection_level * postfix_size_array);
+}
+
+static const char*
+make_pointer_postfix(unsigned int indirection_level)
+{
+ gcc_assert(indirection_level > 0);
+ static const char* max_indirection_level_str_pointer = "************************";
+ static const size_t size_pointer = strlen(max_indirection_level_str_pointer);
+ static const size_t postfix_size_pointer = 1;
+ static const size_t max_indirection_level_pointer = size_pointer / postfix_size_pointer;
+ gcc_assert(indirection_level < max_indirection_level_pointer);
+ return max_indirection_level_str_pointer + size_pointer - (indirection_level * postfix_size_pointer);
+}
+
+static const char*
+make_pointer_or_array_name(const char* base_type, const char* postfix)
+{
+ char *ptr;
+ int calculated_size = strlen(base_type) + strlen(postfix);
+ //TODO: Do not use asprintf?
+ //We'll let exit() deal with freeing this memory.
+ int retval = asprintf(&ptr, "%s%s", base_type, postfix);
+ gcc_assert(retval == calculated_size);
+ return ptr;
+}
+
+static const char*
+make_pointer_name(const char* base_type_name, const unsigned int indirection_level)
+{
+ const char* postfix = make_pointer_postfix(indirection_level);
+ const char* ptr = make_pointer_or_array_name(base_type_name, postfix);
+ return ptr;
+}
+
+static const char*
+make_array_name(const char* base_type_name, const unsigned int indirection_level)
+{
+ const char* postfix = make_array_postfix(indirection_level);
+ const char* ptr = make_pointer_or_array_name(base_type_name, postfix);
+ return ptr;
+}
+
+static const char*
+make_pointer_name(const_tree base_type, const unsigned int indirection_level)
+{
+ const char* struct_name = get_type_name(base_type);
+ return make_pointer_name(struct_name, indirection_level);
+}
+
+static const char*
+make_array_name(const_tree base_type, const unsigned int indirection_level)
+{
+ const char* struct_name = get_type_name(base_type);
+ return make_array_name(struct_name, indirection_level);
+}
+
+static const char*
+make_pointer_name(const_tree pointer)
+{
+ gcc_assert(TREE_CODE(pointer) == POINTER_TYPE);
+ unsigned int indirection_level;
+ const_tree base_type = get_base_type_from_pointer_type(pointer, indirection_level);
+ const char* pointer_name = make_pointer_name(base_type, indirection_level);
+ return pointer_name;
+}
+
+static const char*
+make_array_name(const_tree array)
+{
+ gcc_assert(TREE_CODE(array) == ARRAY_TYPE);
+ unsigned int indirection_level;
+ const_tree base_type = get_base_type_from_array_type(array, indirection_level);
+ const char* array_name = make_array_name(base_type, indirection_level);
+ return array_name;
+}
+
+static const char*
+make_base_name_based_on_old(const char* old_name)
+{
+ gcc_assert(old_name);
+ char *ptr;
+ static const char *suffix = ".reorg";
+ int new_size = strlen(old_name) + strlen(suffix);
+ int retval = asprintf(&ptr, "%s%s", old_name, suffix);
+ gcc_assert(retval == new_size);
+ return ptr;
+}
+
+static const char*
+make_base_name_based_on_old(const_tree base_type)
+{
+ enum tree_code base_code = TREE_CODE(base_type);
+ const bool is_pointer = POINTER_TYPE == base_code;
+ const bool is_array = ARRAY_TYPE == base_code;
+ const bool prohibited = is_pointer || is_array;
+ //This means that this is only for base types
+ //and structs.
+ //I.e. we don't want to generate names which have
+ //[][][] at the end or ****
+ gcc_assert(!prohibited);
+ const char* base_type_name = get_type_name(base_type);
+ return make_base_name_based_on_old(base_type_name);
+}
+
+static const char*
+make_record_name_based_on_old(const char* old_record_name)
+{
+ return make_base_name_based_on_old(old_record_name);
+}
+
+static const char*
+make_array_name_based_on_old(const_tree array)
+{
+ enum tree_code code = TREE_CODE(array);
+ gcc_assert(ARRAY_TYPE == code);
+ unsigned int indirection_level;
+ const_tree base_type = get_base_type_from_array_type(array, indirection_level);
+ const char* reorged_base_type_name = make_base_name_based_on_old(base_type);
+ const char* suffix = make_array_postfix(indirection_level);
+ return make_pointer_or_array_name(reorged_base_type_name, suffix);
+}
+
+static const char*
+make_pointer_name_based_on_old(const_tree pointer)
+{
+ enum tree_code code = TREE_CODE(pointer);
+ gcc_assert(POINTER_TYPE == code);
+ unsigned int indirection_level;
+ const_tree base_type = get_base_type_from_pointer_type(pointer, indirection_level);
+ const char* reorged_base_type_name = make_base_name_based_on_old(base_type);
+ const char* suffix = make_pointer_postfix(indirection_level);
+ return make_pointer_or_array_name(reorged_base_type_name, suffix);
+}
+
+static const char*
+make_record_name_based_on_old(const_tree record)
+{
+ enum tree_code code = TREE_CODE(record);
+ gcc_assert(RECORD_TYPE == code);
+ const char* old_name = get_type_name(record);
+ return make_record_name_based_on_old(old_name);
+}
+
+static bool rewrite_addr_expr_def(tree expr, hash_map<const_tree, const_tree> &type_map, const int indent);
+static bool
+rewrite_addr_expr(tree expr, hash_map<const_tree, const_tree> &type_map, const int indent)
+{
+ log_expr_prologue(indent, "rewrite_addr_expr", expr);
+ bool retval = rewrite_addr_expr_def(expr, type_map, indent + 4);
+ log_expr_epilogue(indent, "rewrite_addr_expr", expr);
+ return retval;
+}
+
+static bool rewrite_array_ref_def(tree expr, hash_map<const_tree, const_tree> &type_map, const int indent);
+
+static bool
+rewrite_array_ref(tree expr, hash_map<const_tree, const_tree> &type_map, const int indent)
+{
+ log_expr_prologue(indent, "rewrite_array_ref", expr);
+ bool retval = rewrite_array_ref_def(expr, type_map, indent + 4);
+ log_expr_epilogue(indent, "rewrite_array_ref", expr);
+ return retval;
+}
+
+static bool rewrite_bin_expr_default_def(tree expr, hash_map<const_tree, const_tree> &type_map, const int indent);
+static bool
+rewrite_bin_expr_default(tree expr, hash_map<const_tree, const_tree> &type_map, const int indent)
+{
+ log_expr_prologue(indent, "rewrite_bin_expr", expr);
+ bool retval = rewrite_bin_expr_default_def(expr, type_map, indent + 4);
+ log_expr_epilogue(indent, "rewrite_bin_expr", expr);
+ return retval;
+}
+
+static bool rewrite_constructor_def(tree expr, hash_map<const_tree, const_tree> &type_map, const int indent);
+static bool
+rewrite_constructor(tree expr, hash_map<const_tree, const_tree> &type_map, const int indent)
+{
+ log_expr_prologue(indent, "rewrite_constructor", expr);
+ bool retval = rewrite_constructor_def(expr, type_map, indent + 4);
+ log_expr_epilogue(indent, "rewrite_constructor", expr);
+ return retval;
+}
+
+static bool rewrite_field_decl_def(tree expr, hash_map<const_tree, const_tree> &type_map, const int indent);
+static bool
+rewrite_field_decl(tree expr, hash_map<const_tree, const_tree> &type_map, const int indent)
+{
+ log_expr_prologue(indent, "rewrite_field_decl", expr);
+ bool retval = rewrite_field_decl_def(expr, type_map, indent + 4);
+ log_expr_epilogue(indent, "rewrite_field_decl", expr);
+ return retval;
+}
+
+static bool rewrite_component_ref_def(tree expr, hash_map<const_tree, const_tree> &type_map, const int indent);
+static bool
+rewrite_component_ref(tree expr, hash_map<const_tree, const_tree> &type_map, const int indent)
+{
+ log_expr_prologue(indent, "rewrite_component_ref", expr);
+ bool retval = rewrite_component_ref_def(expr, type_map, indent+4);
+ log_expr_epilogue(indent, "rewrite_component_ref", expr);
+ return retval;
+}
+
+static bool rewrite_expr_def(tree expr, hash_map<const_tree, const_tree> &type_map, const int indent);
+static bool
+rewrite_expr(tree expr, hash_map<const_tree, const_tree> &type_map, const int indent)
+{
+ log_expr_prologue(indent, "rewrite_expr", expr);
+ bool retval = rewrite_expr_def(expr, type_map, indent+4);
+ log_expr_epilogue(indent, "rewrite_expr", expr);
+ return retval;
+}
+
+static bool rewrite_mem_ref_def(tree expr, hash_map<const_tree, const_tree> &type_map, const int indent);
+
+static bool rewrite_mem_ref(tree expr, hash_map<const_tree, const_tree> &type_map, const int indent)
+{
+ log_expr_prologue(indent, "rewrite_mem_ref", expr);
+ bool retval = rewrite_mem_ref_def(expr, type_map, indent+4);
+ log_expr_epilogue(indent, "rewrite_mem_ref", expr);
+ return retval;
+}
+
+static bool rewrite_plus_expr_def(tree expr, hash_map<const_tree, const_tree> &type_map, const int indent);
+static bool
+rewrite_plus_expr(tree expr, hash_map<const_tree, const_tree> &type_map, const int indent)
+{
+ log_expr_prologue(indent, "rewrite_plux_expr", expr);
+ bool retval = rewrite_plus_expr_def(expr, type_map, indent+4);
+ log_expr_epilogue(indent, "rewrite_plus_expr", expr);
+ return retval;
+}
+
+static bool rewrite_pointer_diff_def(tree expr, hash_map<const_tree, const_tree> &type_map, const int indent);
+static bool
+rewrite_pointer_diff(tree expr, hash_map<const_tree, const_tree> &type_map, const int indent)
+{
+ log_expr_prologue(indent, "rewrite_pointer_diff", expr);
+ bool retval = rewrite_pointer_diff_def(expr, type_map, indent+4);
+ log_expr_epilogue(indent, "rewrite_pointer_diff", expr);
+ return retval;
+}
+
+static bool rewrite_pointer_plus_def(tree expr, hash_map<const_tree, const_tree> &type_map, const int indent);
+static bool
+rewrite_pointer_plus(tree expr, hash_map<const_tree, const_tree> &type_map, const int indent)
+{
+ log_expr_prologue(indent, "rewrite_pointer_plus", expr);
+ bool retval = rewrite_pointer_plus_def(expr, type_map, indent+4);
+ log_expr_epilogue(indent, "rewrite_pointer_plus", expr);
+ return retval;
+}
+
+static bool rewrite_ssa_name_def(tree expr, hash_map<const_tree, const_tree> &type_map, const int indent);
+static bool
+rewrite_ssa_name(tree expr, hash_map<const_tree, const_tree> &type_map, const int indent)
+{
+ log_expr_prologue(indent, "rewrite_ssa_name", expr);
+ bool retval = rewrite_ssa_name_def(expr, type_map, indent+4);
+ log_expr_epilogue(indent, "rewrite_ssa_name", expr);
+ return retval;
+}
+
+static bool rewrite_var_decl_def(tree expr, hash_map<const_tree, const_tree> &type_map, const int indent);
+static bool
+rewrite_var_decl(tree expr, hash_map<const_tree, const_tree> &type_map, const int indent)
+{
+ log_expr_prologue(indent, "rewrite_var_decl", expr);
+ bool retval = rewrite_var_decl_def(expr, type_map, indent+4);
+ log_expr_epilogue(indent, "rewrite_var_decl", expr);
+ return retval;
+}
+
+
+static bool
+rewrite_expr_def(tree expr, hash_map<const_tree, const_tree> &type_map, const int indent)
+{
+ bool retval = false;
+ switch (TREE_CODE(expr))
+ {
+ case ADDR_EXPR:
+ retval = rewrite_addr_expr(expr, type_map, indent);
+ break;
+ case ARRAY_REF:
+ retval = rewrite_array_ref(expr, type_map, indent);
+ break;
+ case COMPONENT_REF:
+ retval = rewrite_component_ref(expr, type_map, indent);
+ break;
+ case CONSTRUCTOR:
+ retval = rewrite_constructor(expr, type_map, indent);
+ break;
+ case FIELD_DECL:
+ retval = rewrite_field_decl(expr, type_map, indent);
+ break;
+ case MEM_REF:
+ retval = rewrite_mem_ref(expr, type_map, indent);
+ break;
+ case MINUS_EXPR:
+ retval = rewrite_bin_expr_default(expr, type_map, indent);
+ break;
+ case MULT_EXPR:
+ retval = rewrite_bin_expr_default(expr, type_map, indent);
+ break;
+ case POINTER_DIFF_EXPR:
+ retval = rewrite_pointer_diff(expr, type_map, indent);
+ break;
+ case POINTER_PLUS_EXPR:
+ retval = rewrite_pointer_plus(expr, type_map, indent);
+ break;
+ case PLUS_EXPR:
+ retval = rewrite_plus_expr(expr, type_map, indent);
+ break;
+ case SSA_NAME:
+ retval = rewrite_ssa_name(expr, type_map, indent);
+ break;
+ case VAR_DECL:
+ retval = rewrite_var_decl(expr, type_map, indent);
+ break;
+ default:
+ {
+ enum tree_code code = TREE_CODE(expr);
+ test_log("code = %s", indent, get_tree_code_name(code));
+ retval = false;
+ }
+ break;
+ }
+
+ return retval;
+}
+
+
+inline static void
+test_print_generic_decl(tree decl)
+{
+ if (!dump_file) return;
+ print_generic_decl(dump_file, decl, TDF_DETAILS);
+}
+
+inline static void
+test_print_gimple_stmt(gimple *stmt)
+{
+ if (!dump_file) return;
+ print_gimple_stmt(dump_file, stmt, 0, TDF_NONE);
+}
+
+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);
+}
+
+static int
+get_field_offset(const_tree field)
+{
+ gcc_assert(TREE_CODE(field) == FIELD_DECL);
+ tree cst = byte_position(field);
+ int offset = tree_to_shwi(cst);
+ return offset;
+}
+
+static const char*
+get_field_name(const_tree field_decl)
+{
+ gcc_assert(field_decl);
+ gcc_assert(TREE_CODE(field_decl) == FIELD_DECL);
+ //TODO: deal with anonymous fields.
+ tree id = DECL_NAME(field_decl);
+ if (!id) return "anonymous";
+ gcc_assert(id);
+ const char* identifier = IDENTIFIER_POINTER(id);
+ gcc_assert(identifier);
+ return identifier;
+}
+
+static const_tree
+get_field_with_name(const_tree record, const char* identifier)
+{
+ gcc_assert(record);
+ gcc_assert(TREE_CODE(record) == RECORD_TYPE);
+ for (tree field = TYPE_FIELDS(record); field; field = DECL_CHAIN(field))
+ {
+ const char* field_identifier = get_field_name(field);
+ const bool is_same_name = strcmp(field_identifier, identifier) == 0;
+ if (!is_same_name) continue;
+
+ gcc_assert(TREE_CODE(field) == FIELD_DECL);
+ return field;
+ }
+ //WONTFIX, INFO
+ //WE MUST ALWAYS SUCCEED.
+ gcc_unreachable();
+ return NULL;
+}
+
+static const char*
+get_record_name(const_tree record)
+{
+ gcc_assert(record);
+ gcc_assert(TREE_CODE(record) == RECORD_TYPE);
+ //TODO: deal with anonymous structs.
+ //Some records don't have identifier pointers
+ tree name_tree = TYPE_NAME(record);
+ if (TREE_CODE(name_tree) == TYPE_DECL) {
+ //TODO: For now
+ gcc_unreachable();
+ // Maybe?
+ tree original_type = DECL_ORIGINAL_TYPE(name_tree);
+ tree type_name = DECL_NAME(name_tree);
+ return IDENTIFIER_POINTER(type_name);
+ }
+ gcc_assert(name_tree);
+ const char* identifier = IDENTIFIER_POINTER(name_tree);
+ gcc_assert(identifier);
+ return identifier;
+}
+
+static const char*
+get_array_name(const_tree array)
+{
+ gcc_assert(array);
+ gcc_assert(TREE_CODE(array) == ARRAY_TYPE);
+ const bool is_modified = TYPE_NAME(array);
+ if (is_modified) return IDENTIFIER_POINTER(TYPE_NAME(array));
+
+ return make_array_name(array);
+}
+
+static const char*
+get_pointer_name(const_tree pointer)
+{
+ gcc_assert(pointer);
+ gcc_assert(TREE_CODE(pointer) == POINTER_TYPE);
+ const bool is_modified = TYPE_NAME(pointer);
+ if (is_modified) return IDENTIFIER_POINTER(TYPE_NAME(pointer));
+
+ const char* new_pointer_name = make_pointer_name(pointer);
+ return new_pointer_name;
+}
+
+static const char*
+get_type_name(const_tree type)
+{
+ enum tree_code code = TREE_CODE(type);
+ switch(code)
+ {
+ case ARRAY_TYPE:
+ return get_array_name(type);
+ break;
+ case POINTER_TYPE:
+ return get_pointer_name(type);
+ break;
+ case RECORD_TYPE:
+ return get_record_name(type);
+ break;
+ default:
+ //TODO: generalize even more?
+ //wait for experimental results to dictate what
+ //else we should specify.
+ return get_tree_code_name(code);
+ break;
+ }
+ return NULL;
+}
+
+static bool filter_out_boring_type(const_tree type, hash_map<const_tree, tree> &map);
+
+static bool
+is_interesting_struct(const_tree record)
+{
+ enum tree_code code = TREE_CODE(record);
+ gcc_assert(code == RECORD_TYPE);
+
+ const char* record_name = get_type_name(record);
+ const int buffer_size = 1024;
+ char interesting_structs[buffer_size];
+ static const int cli_length = strlen(flag_ipa_typelist_struct);
+ gcc_assert(cli_length < buffer_size);
+ strcpy(interesting_structs, flag_ipa_typelist_struct);
+ bool retval = false;
+ char *save_ptr;
+ char* token = strtok_r(interesting_structs, ",", &save_ptr);
+ while(token)
+ {
+ retval |= strcmp(record_name, token) == 0;
+ token = strtok_r(NULL, ",", &save_ptr);
+ }
+ return retval;
+}
+
+static bool
+is_interesting_field(const_tree field)
+{
+ enum tree_code code = TREE_CODE(field);
+ gcc_assert(code == FIELD_DECL);
+
+ const char* field_name = get_field_name(field);
+ const int buffer_size = 1024;
+ char interesting_fields[buffer_size];
+ static const int cli_length = strlen(flag_ipa_typelist_field);
+ gcc_assert(cli_length < buffer_size);
+ strcpy(interesting_fields, flag_ipa_typelist_field);
+ bool retval = false;
+ char *save_ptr;
+ char* token = strtok_r(interesting_fields, ",", &save_ptr);
+ while(token)
+ {
+ retval |= strcmp(field_name, token) == 0;
+ token = strtok_r(NULL, ",", &save_ptr);
+ }
+ return retval;
+}
+
+static bool
+filter_out_boring_record(const_tree record, hash_map<const_tree, tree> &map)
+{
+ test_log("filter_out_boring_record", 0);
+ enum tree_code code = TREE_CODE(record);
+ gcc_assert(code == RECORD_TYPE);
+
+
+ for(tree field = TYPE_FIELDS(record); field ; field = DECL_CHAIN(field))
+ {
+ tree field_type = TREE_TYPE(field);
+ bool is_boring = filter_out_boring_type(field_type, map);
+ if (!is_boring) return false;
+ }
+
+ return !is_interesting_struct(record);
+}
+
+static bool
+filter_out_boring_pointer(const_tree pointer, hash_map<const_tree, tree>&map)
+{
+ test_log("filter_out_boring_pointer", 0);
+ enum tree_code code = TREE_CODE(pointer);
+ gcc_assert(code == POINTER_TYPE);
+ const_tree base_type = get_base_type_from_pointer_type(pointer);
+ return filter_out_boring_type(base_type, map);
+}
+
+static bool
+filter_out_boring_array(const_tree array, hash_map<const_tree, tree>&map)
+{
+ enum tree_code code = TREE_CODE(array);
+ gcc_assert(code == ARRAY_TYPE);
+ const_tree base_type = get_base_type_from_array_type(array);
+ return filter_out_boring_type(base_type, map);
+}
+
+static bool
+filter_out_boring_type(const_tree type, hash_map<const_tree, tree> &map)
+{
+ if (!type) {
+ test_log("filter_out_boring_type (NULL)", 0);
+ return true;
+ }
+
+ // maybe something like, if the type is
+ // equivalent to one of the already
+ // interesting types, then it should
+ // also be interesting..?
+ // But then, imagine this happens out of order...
+ // We get type A which is non-interesting
+ // type A is equivalent to B
+ // then we receive type B which is interesting
+ // this approach would fail...
+ test_log("filter_out_boring_type %s", 0, get_type_name(type));
+
+ enum tree_code code = TREE_CODE(type);
+ bool retval = true;
+ switch(code)
+ {
+ case ARRAY_TYPE:
+ retval = filter_out_boring_array(type, map);
+ break;
+ case POINTER_TYPE:
+ retval = filter_out_boring_pointer(type, map);
+ break;
+ case RECORD_TYPE:
+ retval = filter_out_boring_record(type, map);
+ break;
+ default:
+ {
+ test_log("default in tree code %s", 0, get_tree_code_name(code));
+ retval = true;
+ }
+ break;
+ }
+
+ if (!retval) {
+ test_log("putting %s", 0, get_type_name(type));
+ map.put(type, NULL);
+ }
+ return retval;
+}
+
+static bool
+filter_var_decls(tree var_decl, hash_map<const_tree, tree> &type_map)
+{
+ gcc_assert(var_decl);
+ gcc_assert(TREE_CODE(var_decl) == VAR_DECL);
+ tree type = TREE_TYPE(var_decl);
+ return filter_out_boring_type(type, type_map);
+}
+
+static bool
+filter_parm_decls(tree parm_decl, hash_map<const_tree, tree>& type_map)
+{
+ gcc_assert(parm_decl);
+ gcc_assert(TREE_CODE(parm_decl) == PARM_DECL);
+ tree type = TREE_TYPE(parm_decl);
+ return filter_out_boring_type(type, type_map);
+}
+
+static void
+collect_parm_declarations(cgraph_node *cnode, bool (*filter)(tree, hash_map<const_tree, tree>&), hash_map<const_tree, tree> &decl_map)
+{
+ gcc_assert(cnode);
+ //TODO: Do we need to get_untransformed_body_here?
+ for (tree parm = DECL_ARGUMENTS(cnode->decl); parm; parm = DECL_CHAIN(parm))
+ {
+ bool filter_out = (*filter)(parm, decl_map);
+ if (filter_out) continue;
+
+ tree type = TREE_TYPE(parm);
+ tree *ptr = decl_map.get(type);
+ // We already have this type.
+ if (ptr) continue;
+
+ const char* type_identifier = get_type_name(type);
+ test_log("collecting,%s", 0, type_identifier);
+ decl_map.put(type, NULL);
+ }
+}
+
+//TODO: It would be nice to have this as an iterator
+//TODO: Maybe after the filter, there should be
+//a function that takes a type and gets you
+//an identifier string.
+static void
+collect_local_declarations(cgraph_node* cnode, bool (*filter)(tree, hash_map<const_tree, tree>&), hash_map<const_tree, tree> &decl_map)
+{
+ gcc_assert(cnode);
+ int i = 0;
+ function *func = DECL_STRUCT_FUNCTION(cnode->decl);
+ //TODO: What condition do I need to check for this one?
+ cnode->get_untransformed_body();
+ tree var_decl = NULL;
+ FOR_EACH_LOCAL_DECL(func, i, var_decl)
+ {
+ bool filter_out = (*filter)(var_decl, decl_map);
+ if (filter_out) continue;
+
+ tree type = TREE_TYPE(var_decl);
+ const char* type_identifier = get_type_name(type);
+ test_log("collecting,%s", 0, type_identifier);
+ decl_map.put(type, NULL);
+ }
+}
+
+static void
+collect_orig_structs(hash_map<const_tree, tree> &type_map)
+{
+ cgraph_node *cnode = NULL;
+ FOR_EACH_DEFINED_FUNCTION(cnode)
+ {
+ print_function(cnode);
+ collect_parm_declarations(cnode, &filter_parm_decls, type_map);
+ collect_local_declarations(cnode, &filter_var_decls, type_map);
+ }
+}
+
+
+
+static const_tree make_new_type_based_on_old(const_tree old, hash_map<const_tree, const_tree>* mod_type_map);
+
+/*
+ * This method will copy the parameter
+ * and delete the field named "delete_me"
+ * int the copy. The offsets will be adjusted
+ * to account for the deleted parameter
+ */
+static const_tree
+make_new_record_based_on_old(const_tree old,
+ hash_map<const_tree, const_tree>* mod_type_map)
+{
+ const_tree *new_record_ptr = mod_type_map->get(old);
+ gcc_assert(!new_record_ptr);
+
+ //TODO: You will not have this guarantee in the end,
+ //we need an API to let this method know which structs will be
+ //deleted, or someting similar to that.
+ const char* old_name = get_type_name(old);
+ bool will_definitely_change = is_interesting_struct(old);
+
+ tree new_record = make_node(RECORD_TYPE);
+ const char* new_name = make_record_name_based_on_old(old_name);
+ tree new_record_name = get_identifier(new_name);
+ TYPE_NAME(new_record) = new_record_name;
+
+ tree prev_new_field = NULL;
+ for(tree old_field = TYPE_FIELDS(old); old_field; old_field = DECL_CHAIN(old_field))
+ {
+ const bool are_field_names_equal = is_interesting_field(old_field);
+
+ if (are_field_names_equal && will_definitely_change) {
+ continue;
+ }
+
+ tree new_field = make_node(FIELD_DECL);
+ DECL_NAME(new_field) = DECL_NAME(old_field);
+ tree old_field_type = TREE_TYPE(old_field);
+ const_tree new_field_type = make_new_type_based_on_old(TREE_TYPE(old_field), mod_type_map);
+ test_log("inside making new field, %s %s", 0, get_type_name(old_field_type), get_type_name(new_field_type));
+ TREE_TYPE(new_field) = (tree) new_field_type;
+ DECL_SOURCE_LOCATION(new_field) = DECL_SOURCE_LOCATION(old_field);
+ SET_DECL_ALIGN(new_field, DECL_ALIGN(old_field));
+ DECL_USER_ALIGN(new_field) = DECL_ALIGN(old_field);
+ TREE_ADDRESSABLE (new_field) = TREE_ADDRESSABLE (old_field);
+ DECL_NONADDRESSABLE_P (new_field) = !TREE_ADDRESSABLE (old_field);
+ TREE_THIS_VOLATILE (new_field) = TREE_THIS_VOLATILE (old_field);
+ // DECL_FIELD_OFFSET and DECL_FIELD_BIT_OFFSET
+ // are actually set by layout_type.
+ const bool first_new_field = !prev_new_field;
+ if (first_new_field)
+ {
+ TYPE_FIELDS(new_record) = new_field;
+ }
+ else
+ {
+ DECL_CHAIN(prev_new_field) = new_field;
+ }
+
+ prev_new_field = new_field;
+ }
+
+
+ layout_type(new_record);
+
+
+ for(tree new_field = TYPE_FIELDS(new_record); new_field; new_field= DECL_CHAIN(new_field))
+ {
+ const char* new_field_name = get_field_name(new_field);
+ int new_offset = get_field_offset(new_field);
+ test_log("offset,%s,%s,%d", 0, new_name, new_field_name, new_offset);
+ }
+
+ const_tree *ptr = mod_type_map->get(old);
+ if (ptr) return *ptr;
+
+
+ //WONTFIX: Think about: Create pointers and arrays to record up to a limit...
+ //Will this ensure that typedefs shouldn't matter, up to the limit?
+ //No, because we do not have the old type to provide a map between the old
+ //and the new...
+
+ mod_type_map->put(old, new_record);
+ return new_record;
+}
+
+const_tree
+make_new_array_based_on_old(const_tree old_type,
+ hash_map<const_tree, const_tree>* mod_type_map)
+{
+ gcc_assert(TREE_CODE(old_type) == ARRAY_TYPE);
+ const_tree *new_type_ptr = mod_type_map->get(old_type);
+ gcc_assert(!new_type_ptr);
+
+ const char* ptr = make_array_name_based_on_old(old_type);
+ tree new_array = make_node(ARRAY_TYPE);
+ TYPE_NAME(new_array) = get_identifier(ptr);
+ TYPE_DOMAIN(new_array) = TYPE_DOMAIN(old_type);
+ TREE_TYPE(new_array) = (tree) make_new_type_based_on_old(TREE_TYPE(old_type), mod_type_map);
+ layout_type(new_array);
+
+ const_tree *ptr_2 = mod_type_map->get(old_type);
+ if (ptr_2) return *ptr_2;
+
+ mod_type_map->put(old_type, new_array);
+
+ return new_array;
+}
+
+
+static const_tree
+make_new_pointer_based_on_old(const_tree old,
+ hash_map<const_tree, const_tree>* mod_type_map)
+{
+ test_log("make_new_pointer_based_on_old %s", 0, get_type_name(old));
+ const_tree *already_computed = mod_type_map->get(old);
+ gcc_assert(!already_computed);
+
+ gcc_assert(TREE_CODE(old) == POINTER_TYPE);
+
+ tree new_pointer = make_node(POINTER_TYPE);
+ const char* ptr = make_pointer_name_based_on_old(old);
+
+ TYPE_NAME(new_pointer) = get_identifier(ptr);
+ SET_TYPE_MODE(new_pointer, TYPE_MODE(old));
+ tree old_type = TREE_TYPE(old);
+ gcc_assert(old_type);
+ const_tree new_type = make_new_type_based_on_old(old_type, mod_type_map);
+ //We do not need it...
+ if (new_type == old_type) return old;
+
+ TREE_TYPE(new_pointer) = (tree) new_type;
+ layout_type(new_pointer);
+
+ const_tree *ptr_2 = mod_type_map->get(old);
+ if (ptr_2) return *ptr_2;
+
+ mod_type_map->put(old, new_pointer);
+ test_log("putting %s %s", 0, get_type_name(old), get_type_name(new_pointer));
+ return new_pointer;
+
+}
+
+//TODO:
+//This needs a new parameter that allows
+//us to say **how** we modify the type.
+//Not all information can be derived
+//only from the old type.
+//This is only possible now because we are
+//basically hard coding examples.
+static const_tree
+make_new_type_based_on_old(const_tree old,
+ hash_map<const_tree, const_tree>* mod_type_map)
+{
+
+ if (!old) return old;
+
+ gcc_assert(old);
+ const_tree *new_base_ptr = mod_type_map->get(old);
+ if (new_base_ptr) return *new_base_ptr;
+
+ switch(TREE_CODE(old))
+ {
+ case ARRAY_TYPE:
+ return make_new_array_based_on_old(old, mod_type_map);
+ break;
+ case POINTER_TYPE:
+ return make_new_pointer_based_on_old(old, mod_type_map);
+ break;
+ case RECORD_TYPE:
+ return make_new_record_based_on_old(old, mod_type_map);
+ break;
+ default:
+ return old;
+ break;
+ }
+ gcc_unreachable();
+ return NULL;
+}
+
+
+//Non-null values for type_map
+//will be the modified tree.
+bool
+compute_modified_structs_internal(const_tree const & old_type,
+ tree* new_type,
+ hash_map<const_tree, const_tree>* mod_type_map)
+{
+
+ const_tree *ptr = mod_type_map->get(old_type);
+ // already in map
+ if (ptr) return true;
+
+ const char* identifier = get_type_name(old_type);
+ test_log("modifying,%s", 0, identifier);
+
+ const_tree new_record = make_new_type_based_on_old(old_type, mod_type_map);
+ // We might have modified the mod_type_map inside make_new_type_based_on_old
+ // and therefore we no longer have the need to store this there again...
+ const_tree *ptr_2 = mod_type_map->get(old_type);
+ if (ptr_2) return true;
+
+ test_log("new_name,%s", 0, get_type_name(new_record));
+ mod_type_map->put(old_type, new_record);
+ return true;
+}
+
+static void
+compute_modified_structs(hash_map<const_tree, tree> &type_map,
+ hash_map<const_tree, const_tree> &mod_type_map)
+{
+ type_map.traverse<hash_map<const_tree, const_tree>*, compute_modified_structs_internal>(&mod_type_map);
+}
+
+
+static bool
+rewrite_constructor_def(tree expr, hash_map<const_tree, const_tree> &type_map, const int indent)
+{
+ tree old_rhs_type = TREE_TYPE(expr);
+ const_tree* new_rhs_type_ptr = type_map.get(old_rhs_type);
+ if (!new_rhs_type_ptr) return false;
+
+ tree new_rhs_type = (tree) *new_rhs_type_ptr;
+ TREE_TYPE(expr) = new_rhs_type;
+ return true;
+}
+
+
+static bool
+rewrite_field_decl_def(tree expr, hash_map<const_tree, const_tree> &type_map, const int indent)
+{
+ tree old_rhs_type = TREE_TYPE(expr);
+ const_tree* new_rhs_type_ptr = type_map.get(old_rhs_type);
+ if (!new_rhs_type_ptr) return false;
+
+ tree new_rhs_type = (tree) *new_rhs_type_ptr;
+ TREE_TYPE(expr) = new_rhs_type;
+ return true;
+}
+
+
+static bool
+rewrite_component_ref_def(tree expr, hash_map<const_tree, const_tree> &type_map, const int indent)
+{
+ gcc_assert(expr);
+ tree expr_type = TREE_TYPE(expr);
+ gcc_assert(expr_type);
+ const_tree *new_expr_type_ptr = type_map.get(expr_type);
+ if (new_expr_type_ptr) TREE_TYPE(expr) = (tree) *new_expr_type_ptr;
+
+ tree _struct = TREE_OPERAND(expr, 0);
+ gcc_assert(_struct);
+ tree _struct_type = TREE_TYPE(_struct);
+ gcc_assert(_struct_type);
+ const_tree* new_struct_type_ptr = type_map.get(_struct_type);
+
+ bool retval = rewrite_expr(_struct, type_map, indent);
+
+ tree new_type = new_struct_type_ptr ? (tree)*new_struct_type_ptr : _struct_type;
+ tree field_decl = TREE_OPERAND(expr, 1);
+ const char* field_name = get_field_name(field_decl);
+ const_tree new_field = get_field_with_name(new_type, field_name);
+ //INFO: We need to rewrite the whole operand
+ //not just its type.
+ //INFO: When rewriting an operand we **must**
+ //be in -flto-partition=none
+ //INFO: setting the type and calling relayout_decl
+ //doesn't work.
+ //TODO: FIXME: In order to remove this assertion
+ //you need to use clones.
+ gcc_assert(in_lto_p && !flag_ltrans && !flag_wpa);
+ TREE_OPERAND(expr, 1) = (tree) new_field;
+ int offset = get_field_offset(new_field);
+ test_log("rewrite,field_offset,%s,%d", indent, field_name, offset);
+
+ return true;
+}
+
+static bool
+rewrite_addr_expr_def(tree expr, hash_map<const_tree, const_tree> &type_map, const int indent)
+{
+ tree type = TREE_TYPE(expr);
+ gcc_assert(TREE_CODE(expr) == ADDR_EXPR);
+ const_tree *new_type_ptr = type_map.get(type);
+ if (new_type_ptr) TREE_TYPE(expr) = (tree) *new_type_ptr;
+ tree op0 = TREE_OPERAND(expr, 0);
+ bool retval = rewrite_expr(op0, type_map, indent);
+ return retval;
+}
+
+static bool
+rewrite_var_decl_def(tree expr, hash_map<const_tree, const_tree> &type_map, const int indent)
+{
+ tree type = TREE_TYPE(expr);
+ gcc_assert(TREE_CODE(expr) == VAR_DECL);
+ //tree *new_type_ptr = type_map.get(type);
+ //if (!new_type_ptr) return false;
+ //TREE_TYPE(expr) = *new_type_ptr;
+ return false;
+}
+
+static bool
+rewrite_mem_ref_def(tree expr, hash_map<const_tree, const_tree> &type_map, const int indent)
+{
+ gcc_assert(expr);
+ gcc_assert(TREE_CODE(expr) == MEM_REF);
+ tree type = TREE_TYPE(expr);
+ const_tree *new_type_ptr = type_map.get(type);
+ if (new_type_ptr) TREE_TYPE(expr) = (tree) *new_type_ptr;
+
+ const char* old_expr = print_generic_expr_to_str(expr);
+ tree op0 = TREE_OPERAND(expr, 0);
+ bool retval = rewrite_expr(op0, type_map, indent);
+ const char* new_expr = print_generic_expr_to_str(expr);
+ return retval;
+}
+
+
+static bool
+rewrite_ssa_name_def(tree expr, hash_map<const_tree, const_tree> &type_map, const int indent)
+{
+ const char* old_expr = print_generic_expr_to_str(expr);
+ tree type = TREE_TYPE(expr);
+ tree ssa_name_var = SSA_NAME_VAR(expr);
+ const_tree *new_type_ptr = type_map.get(type);
+ if (new_type_ptr) {
+ TREE_TYPE(expr) = (tree) *new_type_ptr;
+ //TODO: I had some cases where ssa_name_var was not set.
+ //Not sure why...
+ //I need to investigate
+ //Could this be the variables that I create?
+ //If so, then the temporary variables should have SSA_NAMES
+ //and there is something else that I need to change
+ if (ssa_name_var) TREE_TYPE(ssa_name_var) = (tree) *new_type_ptr;
+ if (ssa_name_var) relayout_decl(ssa_name_var);
+ }
+ return new_type_ptr;
+}
+
+static bool
+rewrite_bin_expr_default_def(tree expr, hash_map<const_tree, const_tree> &type_map, const int indent)
+{
+ gcc_assert(expr);
+ tree op0 = TREE_OPERAND(expr, 0);
+ tree op1 = TREE_OPERAND(expr, 1);
+ gcc_assert(op0 && op1);
+
+ bool retval = false;
+ retval |= rewrite_expr(op0, type_map, indent);
+ retval |= rewrite_expr(op1, type_map, indent);
+
+ return retval;
+}
+
+static bool
+rewrite_pointer_plus_def(tree expr, hash_map<const_tree, const_tree> &type_map, const int indent)
+{
+ gcc_assert(expr);
+ gcc_assert(TREE_CODE(expr) == POINTER_PLUS_EXPR);
+ const char* old_expr = print_generic_expr_to_str(expr);
+ tree type = TREE_TYPE(expr);
+ const_tree *new_type_ptr = type_map.get(type);
+ if (new_type_ptr) TREE_TYPE(expr) = (tree) *new_type_ptr;
+ return true;
+}
+
+static bool
+rewrite_plus_expr_def(tree expr, hash_map<const_tree, const_tree> &type_map, const int indent)
+{
+ gcc_assert(expr);
+ gcc_assert(TREE_CODE(expr) == PLUS_EXPR);
+ const char* old_expr = print_generic_expr_to_str(expr);
+ bool retval = rewrite_bin_expr_default(expr, type_map, indent);
+ return retval;
+}
+
+static bool
+rewrite_pointer_diff_def(tree expr, hash_map<const_tree, const_tree> &type_map, const int indent)
+{
+ bool retval = false;
+ return retval;
+}
+
+
+static bool
+rewrite_array_ref_def(tree expr, hash_map<const_tree, const_tree> &type_map, const int indent)
+{
+ gcc_assert(expr);
+ gcc_assert(TREE_CODE(expr) == ARRAY_REF);
+ tree type = TREE_TYPE(expr);
+ const_tree *up_ptr = type_map.get(type);
+ if (up_ptr) TREE_TYPE(expr) = (tree) *up_ptr;
+ tree old_rhs_type = TREE_TYPE(expr);
+ const_tree* new_rhs_type_ptr = type_map.get(old_rhs_type);
+
+ rewrite_expr(TREE_OPERAND(expr, 0), type_map, indent+4);
+ rewrite_expr(TREE_OPERAND(expr, 1), type_map, indent+4);
+
+ return true;
+}
+
+
+//TODO:
+//rewrite_pointer_plus_def_rhs_constant is a special case of
+//rewrite_pointer_plus_def_rhs_variable.
+//Maybe variable should subsume constant?
+static tree
+rewrite_pointer_plus_def_rhs_variable(gimple_stmt_iterator &gsi, tree pointer, tree variable, const_tree old_type)
+{
+ tree pointer_type = TREE_TYPE(pointer);
+ gcc_assert(TREE_CODE(pointer_type) == POINTER_TYPE);
+ enum tree_code code = TREE_CODE(variable);
+ gcc_assert(TREE_CODE(variable) == SSA_NAME);
+ tree variable_type = TREE_TYPE(variable);
+ gcc_assert(TREE_CODE(variable_type) == INTEGER_TYPE);
+
+ // the variable holds the offset
+ // variable = anotherthing * old_type_size
+ // result = pointer + variable
+ // Let's first create a temporary variable
+ // variable = anotherthing * old_type_size;
+ // tmpvar = variable / old_struct_size;
+ tree tmpvar = create_tmp_var(TREE_TYPE(variable));
+ // Good.
+ // Now, we can make an integer constant
+ // that is old_struct_size;
+ // tmpvar = variable / old_struct_size;
+ unsigned int indirection_level = 1;
+ const_tree old_base_type = get_base_type_from_pointer_type(old_type, indirection_level);
+ tree old_struct_size_tree_1 = TYPE_SIZE_UNIT(old_base_type);
+ int old_struct_size_int = tree_to_shwi(old_struct_size_tree_1);
+ tree old_struct_size = build_int_cst(TREE_TYPE(variable), old_struct_size_int);
+
+ // Good.
+ // Now we need to create a division operation between the two
+ // Because there is no pointer division.
+ gassign *assign_stmt_1 = gimple_build_assign(tmpvar, TRUNC_DIV_EXPR, variable, old_struct_size);
+ // Now we need to insert assign_stmt_1 before us...
+ gsi_insert_before(&gsi, assign_stmt_1, GSI_SAME_STMT);
+
+ // Ok now we need a new temporary variable
+ // tmpvar2 = tmpvar * new_struct_size;
+ tree tmpvar2 = create_tmp_var(TREE_TYPE(variable));
+ // Good.
+ // Now we need we need another integer constant
+ unsigned int indirection_level2 = 0;
+ const_tree new_base_type = get_base_type_from_pointer_var(pointer, indirection_level);
+ tree new_struct_size_tree_1 = TYPE_SIZE_UNIT(new_base_type);
+ int new_struct_size_int = tree_to_shwi(new_struct_size_tree_1);
+ tree new_struct_size = build_int_cst(TREE_TYPE(variable), new_struct_size_int);
+
+ //Good. Now we need to multiply...
+ // tmpvar2 = tmpvar * new_struct_size;
+ gassign *assign_stmt_2 = gimple_build_assign(tmpvar2, MULT_EXPR, tmpvar, new_struct_size);
+
+ // Now we need to insert assign_stmt_2 before us...
+ gsi_insert_before(&gsi, assign_stmt_2, GSI_SAME_STMT);
+ return tmpvar2;
+}
+
+static tree
+rewrite_pointer_plus_def_rhs_integer_constant(tree pointer, tree integer_constant, const_tree old_type)
+{
+ gcc_assert(TREE_CODE(integer_constant) == INTEGER_CST);
+ tree pointer_type = TREE_TYPE(pointer);
+ gcc_assert(TREE_CODE(pointer_type) == POINTER_TYPE);
+
+ unsigned int indirection_level_1 = 0;
+ const_tree base_type = get_base_type_from_pointer_var(pointer, indirection_level_1);
+
+ tree size = TYPE_SIZE_UNIT(base_type);
+ int new_struct_size = tree_to_shwi(size);
+ int old_offset = tree_to_uhwi(integer_constant);
+
+ unsigned int indirection_level_2 = 1;
+ const_tree old_base_type = get_base_type_from_pointer_type(old_type, indirection_level_2);
+
+ tree old_type_size = TYPE_SIZE_UNIT(old_base_type);
+ int old_struct_size = tree_to_shwi(old_type_size);
+ test_log("old_struct_size = %d", 0, old_struct_size);
+
+ bool addition = old_offset > 0;
+ tree integer_constant_type = TREE_TYPE(integer_constant);
+
+ int new_offset = old_offset / old_struct_size * new_struct_size;
+ tree new_constant = build_int_cst(integer_constant_type, new_offset);
+ return new_constant;
+}
+
+static bool
+rewrite_pointer_plus_def_rhs(gimple *stmt, gimple_stmt_iterator &gsi, tree lhs, tree op0, tree op1, hash_map<const_tree, const_tree> &type_map, hash_map<const_tree, const_tree>& inverse)
+{
+ gcc_assert(op0 && op1);
+ tree op0_type = TREE_TYPE(op0);
+ const_tree *new_op0_type = type_map.get(op0_type);
+ test_log("rewrite_pointer_plus has old_type %s", 0, new_op0_type ? "true" : "false");
+ //gcc_assert(!new_op0_type);
+
+ rewrite_expr_def(op0, type_map, 0);
+ rewrite_expr_def(op1, type_map, 0);
+
+ tree rhs_type = TREE_TYPE(op0);
+ const char* new_type_name = new_op0_type ? get_type_name(*new_op0_type) : get_type_name(op0_type);
+ //TODO: I'd prefer to have a parameter
+ //that tells me what to change
+ //several stack frames above.
+ const_tree * old_type_ptr = inverse.get(op0_type);
+ if (!old_type_ptr) return false;
+ const_tree old_type = *old_type_ptr;
+
+ bool is_op1_int_cst = TREE_CODE(op1) == INTEGER_CST;
+ tree integer_constant = is_op1_int_cst ? op1 : op0;
+ bool has_integer_constant = (TREE_CODE(integer_constant) == INTEGER_CST);
+
+ // I want to know if this is an invariant.
+ if (has_integer_constant) gcc_assert(TREE_CODE(op1) == INTEGER_CST);
+
+ switch(has_integer_constant)
+ {
+ case true:
+ {
+ tree pointer = is_op1_int_cst ? op0 : op1;
+ tree pointer_type = TREE_TYPE(pointer);
+ tree new_constant = rewrite_pointer_plus_def_rhs_integer_constant(pointer, integer_constant, old_type);
+ unsigned int operand = is_op1_int_cst ? 2 : 1;
+ gimple_set_op(stmt, operand, new_constant);
+ }
+ break;
+ case false:
+ {
+ tree variable = op1;
+ tree pointer = op0;
+ // I want to know if this is an invariant.
+ tree pointer_type = TREE_TYPE(pointer);
+ gcc_assert(TREE_CODE(pointer_type) == POINTER_TYPE);
+ tree new_variable = rewrite_pointer_plus_def_rhs_variable(gsi, pointer, variable, old_type);
+ unsigned int operand = TREE_CODE(TREE_TYPE(op0)) == POINTER_TYPE ? 2 : 1;
+ gimple_set_op(stmt, operand, new_variable);
+ }
+ break;
+ default:
+ gcc_unreachable();
+ break;
+ }
+
+ return true;
+}
+
+static bool
+rewrite_assign_rhs(gimple *stmt, gimple_stmt_iterator &gsi, hash_map<const_tree, const_tree> &type_map, hash_map<const_tree, const_tree> &inverse)
+{
+ bool is_stmt_rewritten = false;
+ //WONTFIX, It looks like there is no way to obtain
+ //the expression for the rhs. So instead, we have to do
+ //this hack.
+ //Which expressions can be toplevel?
+ enum tree_code code = gimple_expr_code(stmt);
+ switch(code)
+ {
+ case POINTER_PLUS_EXPR:
+ {
+ tree rhs2 = gimple_assign_rhs2(stmt);
+ tree rhs1 = gimple_assign_rhs1(stmt);
+ tree lhs = gimple_assign_lhs(stmt);
+ tree lhs_type = TREE_TYPE(lhs);
+ gcc_assert(lhs_type);
+ const_tree* new_type_ptr = type_map.get(lhs_type);
+ gcc_assert(lhs && rhs2 && rhs1);
+ bool retval = rewrite_pointer_plus_def_rhs(stmt, gsi, lhs, rhs1, rhs2, type_map, inverse);
+ if (new_type_ptr) TREE_TYPE(lhs) = (tree)*new_type_ptr;
+ return retval;
+ }
+ break;
+ case POINTER_DIFF_EXPR:
+ {
+ // It's weird. Test case #4
+ // uses this, but the answer
+ // is to do nothing...
+ }
+ default:
+ break;
+ }
+
+ switch (gimple_assign_rhs_class(stmt))
+ {
+ case GIMPLE_TERNARY_RHS:
+ {
+ tree rhs3 = gimple_assign_rhs3(stmt);
+ is_stmt_rewritten |= rewrite_expr(rhs3, type_map, 0);
+ }
+ /* fall through */
+ case GIMPLE_BINARY_RHS:
+ {
+ tree rhs2 = gimple_assign_rhs2(stmt);
+ is_stmt_rewritten |= rewrite_expr(rhs2, type_map, 0);
+ }
+ /* fall through */
+ case GIMPLE_SINGLE_RHS:
+ case GIMPLE_UNARY_RHS:
+ {
+ tree rhs1 = gimple_assign_rhs1(stmt);
+ is_stmt_rewritten |= rewrite_expr(rhs1, type_map, 0);
+ }
+ break;
+ default:
+ gcc_unreachable();
+ break;
+ }
+
+ return is_stmt_rewritten;
+}
+
+static void
+rewrite_call_lhs(gimple *stmt, gimple_stmt_iterator &gsi, hash_map<const_tree, const_tree> &type_map, hash_map<const_tree, const_tree> &inverse)
+{
+ gcc_assert(stmt);
+ test_print_gimple_stmt(stmt);
+ tree lhs = gimple_call_lhs (stmt);
+ //LHS can be null. Example `foo()`
+ if (!lhs) return;
+
+ //TODO: is there anything else I need to do?
+ rewrite_expr(lhs, type_map, 0);
+}
+
+static void
+rewrite_call_rhs(gimple *stmt, gimple_stmt_iterator &gsi, hash_map<const_tree, const_tree> &type_map, hash_map<const_tree, const_tree> &inverse)
+{
+ gcc_assert(stmt);
+ // PRETTY SURE YOU MUST HAVE A FUNCTION
+ // TO CALL
+ tree fn = gimple_call_fn (stmt);
+ gcc_assert(fn);
+ gcall *call = dyn_cast<gcall*>(stmt);
+ tree return_type = gimple_call_return_type(call);
+ test_log("what is the return type %s", 0, get_type_name(return_type));
+ //TODO: What happens with void?
+ gcc_assert(return_type);
+
+ const_tree *new_type = type_map.get(return_type);
+ if (!new_type) return;
+
+ /*
+ * This is not the way to do it.
+ TREE_TYPE(fn) = (tree) *new_type;
+ gcall *call_new = dyn_cast<gcall*>(stmt);
+ tree return_type_new = gimple_call_return_type(call);
+ test_log("after what is the return type %s", 0, get_type_name(return_type_new));
+ */
+
+
+
+}
+
+static void
+rewrite_call(gimple *stmt, gimple_stmt_iterator &gsi, hash_map<const_tree, const_tree> &type_map, hash_map<const_tree, const_tree> &inverse)
+{
+ rewrite_call_lhs(stmt, gsi, type_map, inverse);
+ rewrite_call_rhs(stmt, gsi, type_map, inverse);
+}
+
+
+static void
+rewrite_assign(gimple *stmt, gimple_stmt_iterator &gsi, hash_map<const_tree, const_tree> &type_map, hash_map<const_tree, const_tree> &inverse)
+{
+ gcc_assert(stmt);
+ test_print_gimple_stmt(stmt);
+ tree lhs = gimple_assign_lhs (stmt);
+ const bool lhs_rewrite = rewrite_expr(lhs, type_map, 0);
+ const bool rhs_rewrite = rewrite_assign_rhs(stmt, gsi, type_map, inverse);
+ test_print_gimple_stmt(stmt);
+}
+
+static void
+rewrite_stmt(gimple *stmt, gimple_stmt_iterator &gsi, hash_map<const_tree, const_tree> &type_map, hash_map<const_tree, const_tree> &inverse)
+{
+ gcc_assert(stmt);
+ const enum gimple_code code = gimple_code(stmt);
+ switch (code)
+ {
+ case GIMPLE_ASSIGN:
+ rewrite_assign(stmt, gsi, type_map, inverse);
+ break;
+ case GIMPLE_CALL:
+ rewrite_call(stmt, gsi, type_map, inverse);
+ break;
+ default:
+ {
+ const char* const gimple_code_str = gimple_code_name[code];
+ test_log("gimple_code %s", 0, gimple_code_str);
+ }
+ break;
+ }
+ return;
+}
+
+static void
+rewrite_basic_block(basic_block bb, hash_map<const_tree, const_tree> &type_map, hash_map<const_tree, const_tree> &inverse)
+{
+ gcc_assert(bb);
+ for (gimple_stmt_iterator gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi))
+ {
+ gimple *stmt = gsi_stmt(gsi);
+ rewrite_stmt(stmt, gsi, type_map, inverse);
+ }
+}
+
+static void
+rewrite_function_body(cgraph_node *cnode, hash_map<const_tree, const_tree> &type_map, hash_map<const_tree, const_tree> &inverse)
+{
+ gcc_assert(cnode);
+ cnode->get_untransformed_body();
+ basic_block bb = NULL;
+ function *func = DECL_STRUCT_FUNCTION (cnode->decl);
+ push_cfun(func);
+ FOR_EACH_BB_FN (bb, func)
+ {
+ rewrite_basic_block(bb, type_map, inverse);
+ }
+ pop_cfun();
+ print_function(cnode);
+}
+
+static void
+rewrite_local_decl(tree var_decl, hash_map<const_tree, const_tree> &type_map)
+{
+ gcc_assert(var_decl);
+ gcc_assert(TREE_CODE(var_decl) == VAR_DECL);
+ const_tree type = TREE_TYPE(var_decl);
+ gcc_assert(type);
+ const_tree* new_type_ptr = type_map.get(type);
+
+ if (!new_type_ptr) return;
+
+ const_tree new_type = *new_type_ptr;
+ gcc_assert(new_type);
+ //FIXME: We know these are record types
+ //make more general later.
+ const char* identifier_old = get_type_name(type);
+ const char* identifier_new = get_type_name(new_type);
+ test_write("rewriting,local_decl");
+ test_print_generic_decl(var_decl);
+ test_write(",");
+ TREE_TYPE(var_decl) = (tree) new_type;
+ // Keep this relayout_decl
+ relayout_decl(var_decl);
+ test_print_generic_decl(var_decl);
+ test_write("\n");
+}
+
+static void
+rewrite_local_decls(cgraph_node *cnode, hash_map<const_tree, const_tree> &type_map)
+{
+ gcc_assert(cnode);
+ tree decl = cnode->decl;
+ gcc_assert(decl);
+ gcc_assert(TREE_CODE(decl) == FUNCTION_DECL);
+ function *func = DECL_STRUCT_FUNCTION(decl);
+ gcc_assert(func);
+ tree var_decl = NULL;
+ int i = 0;
+ FOR_EACH_LOCAL_DECL(func, i, var_decl)
+ {
+ rewrite_local_decl(var_decl, type_map);
+ }
+ print_function(cnode);
+}
+
+static void
+rewrite_function_parms(cgraph_node *cnode, hash_map<const_tree, const_tree> &type_map)
+{
+ //TODO: Do we need to do get_untransformed_body here?
+ for (tree parm = DECL_ARGUMENTS(cnode->decl); parm; parm = DECL_CHAIN(parm))
+ {
+ tree parm_type = TREE_TYPE(parm);
+ const_tree *type_ptr = type_map.get(parm_type);
+ if (!type_ptr) continue;
+
+ test_log("before rewrite_function_arg %s", 0, get_type_name(parm_type));
+ TREE_TYPE(parm) = (tree) *type_ptr;
+ relayout_decl(parm);
+ tree parm_type_2 = TREE_TYPE(parm);
+ test_log("after rewrite_function_arg %s", 0, get_type_name(parm_type_2));
+ }
+}
+
+static void
+rewrite_function_return_type(cgraph_node *cnode, hash_map<const_tree, const_tree> &type_map)
+{
+
+ gcc_assert(TREE_CODE(cnode->decl) == FUNCTION_DECL);
+ tree function_type = TREE_TYPE(cnode->decl);
+ gcc_assert(function_type);
+ // TODO: We do not support method's yet.
+ gcc_assert(TREE_CODE(function_type) == FUNCTION_TYPE);
+ tree function_return_type = TREE_TYPE(function_type);
+ //TODO: What happens with void return
+ gcc_assert(function_return_type);
+
+ test_log("before rewrite_function_return_type %s", 0, get_type_name(function_return_type));
+ const_tree *new_type_ptr = type_map.get(function_return_type);
+ if (!new_type_ptr) return;
+
+ TREE_TYPE(function_type) = (tree) *new_type_ptr;
+ //relayout_decl(cnode->decl);
+ tree function_type_2 = TREE_TYPE(cnode->decl);
+ tree function_return_type_2 = TREE_TYPE(function_type_2);
+ test_log("after rewrite_function_return_type %s", 0, get_type_name(function_return_type_2));
+}
+
+static void
+rewrite_function(cgraph_node *cnode, hash_map<const_tree, const_tree> &type_map, hash_map<const_tree, const_tree> &inverse)
+{
+ //rewrite_function_body should be before
+ //rewrite_local_decls to make work easier.
+ //Why? Because if we rewrite local decl types
+ //first, then we might need to look for
+ //old AND new types in rewrite_function_body.
+ //If we rewrite local decl types later,
+ //then in rewrite_function_body we only
+ //need to look for old types.
+ rewrite_function_parms(cnode, type_map);
+ rewrite_function_return_type(cnode, type_map);
+ rewrite_function_body(cnode, type_map, inverse);
+ rewrite_local_decls(cnode, type_map);
+}
+
+static void
+rewrite_functions(hash_map<const_tree, const_tree> &type_map, hash_map<const_tree, const_tree> &inverse)
+{
+ cgraph_node *cnode = NULL;
+ FOR_EACH_DEFINED_FUNCTION(cnode)
+ {
+ rewrite_function(cnode, type_map, inverse);
+ }
+}
+
+//TODO:
+//Get rid of this function but make sure test still pass
+bool
+rewrite_references_to_modified_structs_internal(const_tree const &old_type,
+ const_tree* new_type,
+ __attribute__((unused))void*)
+{
+ const char* identifier = get_type_name(old_type);
+ test_log("rewriting,%s,%s", 0, identifier, get_type_name(*new_type));
+ return true;
+}
+
+static void
+rewrite_references_to_modified_structs(hash_map<const_tree, const_tree> &type_map, hash_map<const_tree, const_tree> &inverse)
+{
+ type_map.traverse<void*, rewrite_references_to_modified_structs_internal>(NULL);
+ //FIXME: You'll need to iterate over more than just
+ //defined functions.
+ rewrite_functions(type_map, inverse);
+}
+
+bool
+compute_inverse_type_map_internal(const_tree const & old_type,
+ const_tree* new_type,
+ hash_map<const_tree, const_tree>* inverse_map)
+{
+ gcc_assert(new_type && *new_type);
+ gcc_assert(inverse_map);
+ inverse_map->put(*new_type, old_type);
+ const char* old_identifier = get_type_name(old_type);
+ const char* new_identifier = get_type_name(*new_type);
+ test_log("inverse,%s,%s", 0, new_identifier,old_identifier);
+ return true;
+}
+
+static void
+compute_inverse_type_map(hash_map<const_tree, const_tree> &mod_type_map,
+ hash_map<const_tree, const_tree> &inverse_map)
+{
+ mod_type_map.traverse<hash_map<const_tree, const_tree>*, compute_inverse_type_map_internal>(&inverse_map);
+}
+
+static unsigned int
+iphw_execute()
+{
+ test_log("Executing structreorg", 0);
+
+ //TODO: change orig_type_map to hash_set.
+ hash_map<const_tree, tree> orig_type_map;
+ collect_orig_structs(orig_type_map);
+
+ //TODO: ideally mod_type_map would be a bidirectional map.
+ //but we work with what we have.
+ hash_map<const_tree, const_tree> mod_type_map;
+ compute_modified_structs(orig_type_map, mod_type_map);
+ hash_map<const_tree, const_tree> inverse_type_map;
+ compute_inverse_type_map(mod_type_map, inverse_type_map);
+ rewrite_references_to_modified_structs(mod_type_map, inverse_type_map);
+ return 0;
+}
int
str_reorg_dead_field_eliminate( Info *info)
{
- // TBD
- //DEBUG ( "Running str_reorg_dead_field_eliminate\n");
- return 0;
+ gcc_assert(in_lto_p && flag_ipa_typelist);
+ return iphw_execute();
}