Mercurial > cospy
view src/cospy.c @ 12:6fdb0cfdc2a7
More information about GIMPLE
author | Thinker K.F. Li <thinker@codemud.net> |
---|---|
date | Thu, 09 Sep 2010 16:06:55 +0800 |
parents | bf14d3ed008e |
children | 708921504d6d |
line wrap: on
line source
#include "gcc-plugin.h" #include "plugin-version.h" #include "system.h" #include "coretypes.h" #include "tree-pass.h" #include "tree.h" #include "gimple.h" #include "cgraph.h" #include <stdio.h> /* This is required for GCC plugin, or it is can not be loaded */ int plugin_is_GPL_compatible; /*! \brief Parse a tree of type and return respective string. * * The struncture of a pointer type * - pointer:pointer_type * - type:*_type * - name:type_decl * - name:identifier * * For a constant type, it is flaged as a readonly. * * \return a string for the type. It must be free through ggc_free(). */ static char * parse_type(tree type_node) { tree type_v; tree *pointers; tree type_decl, type_name; int ptr_lvl = 0; int const_cnt = 0; char *type_str; const char *base_type_name; int type_str_len; int str_i, ptr_i; /* Collect pointers */ type_v = type_node; while(TREE_CODE(type_v) == POINTER_TYPE) { if(TREE_READONLY(type_v)) const_cnt++; type_v = TREE_TYPE(type_v); ptr_lvl++; } pointers = (tree *)ggc_alloc(sizeof(tree) * ptr_lvl); type_v = type_node; for(ptr_i = 0; ptr_i < ptr_lvl; ptr_i++) { pointers[ptr_i] = type_v; type_v = TREE_TYPE(type_v); } /* Get name of base type */ type_decl = TYPE_NAME(type_v); type_name = DECL_NAME(type_decl); base_type_name = IDENTIFIER_POINTER(type_name); /* Compute total length of string of full type */ type_str_len = ptr_lvl + strlen(base_type_name) + const_cnt * 5; /* "const" */ if(TREE_READONLY(type_v)) type_str_len += 6; /* "const " */ type_str = (char *)ggc_alloc(type_str_len + 1); /* base type and constant modification */ type_str[0] = 0; if(TREE_READONLY(type_v)) strcpy(type_str, "const "); strcat(type_str, base_type_name); /* Add pointers and const modifications after base type */ str_i = strlen(type_str); for(ptr_i = ptr_lvl - 1; ptr_i >= 0; ptr_i--) { type_v = pointers[ptr_i]; type_str[str_i++] = '*'; if(TREE_READONLY(type_v)) { strcpy(type_str + str_i, "const"); str_i += 5; } } type_str[str_i] = 0; ggc_free(pointers); return type_str; } /*! \brief Show functions that called by a specified function. * * \param cgn is cgraph_node of a function. */ static void show_callees(struct cgraph_node *cgn) { struct cgraph_edge *edge; struct cgraph_node *callee_cgn; tree callee, callee_name; /* Follow edges to called functions */ edge = cgn->callees; while(edge) { callee_cgn = edge->callee; callee = callee_cgn->decl; callee_name = DECL_NAME(callee); printf(" call %s\n", IDENTIFIER_POINTER(callee_name)); edge = edge->next_callee; } } /*! \brief Find all call expression in a code block. * * This function find CALL_EXPR in body of a function that represented * as a GIMPE tree. See gcc/tree.def and gcc/c-gimplify.c of GCC for * more information of tree code of GIMPLE. */ static void find_call_expr(tree fn) { tree bind, body; bind = DECL_SAVED_TREE(fn); /* BIND_EXPR */ body = BIND_EXPR_BODY(bind); printf("%d:%d\n", TREE_CODE(body), BIND_EXPR); } /*! \brief This function is called before running all_passes. * * all_passes is a list of optimization passes of GCC. See * init_optimization_passes() in gcc/passes.c of GCC. * * This function is called for every function. */ static void handle_all_passes(void *gcc_data, void *user_data) { tree decl; struct cgraph_node *cgn; /* * GCC uses cgraph_node to save information of functions and * relationships between functions (a.k.a call graphy). */ decl = cfun->decl; cgn = cgraph_node(decl); printf("%s:%d:%s\n", current_function_name(), DECL_SOURCE_LINE(decl), DECL_SOURCE_FILE(decl)); show_callees(cgn); } /*! \brief Called before every optimization pass. */ static void handle_every_pass(void *gcc_data, void *user_data) { #if 0 printf("PASS %s (type=%x)\n", current_pass->name, current_pass->type); #endif } /*! \brief Callback before any optimization pass. * * It supposed to get function body in GIMPLE statements. If we don't * do this, here, it, GIMPLE statements, would be destroyed by * optimization passes. */ static void handle_pre_genericize(void *gcc_data, void *user_data) { tree fndecl; /* for arguments */ tree arg, arg_name; tree arg_type; char *arg_type_str; fndecl = cfun->decl; printf("%s:%d:%s\n", current_function_name(), DECL_SOURCE_LINE(fndecl), DECL_SOURCE_FILE(fndecl)); /* * Parse and show arguments of the function. */ arg = DECL_ARGUMENTS(fndecl); while(arg) { /* * The structure of an argument. * - parm * - name:identifier * - type:type * - name:type_decl * - name:identifier */ arg_name = DECL_NAME(arg); arg_type = TREE_TYPE(arg); arg_type_str = parse_type(arg_type); printf(" %s:%s\n", IDENTIFIER_POINTER(arg_name), arg_type_str); ggc_free(arg_type_str); arg = TREE_CHAIN(arg); } find_call_expr(fndecl); } /*! \brief Initialize function for the plugin. */ int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version) { if (!plugin_default_version_check (version, &gcc_version)) return 1; printf("Initialize plugin %s\n", plugin_info->base_name); /* * Register a callback called before running passes in all_passes. */ register_callback(plugin_info->base_name, PLUGIN_ALL_PASSES_START, handle_all_passes, NULL); register_callback(plugin_info->base_name, PLUGIN_PASS_EXECUTION, handle_every_pass, NULL); /* * Call handle_pre_genericize before genericize a function. * * This callback is run before any optimization pass. It is just * after finishing (parsing) a function. */ register_callback(plugin_info->base_name, PLUGIN_PRE_GENERICIZE, handle_pre_genericize, NULL); return 0; }