├── Makefile ├── README ├── alwayszero-test.c ├── alwayszero_plugin.c ├── attribute_plugin-test-1.C ├── attribute_plugin.c ├── dumb-plugin-test-1.C ├── dumb_plugin.c ├── ggcplug-test-1.c ├── ggcplug.c ├── pragma_plugin-test-1.C ├── pragma_plugin.c ├── self-assign-test-1.C ├── self-assign-test-1.c ├── self-assign-test-2.C ├── self-assign-test-2.c ├── self-assign-test-3.C ├── selfassign.c └── start_unit_plugin.c /Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc-4.5 2 | CFLAGS+= -I/usr/lib/gcc/i486-linux-gnu/4.5/plugin/include -fPIC 3 | 4 | dumb_plugin.so: dumb_plugin.o 5 | $(CC) -shared $^ -o $@ 6 | g++-4.5 -O -fplugin=./dumb_plugin.so -fplugin-arg-dumb_plugin-ref-pass-name=ccp -fplugin-arg-dumb_plugin-ref-pass-instance-num=1 -c dumb-plugin-test-1.C 7 | 8 | alwayszero_plugin.so: alwayszero_plugin.o 9 | $(CC) -shared $^ -o $@ 10 | gcc-4.5 -O -fplugin=./alwayszero_plugin.so alwayszero-test.c -o zero.out 11 | ./zero.out 12 | 13 | clean: 14 | rm -f *o *~ *out -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | GCC-4.5 and above supports plugins. This project explores this mechanism. 2 | Most code is taken from gcc/g++ testsuites. 3 | Two real-world examples are dragonegg and melt (Middle End Lisp Translator). 4 | 5 | References: 6 | http://gcc.gnu.org/wiki/plugins 7 | http://gcc.gnu.org/onlinedocs/gccint/Plugins.html 8 | http://ehren.wordpress.com/2009/11/04/creating-a-gcc-optimization-plugin/ -------------------------------------------------------------------------------- /alwayszero-test.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int f() __attribute__((user("alwayszero"))); 4 | f() { 5 | printf("In f\n"); 6 | return 5; 7 | } 8 | 9 | int main() { 10 | int x = f(); 11 | printf("%d\n", x); 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /alwayszero_plugin.c: -------------------------------------------------------------------------------- 1 | /* 2 | alwayszero_plugin.c 3 | 4 | This plugin contains an optimization pass that affects all functions tagged 5 | as __attribute__((user("alwayszero"))) (typically these functions already 6 | return 0 yet GCC cannot determine this). 7 | 8 | A statement of the form x = call(); where call is alwayszero will be 9 | transformed into dummy_var = call(); x = 0;. Further GCC optimization 10 | passes will eliminate dummy_var and propagate the value 0 into subsequent 11 | uses of x. 12 | 13 | Ehren Metcalfe 14 | */ 15 | 16 | #include "gcc-plugin.h" 17 | #include "config.h" 18 | #include "system.h" 19 | #include "coretypes.h" 20 | #include "tm.h" 21 | #include "toplev.h" 22 | #include "basic-block.h" 23 | #include "gimple.h" 24 | #include "tree.h" 25 | #include "tree-pass.h" 26 | #include "intl.h" 27 | #include 28 | 29 | int plugin_is_GPL_compatible; 30 | 31 | /* Attribute handler callback */ 32 | 33 | static tree 34 | handle_user_attribute (tree *node, tree name, tree args, 35 | int flags, bool *no_add_attrs) 36 | { 37 | return NULL_TREE; 38 | } 39 | 40 | /* Attribute definition */ 41 | 42 | static struct attribute_spec user_attr = 43 | { "user", 1, 1, false, false, false, handle_user_attribute }; 44 | 45 | /* Plugin callback called during attribute registration */ 46 | 47 | static void 48 | register_attributes (void *event_data, void *data) 49 | { 50 | register_attribute (&user_attr); 51 | } 52 | 53 | /* Checks if stmt is a gimple call tagged with 54 | __attribute__((user("alwayszero"))) */ 55 | 56 | static bool 57 | is_alwayszero_function (gimple stmt) 58 | { 59 | if (!is_gimple_call (stmt)) 60 | return false; 61 | 62 | tree fndecl = gimple_call_fndecl (stmt); 63 | const char* attrarg = NULL; 64 | 65 | if (fndecl != NULL_TREE) 66 | { 67 | tree attrlist = DECL_ATTRIBUTES (fndecl); 68 | if (attrlist != NULL_TREE) 69 | { 70 | tree attr; 71 | for (attr = lookup_attribute("user", attrlist); 72 | attr != NULL_TREE; 73 | attr = lookup_attribute("user", TREE_CHAIN (attr))) 74 | { 75 | attrarg = TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr))); 76 | if (strcmp(attrarg, "alwayszero") == 0) 77 | return true; 78 | } 79 | } 80 | } 81 | return false; 82 | } 83 | 84 | /* Entry point for the alwayszero optimization pass. 85 | Creates a new assignment statement with the lhs of the alwayszero call 86 | then swaps out the old lhs with a new dummy temporary */ 87 | 88 | static unsigned int 89 | execute_alwayszero_opt (void) 90 | { 91 | gimple_stmt_iterator gsi; 92 | basic_block bb; 93 | 94 | FOR_EACH_BB (bb) 95 | { 96 | for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) 97 | { 98 | gimple stmt = gsi_stmt (gsi); 99 | if (is_gimple_call (stmt) && gimple_call_lhs (stmt) != NULL_TREE && 100 | is_alwayszero_function (stmt)) 101 | { 102 | tree lhs = gimple_get_lhs (stmt); 103 | tree zero = build_int_cst (TREE_TYPE (lhs), 0); 104 | gimple assign = gimple_build_assign_stat (lhs, zero); 105 | tree var = create_tmp_var (TREE_TYPE (lhs), "dummy_var"); 106 | add_referenced_var (var); 107 | mark_sym_for_renaming (var); 108 | gimple_call_set_lhs (stmt, var); 109 | gsi_insert_after (&gsi, assign, GSI_CONTINUE_LINKING); 110 | } 111 | } 112 | } 113 | 114 | return 0; 115 | } 116 | 117 | static struct gimple_opt_pass pass_alwayszero = 118 | { 119 | { 120 | GIMPLE_PASS, 121 | "alwayszero", /* name */ 122 | NULL, /* gate */ 123 | execute_alwayszero_opt, /* execute */ 124 | NULL, /* sub */ 125 | NULL, /* next */ 126 | 0, /* static_pass_number */ 127 | 0, /* tv_id */ 128 | PROP_cfg | PROP_ssa, /* properties_required */ 129 | 0, /* properties_provided */ 130 | 0, /* properties_destroyed */ 131 | 0, /* todo_flags_start */ 132 | TODO_dump_func 133 | | TODO_verify_ssa 134 | | TODO_update_ssa /* todo_flags_finish */ 135 | } 136 | }; 137 | 138 | /* The initialization routine exposed to and called by GCC. The spec of this 139 | function is defined in gcc/gcc-plugin.h. */ 140 | 141 | int 142 | plugin_init (struct plugin_name_args *plugin_info, 143 | struct plugin_gcc_version *version) 144 | { 145 | struct register_pass_info pass_info; 146 | const char *plugin_name = plugin_info->base_name; 147 | int argc = plugin_info->argc; 148 | struct plugin_argument *argv = plugin_info->argv; 149 | 150 | /* Handle alwayszero functions near conditional constant propagation */ 151 | pass_info.pass = &pass_alwayszero.pass; 152 | pass_info.reference_pass_name = "ccp"; 153 | pass_info.ref_pass_instance_number = 1; 154 | /* It seems more logical to insert the pass before ccp, but: 155 | A) this does the trick anyway, even with regard to dead branch elimination 156 | B) inserting directly before ccp prevents recognition of user attributes 157 | for some reason 158 | C) this pass can go almost anywhere as long as you're in SSA form 159 | */ 160 | pass_info.pos_op = PASS_POS_INSERT_AFTER; 161 | 162 | /* Register this new pass with GCC */ 163 | register_callback (plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, 164 | &pass_info); 165 | 166 | /* Register the user attribute */ 167 | register_callback (plugin_name, PLUGIN_ATTRIBUTES, register_attributes, NULL); 168 | 169 | return 0; 170 | } 171 | -------------------------------------------------------------------------------- /attribute_plugin-test-1.C: -------------------------------------------------------------------------------- 1 | // { dg-warning "Callback to register attributes" "" { target *-*-* } 0 } 2 | 3 | void normal_func (char c, char c2); 4 | void normal_func (char __attribute__((user("param"))) c, char); 5 | void normal_func (char c, char __attribute__((user("param"))) c2) 6 | { 7 | } // { dg-warning "attribute 'user' on param 'c' of function normal_func" } 8 | // { dg-warning "attribute 'user' on param 'c2' of function normal_func" "" { target *-*-* } 7 } 9 | 10 | class Foo { 11 | void method (char __attribute__((user("param"))) c); 12 | }; 13 | 14 | void Foo::method(char c) 15 | { 16 | } // { dg-warning "attribute 'user' on param 'c' of function method" } 17 | -------------------------------------------------------------------------------- /attribute_plugin.c: -------------------------------------------------------------------------------- 1 | /* Demonstrates how to add custom attributes */ 2 | 3 | #include "gcc-plugin.h" 4 | #include 5 | #include "config.h" 6 | #include "system.h" 7 | #include "coretypes.h" 8 | #include "tree.h" 9 | #include "tree-pass.h" 10 | #include "intl.h" 11 | 12 | int plugin_is_GPL_compatible; 13 | 14 | /* Attribute handler callback */ 15 | 16 | static tree 17 | handle_user_attribute (tree *node, tree name, tree args, 18 | int flags, bool *no_add_attrs) 19 | { 20 | return NULL_TREE; 21 | } 22 | 23 | /* Attribute definition */ 24 | 25 | static struct attribute_spec user_attr = 26 | { "user", 1, 1, false, false, false, handle_user_attribute }; 27 | 28 | /* Plugin callback called during attribute registration */ 29 | 30 | static void 31 | register_attributes (void *event_data, void *data) 32 | { 33 | warning (0, G_("Callback to register attributes")); 34 | register_attribute (&user_attr); 35 | } 36 | 37 | /* Callback function to invoke before the function body is genericized. */ 38 | 39 | void 40 | handle_pre_generic (void *event_data, void *data) 41 | { 42 | tree fndecl = (tree) event_data; 43 | tree arg; 44 | for (arg = DECL_ARGUMENTS(fndecl); arg; arg = TREE_CHAIN (arg)) { 45 | tree attr; 46 | for (attr = DECL_ATTRIBUTES (arg); attr; attr = TREE_CHAIN (attr)) { 47 | tree attrname = TREE_PURPOSE (attr); 48 | tree attrargs = TREE_VALUE (attr); 49 | warning (0, G_("attribute '%s' on param '%s' of function %s"), 50 | IDENTIFIER_POINTER (attrname), 51 | IDENTIFIER_POINTER (DECL_NAME (arg)), 52 | IDENTIFIER_POINTER (DECL_NAME (fndecl)) 53 | ); 54 | } 55 | } 56 | } 57 | 58 | int 59 | plugin_init (struct plugin_name_args *plugin_info, 60 | struct plugin_gcc_version *version) 61 | { 62 | const char *plugin_name = plugin_info->base_name; 63 | register_callback (plugin_name, PLUGIN_PRE_GENERICIZE, 64 | handle_pre_generic, NULL); 65 | 66 | register_callback (plugin_name, PLUGIN_ATTRIBUTES, register_attributes, NULL); 67 | return 0; 68 | } 69 | -------------------------------------------------------------------------------- /dumb-plugin-test-1.C: -------------------------------------------------------------------------------- 1 | // Test case for the dumb plugin. 2 | // { dg-do compile } 3 | // { dg-options "-O -fplugin-arg-dumb_plugin-ref-pass-name=ccp -fplugin-arg-dumb_plugin-ref-pass-instance-num=1" } 4 | 5 | class Foo { 6 | private: 7 | int a_; 8 | 9 | public: 10 | Foo() : a_(a_) {} // { dg-warning "Before genericizing function" } 11 | 12 | void setA(int a) { 13 | a_ = a_; 14 | } // { dg-warning "Before genericizing function" } 15 | 16 | void operator=(Foo& rhs) { 17 | this->a_ = rhs.a_; 18 | } // { dg-warning "Before genericizing function" } 19 | }; // { dg-warning "Process struct Foo" } 20 | 21 | struct Bar { 22 | int b_; 23 | int c_; 24 | }; // { dg-warning "Process struct Bar" } 25 | 26 | int g = g; 27 | Foo foo = foo; 28 | 29 | int func() 30 | { 31 | Bar *bar1, bar2; 32 | Foo local_foo; 33 | int x = x; 34 | static int y = y; 35 | float *f; 36 | Bar bar_array[5]; 37 | char n; 38 | int overflow; 39 | 40 | *f = *f; 41 | bar1->b_ = bar1->b_; 42 | bar2.c_ = bar2.c_; 43 | local_foo = local_foo; 44 | foo = foo; 45 | foo.setA(5); 46 | bar_array[3].c_ = bar_array[3].c_; 47 | bar_array[x+g].b_ = bar_array[x+g].b_; 48 | y = x; 49 | x = y; 50 | } // { dg-warning "Before genericizing function" } 51 | 52 | // { dg-warning "Analyze function" "" { target *-*-* } 50 } 53 | // { dg-warning "End of compilation unit" "" { target *-*-* } 50 } 54 | -------------------------------------------------------------------------------- /dumb_plugin.c: -------------------------------------------------------------------------------- 1 | /* A trivial (dumb) plugin example that shows how to use the GCC plugin 2 | mechanism. */ 3 | 4 | #include "gcc-plugin.h" 5 | #include 6 | #include "config.h" 7 | #include "system.h" 8 | #include "coretypes.h" 9 | #include "tree.h" 10 | #include "tree-pass.h" 11 | #include "intl.h" 12 | 13 | int plugin_is_GPL_compatible; 14 | 15 | /* Callback function to invoke after GCC finishes parsing a struct. */ 16 | 17 | void 18 | handle_struct (void *event_data, void *data) 19 | { 20 | tree type = (tree) event_data; 21 | warning (0, G_("Process struct %s"), 22 | IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)))); 23 | } 24 | 25 | /* Callback function to invoke before the function body is genericized. */ 26 | 27 | void 28 | handle_pre_generic (void *event_data, void *data) 29 | { 30 | tree fndecl = (tree) event_data; 31 | warning (0, G_("Before genericizing function %s"), 32 | IDENTIFIER_POINTER (DECL_NAME (fndecl))); 33 | } 34 | 35 | /* Callback function to invoke after GCC finishes the compilation unit. */ 36 | 37 | void 38 | handle_end_of_compilation_unit (void *event_data, void *data) 39 | { 40 | warning (0, G_("End of compilation unit")); 41 | } 42 | 43 | 44 | static unsigned int 45 | execute_dumb_plugin_example (void) 46 | { 47 | warning (0, G_("Analyze function %s"), 48 | IDENTIFIER_POINTER (DECL_NAME (current_function_decl))); 49 | return 0; 50 | } 51 | 52 | static bool 53 | gate_dumb_plugin_example (void) 54 | { 55 | return true; 56 | } 57 | 58 | static struct gimple_opt_pass pass_dumb_plugin_example = 59 | { 60 | { 61 | GIMPLE_PASS, 62 | "dumb_plugin_example", /* name */ 63 | gate_dumb_plugin_example, /* gate */ 64 | execute_dumb_plugin_example, /* execute */ 65 | NULL, /* sub */ 66 | NULL, /* next */ 67 | 0, /* static_pass_number */ 68 | 0, /* tv_id */ 69 | PROP_cfg, /* properties_required */ 70 | 0, /* properties_provided */ 71 | 0, /* properties_destroyed */ 72 | 0, /* todo_flags_start */ 73 | TODO_dump_func /* todo_flags_finish */ 74 | } 75 | }; 76 | 77 | /* Initialization function that GCC calls. This plugin takes an argument 78 | that specifies the name of the reference pass and an instance number, 79 | both of which determine where the plugin pass should be inserted. */ 80 | 81 | int 82 | plugin_init (struct plugin_name_args *plugin_info, 83 | struct plugin_gcc_version *version) 84 | { 85 | struct register_pass_info pass_info; 86 | const char *plugin_name = plugin_info->base_name; 87 | int argc = plugin_info->argc; 88 | struct plugin_argument *argv = plugin_info->argv; 89 | char *ref_pass_name = NULL; 90 | int ref_instance_number = 0; 91 | int i; 92 | 93 | /* Process the plugin arguments. This plugin takes the following arguments: 94 | ref-pass-name= and ref-pass-instance-num=. */ 95 | for (i = 0; i < argc; ++i) 96 | { 97 | if (!strcmp (argv[i].key, "ref-pass-name")) 98 | { 99 | if (argv[i].value) 100 | ref_pass_name = argv[i].value; 101 | else 102 | warning (0, G_("option '-fplugin-arg-%s-ref-pass-name'" 103 | " requires a pass name"), plugin_name); 104 | } 105 | else if (!strcmp (argv[i].key, "ref-pass-instance-num")) 106 | { 107 | if (argv[i].value) 108 | ref_instance_number = strtol (argv[i].value, NULL, 0); 109 | else 110 | warning (0, G_("option '-fplugin-arg-%s-ref-pass-instance-num'" 111 | " requires an integer value"), plugin_name); 112 | } 113 | else 114 | warning (0, G_("plugin %qs: unrecognized argument %qs ignored"), 115 | plugin_name, argv[i].key); 116 | } 117 | 118 | if (!ref_pass_name) 119 | { 120 | error (G_("plugin %qs requires a reference pass name"), plugin_name); 121 | return 1; 122 | } 123 | 124 | pass_info.pass = &pass_dumb_plugin_example.pass; 125 | pass_info.reference_pass_name = ref_pass_name; 126 | pass_info.ref_pass_instance_number = ref_instance_number; 127 | pass_info.pos_op = PASS_POS_INSERT_AFTER; 128 | 129 | register_callback (plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &pass_info); 130 | 131 | /* 132 | register_callback (plugin_name, PLUGIN_FINISH_TYPE, handle_struct, NULL); 133 | 134 | register_callback (plugin_name, PLUGIN_PRE_GENERICIZE, 135 | handle_pre_generic, NULL); 136 | 137 | register_callback (plugin_name, PLUGIN_FINISH_UNIT, 138 | handle_end_of_compilation_unit, NULL); 139 | */ 140 | return 0; 141 | } 142 | -------------------------------------------------------------------------------- /ggcplug-test-1.c: -------------------------------------------------------------------------------- 1 | /* Test the ggcplug plugin. */ 2 | /* { dg-do compile } */ 3 | /* { dg-options "-O" } */ 4 | 5 | int main() 6 | { 7 | int i=0, j=0; 8 | for (i= 0; i<1000; i++) 9 | if (i%8 == 0) 10 | j++; 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /ggcplug.c: -------------------------------------------------------------------------------- 1 | /* This plugin tests the GGC related plugin events. */ 2 | /* { dg-options "-O" } */ 3 | 4 | #include "config.h" 5 | #include "system.h" 6 | #include "coretypes.h" 7 | #include "tm.h" 8 | #include "toplev.h" 9 | #include "basic-block.h" 10 | #include "gimple.h" 11 | #include "tree.h" 12 | #include "tree-pass.h" 13 | #include "intl.h" 14 | #include "gcc-plugin.h" 15 | #include "plugin-version.h" 16 | 17 | int plugin_is_GPL_compatible; 18 | 19 | /* our callback is the same for all PLUGIN_GGC_START, 20 | PLUGIN_GGC_MARKING, PLUGIN_GGC_END events; it just increments the 21 | user_data which is an int */ 22 | static void increment_callback (void *gcc_data, void *user_data); 23 | 24 | /* our counters are user_data */ 25 | static int our_ggc_start_counter; 26 | static int our_ggc_end_counter; 27 | static int our_ggc_marking_counter; 28 | 29 | /* our empty GGC extra root table */ 30 | static const struct ggc_root_tab our_xtratab[] = { 31 | LAST_GGC_ROOT_TAB 32 | }; 33 | 34 | 35 | /* The initialization routine exposed to and called by GCC. The spec of this 36 | function is defined in gcc/gcc-plugin.h. 37 | 38 | Note that this function needs to be named exactly "plugin_init". */ 39 | int 40 | plugin_init (struct plugin_name_args *plugin_info, 41 | struct plugin_gcc_version *version) 42 | { 43 | const char *plugin_name = plugin_info->base_name; 44 | int argc = plugin_info->argc; 45 | int i = 0; 46 | struct plugin_argument *argv = plugin_info->argv; 47 | if (!plugin_default_version_check (version, &gcc_version)) 48 | return 1; 49 | /* Process the plugin arguments. This plugin takes the following arguments: 50 | count-ggc-start count-ggc-end count-ggc-mark */ 51 | for (i = 0; i < argc; ++i) 52 | { 53 | if (!strcmp (argv[i].key, "count-ggc-start")) 54 | { 55 | if (argv[i].value) 56 | warning (0, G_ ("option '-fplugin-arg-%s-count-ggc-start=%s'" 57 | " ignored (superfluous '=%s')"), 58 | plugin_name, argv[i].value, argv[i].value); 59 | else 60 | register_callback ("ggcplug", 61 | PLUGIN_GGC_START, 62 | increment_callback, 63 | (void *) &our_ggc_start_counter); 64 | } 65 | else if (!strcmp (argv[i].key, "count-ggc-end")) 66 | { 67 | if (argv[i].value) 68 | warning (0, G_ ("option '-fplugin-arg-%s-count-ggc-end=%s'" 69 | " ignored (superfluous '=%s')"), 70 | plugin_name, argv[i].value, argv[i].value); 71 | else 72 | register_callback ("ggcplug", 73 | PLUGIN_GGC_END, 74 | increment_callback, 75 | (void *) &our_ggc_end_counter); 76 | } 77 | else if (!strcmp (argv[i].key, "count-ggc-mark")) 78 | { 79 | if (argv[i].value) 80 | warning (0, G_ ("option '-fplugin-arg-%s-count-ggc-mark=%s'" 81 | " ignored (superfluous '=%s')"), 82 | plugin_name, argv[i].value, argv[i].value); 83 | else 84 | register_callback ("ggcplug", 85 | PLUGIN_GGC_MARKING, 86 | increment_callback, 87 | (void *) &our_ggc_marking_counter); 88 | } 89 | else if (!strcmp (argv[i].key, "test-extra-root")) 90 | { 91 | if (argv[i].value) 92 | warning (0, G_ ("option '-fplugin-arg-%s-test-extra-root=%s'" 93 | " ignored (superfluous '=%s')"), 94 | plugin_name, argv[i].value, argv[i].value); 95 | else 96 | register_callback ("ggcplug", 97 | PLUGIN_REGISTER_GGC_ROOTS, 98 | NULL, 99 | (void *) our_xtratab); 100 | } 101 | } 102 | /* plugin initialization succeeded */ 103 | return 0; 104 | } 105 | 106 | static void 107 | increment_callback (void *gcc_data, void *user_data) 108 | { 109 | int *usercountptr = (int *) user_data; 110 | gcc_assert (!gcc_data); 111 | gcc_assert (user_data); 112 | (*usercountptr)++; 113 | } 114 | -------------------------------------------------------------------------------- /pragma_plugin-test-1.C: -------------------------------------------------------------------------------- 1 | // { dg-warning "Callback to register pragmas" "" { target *-*-* } 0 } 2 | 3 | int some_func (int c); 4 | 5 | #pragma GCCPLUGIN sayhello "here" // { dg-warning "'pragma GCCPLUGIN sayhello' outside of function: here" } 6 | 7 | int some_func (const char* s) 8 | { 9 | #pragma GCCPLUGIN sayhello "at start" // { dg-warning "'pragma GCCPLUGIN sayhello' from function 'some_func': at start" } 10 | 11 | #define DO_PRAGMA(x) _Pragma(#x) 12 | if (!s) 13 | { 14 | DO_PRAGMA(GCCPLUGIN sayhello "in block"); // { dg-warning "'pragma GCCPLUGIN sayhello' from function 'some_func': in block" } 15 | return 0; 16 | } 17 | return 1; 18 | } 19 | -------------------------------------------------------------------------------- /pragma_plugin.c: -------------------------------------------------------------------------------- 1 | /* Demonstrates how to add custom pragmas */ 2 | 3 | #include "gcc-plugin.h" 4 | #include 5 | #include "config.h" 6 | #include "system.h" 7 | #include "coretypes.h" 8 | #include "tm.h" 9 | #include "rtl.h" 10 | #include "tree.h" 11 | #include "function.h" 12 | #include "c-pragma.h" 13 | #include "cpplib.h" 14 | #include "tree-pass.h" 15 | #include "intl.h" 16 | 17 | int plugin_is_GPL_compatible; 18 | 19 | 20 | /* handler of #pragma GCCPLUGIN sayhello "message" is quite similar to 21 | handler of #pragma GCC message...*/ 22 | 23 | static void 24 | handle_pragma_sayhello (cpp_reader *dummy) 25 | { 26 | tree message = 0; 27 | if (pragma_lex (&message) != CPP_STRING) 28 | { 29 | warning (OPT_Wpragmas, "%<#pragma GCCPLUGIN sayhello%> is not a string"); 30 | return; 31 | } 32 | if (TREE_STRING_LENGTH (message) > 1) 33 | if (cfun) 34 | warning (OPT_Wpragmas, 35 | "% from function %qE: %s", 36 | cfun->decl, TREE_STRING_POINTER (message)); 37 | else 38 | warning (OPT_Wpragmas, 39 | "% outside of function: %s", 40 | TREE_STRING_POINTER (message)); 41 | } 42 | 43 | /* Plugin callback called during pragma registration */ 44 | 45 | static void 46 | register_my_pragma (void *event_data, void *data) 47 | { 48 | warning (0, G_("Callback to register pragmas")); 49 | c_register_pragma ("GCCPLUGIN", "sayhello", handle_pragma_sayhello); 50 | } 51 | 52 | int 53 | plugin_init (struct plugin_name_args *plugin_info, 54 | struct plugin_gcc_version *version) 55 | { 56 | const char *plugin_name = plugin_info->base_name; 57 | 58 | register_callback (plugin_name, PLUGIN_PRAGMAS, register_my_pragma, NULL); 59 | return 0; 60 | } 61 | -------------------------------------------------------------------------------- /self-assign-test-1.C: -------------------------------------------------------------------------------- 1 | // Test the self-assignemnt detection plugin. 2 | // { dg-do compile } 3 | // { dg-options "-O" } 4 | 5 | class Foo { 6 | private: 7 | int a_; 8 | 9 | public: 10 | Foo() : a_(a_) {} // { dg-warning "assigned to itself" } 11 | 12 | void setA(int a) { 13 | a_ = a_; // { dg-warning "assigned to itself" } 14 | } 15 | 16 | void operator=(Foo& rhs) { 17 | this->a_ = rhs.a_; 18 | } 19 | }; 20 | 21 | struct Bar { 22 | int b_; 23 | int c_; 24 | }; 25 | 26 | int g = g; // { dg-warning "assigned to itself" } 27 | Foo foo = foo; // { dg-warning "assigned to itself" } 28 | 29 | int func() 30 | { 31 | Bar *bar1, bar2; 32 | Foo local_foo; 33 | int x = x; // { dg-warning "assigned to itself" } 34 | static int y = y; // { dg-warning "assigned to itself" } 35 | float *f; 36 | Bar bar_array[5]; 37 | char n; 38 | int overflow; 39 | 40 | *f = *f; // { dg-warning "assigned to itself" } 41 | bar1->b_ = bar1->b_; // { dg-warning "assigned to itself" } 42 | bar2.c_ = bar2.c_; // { dg-warning "assigned to itself" } 43 | local_foo = local_foo; // { dg-warning "assigned to itself" } 44 | foo = foo; // { dg-warning "assigned to itself" } 45 | foo.setA(5); 46 | bar_array[3].c_ = bar_array[3].c_; // { dg-warning "assigned to itself" } 47 | bar_array[x+g].b_ = bar_array[x+g].b_; // { dg-warning "self-assignment detected" } 48 | y = x; 49 | x = y; 50 | } 51 | -------------------------------------------------------------------------------- /self-assign-test-1.c: -------------------------------------------------------------------------------- 1 | /* Test the self-assignemnt detection plugin. */ 2 | /* { dg-do compile } */ 3 | /* { dg-options "-O" } */ 4 | 5 | struct Bar { 6 | int b_; 7 | int c_; 8 | }; 9 | 10 | int g; 11 | 12 | int main() 13 | { 14 | struct Bar *bar; 15 | int x = x; /* { dg-warning "assigned to itself" } */ 16 | static int y; 17 | struct Bar b_array[5]; 18 | 19 | b_array[x+g].b_ = b_array[x+g].b_; /* { dg-warning "self-assignment detected" } */ 20 | g = g; /* { dg-warning "assigned to itself" } */ 21 | y = y; /* { dg-warning "assigned to itself" } */ 22 | bar->b_ = bar->b_; /* { dg-warning "assigned to itself" } */ 23 | } 24 | -------------------------------------------------------------------------------- /self-assign-test-2.C: -------------------------------------------------------------------------------- 1 | // Test the self-assignemnt detection plugin without checking of operator-eq. 2 | // { dg-do compile } 3 | // { dg-options "-O -fplugin-arg-selfassign-no-check-operator-eq" } 4 | 5 | class Foo { 6 | private: 7 | int a_; 8 | 9 | public: 10 | Foo() : a_(a_) {} // { dg-warning "assigned to itself" } 11 | 12 | void setA(int a) { 13 | a_ = a_; // { dg-warning "assigned to itself" } 14 | } 15 | 16 | void operator=(Foo& rhs) { 17 | this->a_ = rhs.a_; 18 | } 19 | }; 20 | 21 | struct Bar { 22 | int b_; 23 | int c_; 24 | }; 25 | 26 | int g = g; // { dg-warning "assigned to itself" } 27 | Foo foo = foo; // { dg-warning "assigned to itself" } 28 | 29 | int func() 30 | { 31 | Bar *bar1, bar2; 32 | Foo local_foo; 33 | int x = x; // { dg-warning "assigned to itself" } 34 | static int y = y; // { dg-warning "assigned to itself" } 35 | float *f; 36 | Bar bar_array[5]; 37 | char n; 38 | int overflow; 39 | 40 | *f = *f; // { dg-warning "assigned to itself" } 41 | bar1->b_ = bar1->b_; // { dg-warning "assigned to itself" } 42 | bar2.c_ = bar2.c_; // { dg-warning "assigned to itself" } 43 | local_foo = local_foo; // { dg-bogus "assigned to itself" } 44 | foo = foo; // { dg-bogus "assigned to itself" } 45 | foo.setA(5); 46 | bar_array[3].c_ = bar_array[3].c_; // { dg-warning "assigned to itself" } 47 | bar_array[x+g].b_ = bar_array[x+g].b_; // { dg-warning "self-assignment detected" } 48 | y = x; 49 | x = y; 50 | } 51 | -------------------------------------------------------------------------------- /self-assign-test-2.c: -------------------------------------------------------------------------------- 1 | /* Test the self-assignemnt detection plugin with the 'disable' argument. */ 2 | /* { dg-do compile } */ 3 | /* { dg-options "-O -fplugin-arg-selfassign-disable" } */ 4 | 5 | struct Bar { 6 | int b_; 7 | int c_; 8 | }; 9 | 10 | int g; 11 | 12 | int main() 13 | { 14 | struct Bar *bar; 15 | int x = x; /* { dg-bogus "assigned to itself" } */ 16 | static int y; 17 | struct Bar b_array[5]; 18 | 19 | b_array[x+g].b_ = b_array[x+g].b_; /* { dg-bogus "self-assignment detected" } */ 20 | g = g; /* { dg-bogus "assigned to itself" } */ 21 | y = y; /* { dg-bogus "assigned to itself" } */ 22 | bar->b_ = bar->b_; /* { dg-bogus "assigned to itself" } */ 23 | } 24 | -------------------------------------------------------------------------------- /self-assign-test-3.C: -------------------------------------------------------------------------------- 1 | // Test the self-assignemnt detection plugin with the 'disable' argument. 2 | // { dg-do compile } 3 | // { dg-options "-O -fplugin-arg-selfassign-disable" } 4 | 5 | class Foo { 6 | private: 7 | int a_; 8 | 9 | public: 10 | Foo() : a_(a_) {} // { dg-bogus "assigned to itself" } 11 | 12 | void setA(int a) { 13 | a_ = a_; // { dg-bogus "assigned to itself" } 14 | } 15 | 16 | void operator=(Foo& rhs) { 17 | this->a_ = rhs.a_; 18 | } 19 | }; 20 | 21 | struct Bar { 22 | int b_; 23 | int c_; 24 | }; 25 | 26 | int g = g; // { dg-bogus "assigned to itself" } 27 | Foo foo = foo; // { dg-bogus "assigned to itself" } 28 | 29 | int func() 30 | { 31 | Bar *bar1, bar2; 32 | Foo local_foo; 33 | int x = x; // { dg-bogus "assigned to itself" } 34 | static int y = y; // { dg-bogus "assigned to itself" } 35 | float *f; 36 | Bar bar_array[5]; 37 | char n; 38 | int overflow; 39 | 40 | *f = *f; // { dg-bogus "assigned to itself" } 41 | bar1->b_ = bar1->b_; // { dg-bogus "assigned to itself" } 42 | bar2.c_ = bar2.c_; // { dg-bogus "assigned to itself" } 43 | local_foo = local_foo; // { dg-bogus "assigned to itself" } 44 | foo = foo; // { dg-bogus "assigned to itself" } 45 | foo.setA(5); 46 | bar_array[3].c_ = bar_array[3].c_; // { dg-bogus "assigned to itself" } 47 | bar_array[x+g].b_ = bar_array[x+g].b_; // { dg-bogus "self-assignment detected" } 48 | y = x; 49 | x = y; 50 | } 51 | -------------------------------------------------------------------------------- /selfassign.c: -------------------------------------------------------------------------------- 1 | /* This plugin contains an analysis pass that detects and warns about 2 | self-assignment statements. */ 3 | /* { dg-options "-O" } */ 4 | 5 | #include "gcc-plugin.h" 6 | #include "config.h" 7 | #include "system.h" 8 | #include "coretypes.h" 9 | #include "tm.h" 10 | #include "toplev.h" 11 | #include "basic-block.h" 12 | #include "gimple.h" 13 | #include "tree.h" 14 | #include "tree-pass.h" 15 | #include "intl.h" 16 | #include "plugin-version.h" 17 | 18 | int plugin_is_GPL_compatible; 19 | 20 | /* Indicate whether to check overloaded operator '=', which is performed by 21 | default. To disable it, use -fplugin-arg-NAME-no-check-operator-eq. */ 22 | bool check_operator_eq = true; 23 | 24 | /* Given a rhs EXPR of a gimple assign statement, if it is 25 | - SSA_NAME : returns its var decl, or, if it is a temp variable, 26 | returns the rhs of its SSA def statement. 27 | - VAR_DECL, PARM_DECL, FIELD_DECL, or a reference expression : 28 | returns EXPR itself. 29 | - any other expression : returns NULL_TREE. */ 30 | 31 | static tree 32 | get_real_ref_rhs (tree expr) 33 | { 34 | switch (TREE_CODE (expr)) 35 | { 36 | case SSA_NAME: 37 | { 38 | /* Given a self-assign statement, say foo.x = foo.x, 39 | the IR (after SSA) looks like: 40 | 41 | D.1797_14 = foo.x; 42 | foo.x ={v} D.1797_14; 43 | 44 | So if the rhs EXPR is an SSA_NAME of a temp variable, 45 | e.g. D.1797_14, we need to grab the rhs of its SSA def 46 | statement (i.e. foo.x). */ 47 | tree vdecl = SSA_NAME_VAR (expr); 48 | if (DECL_ARTIFICIAL (vdecl) 49 | && !gimple_nop_p (SSA_NAME_DEF_STMT (expr))) 50 | { 51 | gimple def_stmt = SSA_NAME_DEF_STMT (expr); 52 | /* We are only interested in an assignment with a single 53 | rhs operand because if it is not, the original assignment 54 | will not possibly be a self-assignment. */ 55 | if (is_gimple_assign (def_stmt) 56 | && (get_gimple_rhs_class (gimple_assign_rhs_code (def_stmt)) 57 | == GIMPLE_SINGLE_RHS)) 58 | return get_real_ref_rhs (gimple_assign_rhs1 (def_stmt)); 59 | else 60 | return NULL_TREE; 61 | } 62 | else 63 | return vdecl; 64 | } 65 | case VAR_DECL: 66 | case PARM_DECL: 67 | case FIELD_DECL: 68 | case COMPONENT_REF: 69 | case INDIRECT_REF: 70 | case ARRAY_REF: 71 | return expr; 72 | default: 73 | return NULL_TREE; 74 | } 75 | } 76 | 77 | /* Given an expression tree, EXPR, that may contains SSA names, returns an 78 | equivalent tree with the SSA names converted to var/parm/field decls 79 | so that it can be used with '%E' format modifier when emitting warning 80 | messages. 81 | 82 | This function currently only supports VAR/PARM/FIELD_DECL, reference 83 | expressions (COMPONENT_REF, INDIRECT_REF, ARRAY_REF), integer constant, 84 | and SSA_NAME. If EXPR contains any other tree nodes (e.g. an arithmetic 85 | expression appears in array index), NULL_TREE is returned. */ 86 | 87 | static tree 88 | get_non_ssa_expr (tree expr) 89 | { 90 | switch (TREE_CODE (expr)) 91 | { 92 | case VAR_DECL: 93 | case PARM_DECL: 94 | case FIELD_DECL: 95 | { 96 | if (DECL_NAME (expr)) 97 | return expr; 98 | else 99 | return NULL_TREE; 100 | } 101 | case COMPONENT_REF: 102 | { 103 | tree base, orig_base = TREE_OPERAND (expr, 0); 104 | tree component, orig_component = TREE_OPERAND (expr, 1); 105 | base = get_non_ssa_expr (orig_base); 106 | if (!base) 107 | return NULL_TREE; 108 | component = get_non_ssa_expr (orig_component); 109 | if (!component) 110 | return NULL_TREE; 111 | /* If either BASE or COMPONENT is converted, build a new 112 | component reference tree. */ 113 | if (base != orig_base || component != orig_component) 114 | return build3 (COMPONENT_REF, TREE_TYPE (component), 115 | base, component, NULL_TREE); 116 | else 117 | return expr; 118 | } 119 | case INDIRECT_REF: 120 | { 121 | tree orig_base = TREE_OPERAND (expr, 0); 122 | tree base = get_non_ssa_expr (orig_base); 123 | if (!base) 124 | return NULL_TREE; 125 | /* If BASE is converted, build a new indirect reference tree. */ 126 | if (base != orig_base) 127 | return build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (base)), base); 128 | else 129 | return expr; 130 | } 131 | case ARRAY_REF: 132 | { 133 | tree array, orig_array = TREE_OPERAND (expr, 0); 134 | tree index, orig_index = TREE_OPERAND (expr, 1); 135 | array = get_non_ssa_expr (orig_array); 136 | if (!array) 137 | return NULL_TREE; 138 | index = get_non_ssa_expr (orig_index); 139 | if (!index) 140 | return NULL_TREE; 141 | /* If either ARRAY or INDEX is converted, build a new array 142 | reference tree. */ 143 | if (array != orig_array || index != orig_index) 144 | return build4 (ARRAY_REF, TREE_TYPE (expr), array, index, 145 | TREE_OPERAND (expr, 2), TREE_OPERAND (expr, 3)); 146 | else 147 | return expr; 148 | } 149 | case SSA_NAME: 150 | { 151 | tree vdecl = SSA_NAME_VAR (expr); 152 | if (DECL_ARTIFICIAL (vdecl) 153 | && !gimple_nop_p (SSA_NAME_DEF_STMT (expr))) 154 | { 155 | gimple def_stmt = SSA_NAME_DEF_STMT (expr); 156 | if (is_gimple_assign (def_stmt) 157 | && (get_gimple_rhs_class (gimple_assign_rhs_code (def_stmt)) 158 | == GIMPLE_SINGLE_RHS)) 159 | vdecl = gimple_assign_rhs1 (def_stmt); 160 | } 161 | return get_non_ssa_expr (vdecl); 162 | } 163 | case INTEGER_CST: 164 | return expr; 165 | default: 166 | /* Return NULL_TREE for any other kind of tree nodes. */ 167 | return NULL_TREE; 168 | } 169 | } 170 | 171 | /* Given the LHS and (real) RHS of a gimple assign statement, STMT, check if 172 | they are the same. If so, print a warning message about self-assignment. */ 173 | 174 | static void 175 | compare_and_warn (gimple stmt, tree lhs, tree rhs) 176 | { 177 | if (operand_equal_p (lhs, rhs, OEP_PURE_SAME)) 178 | { 179 | location_t location; 180 | location = (gimple_has_location (stmt) 181 | ? gimple_location (stmt) 182 | : (DECL_P (lhs) 183 | ? DECL_SOURCE_LOCATION (lhs) 184 | : input_location)); 185 | /* If LHS contains any tree node not currently supported by 186 | get_non_ssa_expr, simply emit a generic warning without 187 | specifying LHS in the message. */ 188 | lhs = get_non_ssa_expr (lhs); 189 | if (lhs) 190 | warning_at (location, 0, G_("%qE is assigned to itself"), lhs); 191 | else 192 | warning_at (location, 0, G_("self-assignment detected")); 193 | } 194 | } 195 | 196 | /* Check and warn if STMT is a self-assign statement. */ 197 | 198 | static void 199 | warn_self_assign (gimple stmt) 200 | { 201 | tree rhs, lhs; 202 | 203 | /* Check assigment statement. */ 204 | if (is_gimple_assign (stmt) 205 | && (get_gimple_rhs_class (gimple_assign_rhs_code (stmt)) 206 | == GIMPLE_SINGLE_RHS)) 207 | { 208 | rhs = get_real_ref_rhs (gimple_assign_rhs1 (stmt)); 209 | if (!rhs) 210 | return; 211 | 212 | lhs = gimple_assign_lhs (stmt); 213 | if (TREE_CODE (lhs) == SSA_NAME) 214 | { 215 | lhs = SSA_NAME_VAR (lhs); 216 | if (DECL_ARTIFICIAL (lhs)) 217 | return; 218 | } 219 | 220 | compare_and_warn (stmt, lhs, rhs); 221 | } 222 | /* Check overloaded operator '=' (if enabled). */ 223 | else if (check_operator_eq && is_gimple_call (stmt)) 224 | { 225 | tree fdecl = gimple_call_fndecl (stmt); 226 | if (fdecl && (DECL_NAME (fdecl) == maybe_get_identifier ("operator="))) 227 | { 228 | /* If 'operator=' takes reference operands, the arguments will be 229 | ADDR_EXPR trees. In this case, just remove the address-taken 230 | operator before we compare the lhs and rhs. */ 231 | lhs = gimple_call_arg (stmt, 0); 232 | if (TREE_CODE (lhs) == ADDR_EXPR) 233 | lhs = TREE_OPERAND (lhs, 0); 234 | rhs = gimple_call_arg (stmt, 1); 235 | if (TREE_CODE (rhs) == ADDR_EXPR) 236 | rhs = TREE_OPERAND (rhs, 0); 237 | 238 | compare_and_warn (stmt, lhs, rhs); 239 | } 240 | } 241 | } 242 | 243 | /* Entry point for the self-assignment detection pass. */ 244 | 245 | static unsigned int 246 | execute_warn_self_assign (void) 247 | { 248 | gimple_stmt_iterator gsi; 249 | basic_block bb; 250 | 251 | FOR_EACH_BB (bb) 252 | { 253 | for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) 254 | warn_self_assign (gsi_stmt (gsi)); 255 | } 256 | 257 | return 0; 258 | } 259 | 260 | /* Pass gate function. Currently always returns true. */ 261 | 262 | static bool 263 | gate_warn_self_assign (void) 264 | { 265 | return true; 266 | } 267 | 268 | static struct gimple_opt_pass pass_warn_self_assign = 269 | { 270 | { 271 | GIMPLE_PASS, 272 | "warn_self_assign", /* name */ 273 | gate_warn_self_assign, /* gate */ 274 | execute_warn_self_assign, /* execute */ 275 | NULL, /* sub */ 276 | NULL, /* next */ 277 | 0, /* static_pass_number */ 278 | 0, /* tv_id */ 279 | PROP_ssa, /* properties_required */ 280 | 0, /* properties_provided */ 281 | 0, /* properties_destroyed */ 282 | 0, /* todo_flags_start */ 283 | TODO_dump_func /* todo_flags_finish */ 284 | } 285 | }; 286 | 287 | /* The initialization routine exposed to and called by GCC. The spec of this 288 | function is defined in gcc/gcc-plugin.h. 289 | 290 | PLUGIN_NAME - name of the plugin (useful for error reporting) 291 | ARGC - the size of the ARGV array 292 | ARGV - an array of key-value argument pair 293 | 294 | Returns 0 if initialization finishes successfully. 295 | 296 | Note that this function needs to be named exactly "plugin_init". */ 297 | 298 | int 299 | plugin_init (struct plugin_name_args *plugin_info, 300 | struct plugin_gcc_version *version) 301 | { 302 | struct register_pass_info pass_info; 303 | const char *plugin_name = plugin_info->base_name; 304 | int argc = plugin_info->argc; 305 | struct plugin_argument *argv = plugin_info->argv; 306 | bool enabled = true; 307 | int i; 308 | 309 | if (!plugin_default_version_check (version, &gcc_version)) 310 | return 1; 311 | 312 | /* Self-assign detection should happen after SSA is constructed. */ 313 | pass_info.pass = &pass_warn_self_assign.pass; 314 | pass_info.reference_pass_name = "ssa"; 315 | pass_info.ref_pass_instance_number = 1; 316 | pass_info.pos_op = PASS_POS_INSERT_AFTER; 317 | 318 | /* Process the plugin arguments. This plugin takes the following arguments: 319 | check-operator-eq, no-check-operator-eq, enable, and disable. 320 | By default, the analysis is enabled with 'operator=' checked. */ 321 | for (i = 0; i < argc; ++i) 322 | { 323 | if (!strcmp (argv[i].key, "check-operator-eq")) 324 | { 325 | if (argv[i].value) 326 | warning (0, G_("option '-fplugin-arg-%s-check-operator-eq=%s'" 327 | " ignored (superfluous '=%s')"), 328 | plugin_name, argv[i].value, argv[i].value); 329 | else 330 | check_operator_eq = true; 331 | } 332 | else if (!strcmp (argv[i].key, "no-check-operator-eq")) 333 | { 334 | if (argv[i].value) 335 | warning (0, G_("option '-fplugin-arg-%s-no-check-operator-eq=%s'" 336 | " ignored (superfluous '=%s')"), 337 | plugin_name, argv[i].value, argv[i].value); 338 | else 339 | check_operator_eq = false; 340 | } 341 | else if (!strcmp (argv[i].key, "enable")) 342 | { 343 | if (argv[i].value) 344 | warning (0, G_("option '-fplugin-arg-%s-enable=%s' ignored" 345 | " (superfluous '=%s')"), 346 | plugin_name, argv[i].value, argv[i].value); 347 | else 348 | enabled = true; 349 | } 350 | else if (!strcmp (argv[i].key, "disable")) 351 | { 352 | if (argv[i].value) 353 | warning (0, G_("option '-fplugin-arg-%s-disable=%s' ignored" 354 | " (superfluous '=%s')"), 355 | plugin_name, argv[i].value, argv[i].value); 356 | else 357 | enabled = false; 358 | } 359 | else 360 | warning (0, G_("plugin %qs: unrecognized argument %qs ignored"), 361 | plugin_name, argv[i].key); 362 | } 363 | 364 | /* Register this new pass with GCC if the analysis is enabled. */ 365 | if (enabled) 366 | register_callback (plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, 367 | &pass_info); 368 | 369 | return 0; 370 | } 371 | -------------------------------------------------------------------------------- /start_unit_plugin.c: -------------------------------------------------------------------------------- 1 | /* This plugin tests the correct operation of a PLUGIN_START_UNIT callback. 2 | * By the time a PLUGIN_START_UNIT callback is invoked, the frontend 3 | * initialization should have completed. At least the different *_type_nodes 4 | * should have been created. This plugin creates an artifical global 5 | * interger variable. 6 | * 7 | */ 8 | #include "gcc-plugin.h" 9 | #include "config.h" 10 | #include "system.h" 11 | #include "coretypes.h" 12 | #include "tm.h" 13 | #include "toplev.h" 14 | #include "basic-block.h" 15 | #include "gimple.h" 16 | #include "tree.h" 17 | #include "tree-pass.h" 18 | #include "intl.h" 19 | 20 | int plugin_is_GPL_compatible; 21 | static tree fake_var = NULL; 22 | 23 | static bool 24 | gate_start_unit (void) 25 | { 26 | return true; 27 | } 28 | 29 | static void start_unit_callback (void *gcc_data, void *user_data) 30 | { 31 | if (integer_type_node) { 32 | fake_var = build_decl (UNKNOWN_LOCATION, VAR_DECL, 33 | get_identifier ("_fake_var_"), 34 | integer_type_node); 35 | TREE_PUBLIC (fake_var) = 1; 36 | DECL_ARTIFICIAL (fake_var) = 1; 37 | } 38 | } 39 | 40 | static void finish_unit_callback (void *gcc_data, void *user_data) 41 | { 42 | if (fake_var == NULL) { 43 | printf ("fake_var not created \n"); 44 | return; 45 | } 46 | if (TREE_CODE (fake_var) != VAR_DECL) { 47 | printf ("fake_var not a VAR_DECL \n"); 48 | return; 49 | } 50 | if (TREE_CODE (TREE_TYPE (fake_var)) != INTEGER_TYPE) { 51 | printf ("fake_var not INTEGER_TYPE \n"); 52 | return; 53 | } 54 | if (DECL_ARTIFICIAL (fake_var) == 0) { 55 | printf ("fake_var not ARTIFICIAL \n"); 56 | return; 57 | } 58 | } 59 | 60 | int plugin_init (struct plugin_name_args *plugin_info, 61 | struct plugin_gcc_version *version) 62 | { 63 | register_callback ("start_unit", PLUGIN_START_UNIT, &start_unit_callback, NULL); 64 | register_callback ("finish_unit", PLUGIN_FINISH_UNIT, &finish_unit_callback, NULL); 65 | return 0; 66 | } 67 | --------------------------------------------------------------------------------