#include "config.h" #include "system.h" #include "coretypes.h" #include "backend.h" #include "options.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 "ipa-str-reorg-utils.h" // First we need to collect all types void log (const char * const format, ...) { if (!dump_file) return; va_list args; va_start(args, format); vfprintf(dump_file, format, args); va_end(args); } struct escaping_info_s { const_tree type; bool is_escaping; }; typedef struct escaping_info_s escaping_info; typedef hash_map type_map; static bool filter_type (type_map &escape_map, const_tree type); static bool filter_pointer (type_map &escape_map, const_tree pointer) { enum tree_code code = TREE_CODE (pointer); gcc_assert(POINTER_TYPE == code); const_tree base_type = TREE_TYPE(pointer); return filter_type (escape_map, base_type); } static bool filter_array (type_map &escape_map, const_tree array) { enum tree_code code = TREE_CODE (array); gcc_assert(ARRAY_TYPE == code); const_tree base_type = TREE_TYPE(array); return filter_type (escape_map, base_type); } static bool filter_record (type_map &escape_map, const_tree record) { log("filtering record %s\n", get_type_name(record)); gcc_assert(record); enum tree_code code = TREE_CODE(record); gcc_assert(RECORD_TYPE == code); for (tree field = TYPE_FIELDS (record); field; field = DECL_CHAIN (field)) { tree field_type = TREE_TYPE(field); gcc_assert(field_type); filter_type(escape_map, field_type); } return false; } static bool filter_type (type_map &escape_map, const_tree type) { log("inside filter_type\n"); if (!type) return true; bool retval = true; enum tree_code code = TREE_CODE(type); switch (code) { case ARRAY_TYPE: retval = filter_array(escape_map, type); break; case POINTER_TYPE: retval = filter_pointer(escape_map, type); break; case RECORD_TYPE: retval = filter_record(escape_map, type); break; default: break; } if (retval) return retval; escaping_info info = { type, false }; escape_map.put(type, info); return retval; } static bool filter_var_decl (type_map &escape_map, const_tree var_decl) { log("filtering var_decl\n"); gcc_assert(var_decl); enum tree_code code = TREE_CODE(var_decl); gcc_assert(code == VAR_DECL); tree type = TREE_TYPE (var_decl); gcc_assert(type); return filter_type(escape_map, type); } static bool filter_parm_declarations (const_tree parm_decl, type_map &escape_map) { gcc_assert(parm_decl); enum tree_code code = TREE_CODE(parm_decl); gcc_assert(PARM_DECL == code); tree type = TREE_TYPE (parm_decl); gcc_assert(type); return filter_type(escape_map, type); } static void collect_global(type_map &escape_map, varpool_node *vnode) { log("collect_global\n"); gcc_assert(vnode); struct ipa_ref *ref = NULL; for (int i = 0; vnode->iterate_referring (i, ref); i++) { log("inside vnode loop\n"); tree decl = vnode->decl; gcc_assert(decl); enum tree_code code = TREE_CODE(decl); gcc_assert(VAR_DECL == code); bool filter_out = filter_var_decl(escape_map, decl); if (filter_out) continue; tree type = TREE_TYPE(decl); gcc_assert(type); escaping_info info = { type, false }; escape_map.put (type, info); } } static void collect_globals(type_map &escape_map) { varpool_node *vnode; FOR_EACH_VARIABLE (vnode) { collect_global(escape_map, vnode); } } static void collect_parm_declarations (cgraph_node *cnode, type_map &escape_map) { gcc_assert(cnode); for (tree parm = DECL_ARGUMENTS (cnode->decl); parm; parm = DECL_CHAIN (parm)) { bool filter_out = filter_parm_declarations (parm, escape_map); if (filter_out) continue; tree type = TREE_TYPE(parm); gcc_assert(type); escaping_info info = { type, false }; escape_map.put(type, info); } } static void collect_types(type_map &escape_map) { collect_globals(escape_map); cgraph_node *cnode = NULL; FOR_EACH_DEFINED_FUNCTION (cnode) { collect_parm_declarations (cnode, escape_map); } } bool _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; log("type %s is escaping %s\n", get_type_name(type), is_escaping ? "true" : "false"); return true; } static void print_types(type_map &escape_map) { log("printing_types\n"); escape_map.traverse (NULL); } static bool is_variable_escaping(varpool_node *vnode) { gcc_assert(vnode); return vnode->externally_visible; } static bool is_function_escaping(cgraph_node *cnode) { gcc_assert(cnode); return cnode->externally_visible; } void is_any_function_escaping(type_map &escape_map) { cgraph_node *cnode = NULL; FOR_EACH_FUNCTION (cnode) { log("function name = %s\n", cnode->name()); bool is_escaping = is_function_escaping(cnode); log("function %s is escaping %s\n", cnode->name(), is_escaping ? "true" : "false"); } } void is_any_variable_escaping(type_map &escape_map) { varpool_node *vnode = NULL; // Global variables FOR_EACH_VARIABLE(vnode) { bool is_escaping = is_variable_escaping(vnode); log("variable %s is escaping %s\n", vnode->name(), is_escaping ? "true" : "false"); tree decl = vnode->decl; gcc_assert(decl); tree type = TREE_TYPE(decl); gcc_assert(type); escaping_info *info = escape_map.get(type); gcc_assert(info); // If there is any variable of this type that escapes. // This type will escape info->is_escaping |= is_escaping; } } static unsigned int iphw_execute() { type_map escape_map; collect_types(escape_map); is_any_variable_escaping(escape_map); is_any_function_escaping(escape_map); print_types(escape_map); 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); }