diff mbox

[2/3] Add Cyclomatic complexity GCC plugin

Message ID 20160207223140.830691e83ab579f46f991410@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Emese Revfy Feb. 7, 2016, 9:31 p.m. UTC
Add a very simple plugin to demonstrate the GCC plugin infrastructure. This GCC
plugin computes the cyclomatic complexity of each function.

The complexity M of a function's control flow graph is defined as:
 M = E - N + 2P
where
 E = the number of edges
 N = the number of nodes
 P = the number of connected components (exit nodes).

---
 Makefile                          |   6 +-
 arch/Kconfig                      |  16 +++++
 tools/gcc/Makefile                |   4 ++
 tools/gcc/cyc_complexity_plugin.c | 120 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 145 insertions(+), 1 deletion(-)
 create mode 100644 tools/gcc/cyc_complexity_plugin.c


--
To unsubscribe from this list: send the line "unsubscribe linux-kbuild" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

Rasmus Villemoes Feb. 7, 2016, 11:05 p.m. UTC | #1
On Sun, Feb 07 2016, Emese Revfy <re.emese@gmail.com> wrote:

> Add a very simple plugin to demonstrate the GCC plugin infrastructure.
> This GCC plugin computes the cyclomatic complexity of each function.
>
> The complexity M of a function's control flow graph is defined as:
>  M = E - N + 2P
> where
>  E = the number of edges
>  N = the number of nodes
>  P = the number of connected components (exit nodes).
>
> ---
>  Makefile                          |   6 +-
>  arch/Kconfig                      |  16 +++++
>  tools/gcc/Makefile                |   4 ++
>  tools/gcc/cyc_complexity_plugin.c | 120 ++++++++++++++++++++++++++++++++++++++
>  4 files changed, 145 insertions(+), 1 deletion(-)
>  create mode 100644 tools/gcc/cyc_complexity_plugin.c
>
> diff --git a/Makefile b/Makefile
> index 96ce015..9f76c26 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -628,7 +628,11 @@ else
>  PLUGINCC := $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-plugin.sh "$(HOSTCC)" "$(HOSTCXX)" "$(CC)")
>  endif
>  ifneq ($(PLUGINCC),)
> -export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGINS_AFLAGS
> +ifdef CONFIG_GCC_PLUGIN_CYC_COMPLEXITY
> +GCC_PLUGIN_CYC_COMPLEXITY_CFLAGS := -fplugin=$(objtree)/tools/gcc/cyc_complexity_plugin.so -DGCC_PLUGIN_CYC_COMPLEXITY
> +endif
> +GCC_PLUGINS_CFLAGS := $(GCC_PLUGIN_CYC_COMPLEXITY_CFLAGS)
> +export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGINS_AFLAGS GCC_PLUGIN_CYC_COMPLEXITY

Hm, when the number of plugins grow, I think it'll be somewhat ugly
having all this in the main makefile. Can't all the plugin-related stuff
live in a separate makefile? The same goes for the Kconfig part.

Also, I think the compile command lines are already complicated enough
(I sometimes use V=1 to see what's going on), so I think it's better
that the plugins that need to make themselves known do so "from within"
gcc; something like

static void define_feature_macro(void __unused *event_data, void __unused *data)
{
	cpp_define(parse_in, "HAVE_ATTRIBUTE_FOOBAR");	
}

...

	register_callback(plugin_name, PLUGIN_START_UNIT, &define_feature_macro, NULL);


> +
> +#include "gcc-common.h"
> +
> +int plugin_is_GPL_compatible;
> +
> +static struct plugin_info cyc_complexity_plugin_info = {
> +	.version	= "20150523",
> +	.help		= "Cyclomatic Complexity\n",
> +};
> +
> +static unsigned int handle_function(void)
> +{
> +	int complexity;
> +	expanded_location xloc;
> +
> +	// M = E - N + 2P
> +	complexity = n_edges_for_fn(cfun) - n_basic_blocks_for_fn(cfun) + 2;
> +
> +	xloc = expand_location(DECL_SOURCE_LOCATION(current_function_decl));
> +	fprintf(stderr, "Cyclomatic Complexity %d %s:%s\n", complexity, xloc.file, DECL_NAME_POINTER(current_function_decl));
> +
> +	return 0;
> +}
> +
> +#if BUILDING_GCC_VERSION >= 4009
> +namespace {
> +static const struct pass_data cyc_complexity_pass_data = {
> +#else
> +static struct gimple_opt_pass cyc_complexity_pass = {
> +	.pass = {
> +#endif
> +		.type			= GIMPLE_PASS,
> +		.name			= "cyc_complexity",
> +#if BUILDING_GCC_VERSION >= 4008
> +		.optinfo_flags		= OPTGROUP_NONE,
> +#endif
> +#if BUILDING_GCC_VERSION >= 5000
> +#elif BUILDING_GCC_VERSION >= 4009
> +		.has_gate		= false,
> +		.has_execute		= true,
> +#else
> +		.gate			= NULL,
> +		.execute		= handle_function,
> +		.sub			= NULL,
> +		.next			= NULL,
> +		.static_pass_number	= 0,
> +#endif
> +		.tv_id			= TV_NONE,
> +		.properties_required	= 0,
> +		.properties_provided	= 0,
> +		.properties_destroyed	= 0,
> +		.todo_flags_start	= 0,
> +		.todo_flags_finish	= TODO_dump_func
> +#if BUILDING_GCC_VERSION < 4009
> +	}
> +#endif
> +};
> +

This is really yucky. Is there any way a mere mortal could figure out
how to write this? Or could the compatibility layer provide some utility
macros that would take care of the boilerplate?

Rasmus
--
To unsubscribe from this list: send the line "unsubscribe linux-kbuild" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Emese Revfy Feb. 8, 2016, 9:20 p.m. UTC | #2
On Mon, 08 Feb 2016 00:05:15 +0100
Rasmus Villemoes <linux@rasmusvillemoes.dk> wrote:

> having all this in the main makefile. Can't all the plugin-related stuff
> live in a separate makefile? The same goes for the Kconfig part.

I will do the Makefile separation but I'm not sure about a separate arch/Kconfig.gcc-plugins
as arch/Kconfig seems to be a general collection of arch/toolchain dependent features
so I would rather stick to it until there is a general decision to break it up into smaller pieces.

> Also, I think the compile command lines are already complicated enough
> (I sometimes use V=1 to see what's going on), so I think it's better
> that the plugins that need to make themselves known do so "from within"
> gcc; something like
> 
> static void define_feature_macro(void __unused *event_data, void __unused *data)
> {
> 	cpp_define(parse_in, "HAVE_ATTRIBUTE_FOOBAR");	
> }

I think it is better in the Makefile because -DPLUGIN doesn't matter much in the compile command
compared to -fplugin and -fplugin-arg. An exmaple compile command with more plugins looks like this:

gcc -Wp,-MD,fs/.exec.o.d  -nostdinc -isystem /usr/lib/gcc/x86_64-pc-linux-gnu/4.9.3/include
-I./arch/x86/include -Iarch/x86/include/generated/uapi -Iarch/x86/include/generated  -Iinclude
-I./arch/x86/include/uapi -Iarch/x86/include/generated/uapi -I./include/uapi -Iinclude/generated/uapi
-include ./include/linux/kconfig.h -D__KERNEL__ -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs
-fno-strict-aliasing -fno-common -Werror-implicit-function-declaration -Wno-format-security -std=gnu89
-mno-sse -mno-mmx -mno-sse2 -mno-3dnow -mno-avx -m64 -falign-jumps=1 -falign-loops=1 -mno-80387 -mno-fp-ret-in-387
-mpreferred-stack-boundary=3 -mtune=generic -mno-red-zone -mcmodel=kernel -funit-at-a-time -maccumulate-outgoing-args
-ffreestanding -DCONFIG_X86_X32_ABI -DCONFIG_AS_FXSAVEQ=1 -DCONFIG_AS_SSSE3=1 -DCONFIG_AS_CRC32=1 -DCONFIG_AS_AVX=1 
-DCONFIG_AS_AVX2=1 -pipe -Wno-sign-compare -fno-asynchronous-unwind-tables -fno-delete-null-pointer-checks -Os
-Wno-maybe-uninitialized --param=allow-store-data-races=0 -fno-reorder-blocks -fno-ipa-cp-clone -fno-partial-inlining
-Wframe-larger-than=2048 -fno-stack-protector -Wno-unused-but-set-variable -fno-omit-frame-pointer
-fno-optimize-sibling-calls -fno-var-tracking-assignments -fno-inline-functions-called-once -Wdeclaration-after-statement
-Wno-pointer-sign -fno-strict-overflow -fconserve-stack -Werror=implicit-int -Werror=strict-prototypes -Werror=date-time
-DCC_HAVE_ASM_GOTO -fplugin=./tools/gcc/stackleak_plugin.so -DSTACKLEAK_PLUGIN
-fplugin-arg-stackleak_plugin-track-lowest-sp=100 -fplugin=./tools/gcc/colorize_plugin.so
-fplugin=./tools/gcc/size_overflow_plugin/size_overflow_plugin.so -DSIZE_OVERFLOW_PLUGIN
-fplugin=./tools/gcc/latent_entropy_plugin.so -DLATENT_ENTROPY_PLUGIN -fplugin=./tools/gcc/structleak_plugin.so 
-DSTRUCTLEAK_PLUGIN -fplugin=./tools/gcc/initify_plugin.so -DINITIFY_PLUGIN -fplugin=./tools/gcc/randomize_layout_plugin.so
-DRANDSTRUCT_PLUGIN -fplugin-arg-randomize_layout_plugin-performance-mode    -D"KBUILD_STR(s)=#s" 
-D"KBUILD_BASENAME=KBUILD_STR(exec)"  -D"KBUILD_MODNAME=KBUILD_STR(exec)" -c -o fs/.tmp_exec.o fs/exec.c

> > +#if BUILDING_GCC_VERSION >= 4009
> > +namespace {
> > +static const struct pass_data cyc_complexity_pass_data = {
> > +#else
> > +static struct gimple_opt_pass cyc_complexity_pass = {
> > +	.pass = {
> > +#endif
> > +		.type			= GIMPLE_PASS,
> > +		.name			= "cyc_complexity",
> > +#if BUILDING_GCC_VERSION >= 4008
> > +		.optinfo_flags		= OPTGROUP_NONE,
> > +#endif
> > +#if BUILDING_GCC_VERSION >= 5000
> > +#elif BUILDING_GCC_VERSION >= 4009
> > +		.has_gate		= false,
> > +		.has_execute		= true,
> > +#else
> > +		.gate			= NULL,
> > +		.execute		= handle_function,
> > +		.sub			= NULL,
> > +		.next			= NULL,
> > +		.static_pass_number	= 0,
> > +#endif
> > +		.tv_id			= TV_NONE,
> > +		.properties_required	= 0,
> > +		.properties_provided	= 0,
> > +		.properties_destroyed	= 0,
> > +		.todo_flags_start	= 0,
> > +		.todo_flags_finish	= TODO_dump_func
> > +#if BUILDING_GCC_VERSION < 4009
> > +	}
> > +#endif
> > +};
> > +
> 
> This is really yucky. Is there any way a mere mortal could figure out
> how to write this? Or could the compatibility layer provide some utility
> macros that would take care of the boilerplate?

Yes, it isn't too nice but if I put them into macros (for GIMPLE, IPA and RTL) then
they would have a lot of parameters because the user can and must define too many values
(especially for an IPA pass which has even more fields).
The compatibility with all gcc versions makes it further complicated so I think
the end result would be uglier than it is now.
Kees Cook Feb. 9, 2016, 4:23 a.m. UTC | #3
On Sun, Feb 7, 2016 at 1:31 PM, Emese Revfy <re.emese@gmail.com> wrote:
> Add a very simple plugin to demonstrate the GCC plugin infrastructure. This GCC
> plugin computes the cyclomatic complexity of each function.
>
> The complexity M of a function's control flow graph is defined as:
>  M = E - N + 2P
> where
>  E = the number of edges
>  N = the number of nodes
>  P = the number of connected components (exit nodes).
>
> ---
>  Makefile                          |   6 +-
>  arch/Kconfig                      |  16 +++++
>  tools/gcc/Makefile                |   4 ++
>  tools/gcc/cyc_complexity_plugin.c | 120 ++++++++++++++++++++++++++++++++++++++
>  4 files changed, 145 insertions(+), 1 deletion(-)
>  create mode 100644 tools/gcc/cyc_complexity_plugin.c
>
> diff --git a/Makefile b/Makefile
> index 96ce015..9f76c26 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -628,7 +628,11 @@ else
>  PLUGINCC := $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-plugin.sh "$(HOSTCC)" "$(HOSTCXX)" "$(CC)")
>  endif
>  ifneq ($(PLUGINCC),)
> -export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGINS_AFLAGS
> +ifdef CONFIG_GCC_PLUGIN_CYC_COMPLEXITY
> +GCC_PLUGIN_CYC_COMPLEXITY_CFLAGS := -fplugin=$(objtree)/tools/gcc/cyc_complexity_plugin.so -DGCC_PLUGIN_CYC_COMPLEXITY
> +endif
> +GCC_PLUGINS_CFLAGS := $(GCC_PLUGIN_CYC_COMPLEXITY_CFLAGS)
> +export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGINS_AFLAGS GCC_PLUGIN_CYC_COMPLEXITY
>  ifeq ($(KBUILD_EXTMOD),)
>  gcc-plugins:
>         $(Q)$(MAKE) $(build)=tools/gcc
> diff --git a/arch/Kconfig b/arch/Kconfig
> index a95e5b1..6b7d4de 100644
> --- a/arch/Kconfig
> +++ b/arch/Kconfig
> @@ -365,6 +365,22 @@ config HAVE_GCC_PLUGINS
>           An arch should select this symbol if it supports building with
>           gcc plugins.
>
> +if HAVE_GCC_PLUGINS
> +
> +config GCC_PLUGIN_CYC_COMPLEXITY
> +       bool "Compute the cyclomatic complexity of a function"
> +       help

Rather than the "if HAVE_GCC_PLUGINS" / endif section, I would add
"depends HAVE_GCC_PLUGINS" to the config, which makes things more
discoverable.

> +         The complexity M of a function's control flow graph is defined as:
> +          M = E - N + 2P
> +         where
> +
> +         E = the number of edges
> +         N = the number of nodes
> +         P = the number of connected components (exit nodes).
> +
> +         See Documentation/gcc-plugins.txt for details.

Is this plugin documented there? I don't see a chunk for that in this patch.

> +
> +endif # HAVE_GCC_PLUGINS
>  endmenu # "GCC plugins"
>
>  config HAVE_CC_STACKPROTECTOR
> diff --git a/tools/gcc/Makefile b/tools/gcc/Makefile
> index b2d64af..31c72bf 100644
> --- a/tools/gcc/Makefile
> +++ b/tools/gcc/Makefile
> @@ -12,4 +12,8 @@ endif
>
>  export GCCPLUGINS_DIR HOSTLIBS
>
> +$(HOSTLIBS)-$(CONFIG_GCC_PLUGIN_CYC_COMPLEXITY) := cyc_complexity_plugin.so
> +
>  always := $($(HOSTLIBS)-y)
> +
> +cyc_complexity_plugin-objs := cyc_complexity_plugin.o
> diff --git a/tools/gcc/cyc_complexity_plugin.c b/tools/gcc/cyc_complexity_plugin.c
> new file mode 100644
> index 0000000..c6f0d58
> --- /dev/null
> +++ b/tools/gcc/cyc_complexity_plugin.c
> @@ -0,0 +1,120 @@
> +/*
> + * Copyright 2011-2016 by Emese Revfy <re.emese@gmail.com>
> + * Licensed under the GPL v2, or (at your option) v3
> + *
> + * Homepage:
> + * https://github.com/ephox-gcc-plugins/cyclomatic_complexity
> + *
> + * http://en.wikipedia.org/wiki/Cyclomatic_complexity
> + * The complexity M is then defined as:
> + * M = E - N + 2P
> + * where
> + *
> + *  E = the number of edges of the graph
> + *  N = the number of nodes of the graph
> + *  P = the number of connected components (exit nodes).
> + *
> + * Usage (4.5 - 5):
> + * $ make clean; make run
> + */
> +
> +#include "gcc-common.h"
> +
> +int plugin_is_GPL_compatible;
> +
> +static struct plugin_info cyc_complexity_plugin_info = {
> +       .version        = "20150523",
> +       .help           = "Cyclomatic Complexity\n",
> +};
> +
> +static unsigned int handle_function(void)
> +{
> +       int complexity;
> +       expanded_location xloc;
> +
> +       // M = E - N + 2P
> +       complexity = n_edges_for_fn(cfun) - n_basic_blocks_for_fn(cfun) + 2;
> +
> +       xloc = expand_location(DECL_SOURCE_LOCATION(current_function_decl));
> +       fprintf(stderr, "Cyclomatic Complexity %d %s:%s\n", complexity, xloc.file, DECL_NAME_POINTER(current_function_decl));
> +
> +       return 0;
> +}
> +
> +#if BUILDING_GCC_VERSION >= 4009
> +namespace {
> +static const struct pass_data cyc_complexity_pass_data = {
> +#else
> +static struct gimple_opt_pass cyc_complexity_pass = {
> +       .pass = {
> +#endif
> +               .type                   = GIMPLE_PASS,
> +               .name                   = "cyc_complexity",
> +#if BUILDING_GCC_VERSION >= 4008
> +               .optinfo_flags          = OPTGROUP_NONE,
> +#endif
> +#if BUILDING_GCC_VERSION >= 5000
> +#elif BUILDING_GCC_VERSION >= 4009
> +               .has_gate               = false,
> +               .has_execute            = true,
> +#else
> +               .gate                   = NULL,
> +               .execute                = handle_function,
> +               .sub                    = NULL,
> +               .next                   = NULL,
> +               .static_pass_number     = 0,
> +#endif
> +               .tv_id                  = TV_NONE,
> +               .properties_required    = 0,
> +               .properties_provided    = 0,
> +               .properties_destroyed   = 0,
> +               .todo_flags_start       = 0,
> +               .todo_flags_finish      = TODO_dump_func
> +#if BUILDING_GCC_VERSION < 4009
> +       }
> +#endif
> +};
> +
> +#if BUILDING_GCC_VERSION >= 4009
> +class cyc_complexity_pass : public gimple_opt_pass {
> +public:
> +       cyc_complexity_pass() : gimple_opt_pass(cyc_complexity_pass_data, g) {}
> +#if BUILDING_GCC_VERSION >= 5000
> +       virtual unsigned int execute(function *) { return handle_function(); }
> +#else
> +       unsigned int execute() { return handle_function(); }
> +#endif
> +};
> +}
> +
> +static struct opt_pass *make_cyc_complexity_pass(void)
> +{
> +       return new cyc_complexity_pass();
> +}
> +#else
> +static struct opt_pass *make_cyc_complexity_pass(void)
> +{
> +       return &cyc_complexity_pass.pass;
> +}
> +#endif
> +
> +int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version)
> +{
> +       const char * const plugin_name = plugin_info->base_name;
> +       struct register_pass_info cyc_complexity_pass_info;
> +
> +       cyc_complexity_pass_info.pass                           = make_cyc_complexity_pass();
> +       cyc_complexity_pass_info.reference_pass_name            = "ssa";
> +       cyc_complexity_pass_info.ref_pass_instance_number       = 1;
> +       cyc_complexity_pass_info.pos_op                         = PASS_POS_INSERT_AFTER;
> +
> +       if (!plugin_default_version_check(version, &gcc_version)) {
> +               error(G_("incompatible gcc/plugin versions"));
> +               return 1;
> +       }
> +
> +       register_callback(plugin_name, PLUGIN_INFO, NULL, &cyc_complexity_plugin_info);
> +       register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &cyc_complexity_pass_info);
> +
> +       return 0;
> +}
>
Emese Revfy Feb. 9, 2016, 6:55 p.m. UTC | #4
On Mon, 8 Feb 2016 20:23:12 -0800
Kees Cook <keescook@chromium.org> wrote:
> > +         The complexity M of a function's control flow graph is defined as:
> > +          M = E - N + 2P
> > +         where
> > +
> > +         E = the number of edges
> > +         N = the number of nodes
> > +         P = the number of connected components (exit nodes).
> > +
> > +         See Documentation/gcc-plugins.txt for details.
> 
> Is this plugin documented there? I don't see a chunk for that in this patch.

No yet, please see my other response.

--
Emese
--
To unsubscribe from this list: send the line "unsubscribe linux-kbuild" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/Makefile b/Makefile
index 96ce015..9f76c26 100644
--- a/Makefile
+++ b/Makefile
@@ -628,7 +628,11 @@  else
 PLUGINCC := $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-plugin.sh "$(HOSTCC)" "$(HOSTCXX)" "$(CC)")
 endif
 ifneq ($(PLUGINCC),)
-export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGINS_AFLAGS
+ifdef CONFIG_GCC_PLUGIN_CYC_COMPLEXITY
+GCC_PLUGIN_CYC_COMPLEXITY_CFLAGS := -fplugin=$(objtree)/tools/gcc/cyc_complexity_plugin.so -DGCC_PLUGIN_CYC_COMPLEXITY
+endif
+GCC_PLUGINS_CFLAGS := $(GCC_PLUGIN_CYC_COMPLEXITY_CFLAGS)
+export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGINS_AFLAGS GCC_PLUGIN_CYC_COMPLEXITY
 ifeq ($(KBUILD_EXTMOD),)
 gcc-plugins:
 	$(Q)$(MAKE) $(build)=tools/gcc
diff --git a/arch/Kconfig b/arch/Kconfig
index a95e5b1..6b7d4de 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -365,6 +365,22 @@  config HAVE_GCC_PLUGINS
 	  An arch should select this symbol if it supports building with
 	  gcc plugins.
 
+if HAVE_GCC_PLUGINS
+
+config GCC_PLUGIN_CYC_COMPLEXITY
+	bool "Compute the cyclomatic complexity of a function"
+	help
+	  The complexity M of a function's control flow graph is defined as:
+	   M = E - N + 2P
+	  where
+
+	  E = the number of edges
+	  N = the number of nodes
+	  P = the number of connected components (exit nodes).
+
+	  See Documentation/gcc-plugins.txt for details.
+
+endif # HAVE_GCC_PLUGINS
 endmenu # "GCC plugins"
 
 config HAVE_CC_STACKPROTECTOR
diff --git a/tools/gcc/Makefile b/tools/gcc/Makefile
index b2d64af..31c72bf 100644
--- a/tools/gcc/Makefile
+++ b/tools/gcc/Makefile
@@ -12,4 +12,8 @@  endif
 
 export GCCPLUGINS_DIR HOSTLIBS
 
+$(HOSTLIBS)-$(CONFIG_GCC_PLUGIN_CYC_COMPLEXITY) := cyc_complexity_plugin.so
+
 always := $($(HOSTLIBS)-y)
+
+cyc_complexity_plugin-objs := cyc_complexity_plugin.o
diff --git a/tools/gcc/cyc_complexity_plugin.c b/tools/gcc/cyc_complexity_plugin.c
new file mode 100644
index 0000000..c6f0d58
--- /dev/null
+++ b/tools/gcc/cyc_complexity_plugin.c
@@ -0,0 +1,120 @@ 
+/*
+ * Copyright 2011-2016 by Emese Revfy <re.emese@gmail.com>
+ * Licensed under the GPL v2, or (at your option) v3
+ *
+ * Homepage:
+ * https://github.com/ephox-gcc-plugins/cyclomatic_complexity
+ *
+ * http://en.wikipedia.org/wiki/Cyclomatic_complexity
+ * The complexity M is then defined as:
+ * M = E - N + 2P
+ * where
+ *
+ *  E = the number of edges of the graph
+ *  N = the number of nodes of the graph
+ *  P = the number of connected components (exit nodes).
+ *
+ * Usage (4.5 - 5):
+ * $ make clean; make run
+ */
+
+#include "gcc-common.h"
+
+int plugin_is_GPL_compatible;
+
+static struct plugin_info cyc_complexity_plugin_info = {
+	.version	= "20150523",
+	.help		= "Cyclomatic Complexity\n",
+};
+
+static unsigned int handle_function(void)
+{
+	int complexity;
+	expanded_location xloc;
+
+	// M = E - N + 2P
+	complexity = n_edges_for_fn(cfun) - n_basic_blocks_for_fn(cfun) + 2;
+
+	xloc = expand_location(DECL_SOURCE_LOCATION(current_function_decl));
+	fprintf(stderr, "Cyclomatic Complexity %d %s:%s\n", complexity, xloc.file, DECL_NAME_POINTER(current_function_decl));
+
+	return 0;
+}
+
+#if BUILDING_GCC_VERSION >= 4009
+namespace {
+static const struct pass_data cyc_complexity_pass_data = {
+#else
+static struct gimple_opt_pass cyc_complexity_pass = {
+	.pass = {
+#endif
+		.type			= GIMPLE_PASS,
+		.name			= "cyc_complexity",
+#if BUILDING_GCC_VERSION >= 4008
+		.optinfo_flags		= OPTGROUP_NONE,
+#endif
+#if BUILDING_GCC_VERSION >= 5000
+#elif BUILDING_GCC_VERSION >= 4009
+		.has_gate		= false,
+		.has_execute		= true,
+#else
+		.gate			= NULL,
+		.execute		= handle_function,
+		.sub			= NULL,
+		.next			= NULL,
+		.static_pass_number	= 0,
+#endif
+		.tv_id			= TV_NONE,
+		.properties_required	= 0,
+		.properties_provided	= 0,
+		.properties_destroyed	= 0,
+		.todo_flags_start	= 0,
+		.todo_flags_finish	= TODO_dump_func
+#if BUILDING_GCC_VERSION < 4009
+	}
+#endif
+};
+
+#if BUILDING_GCC_VERSION >= 4009
+class cyc_complexity_pass : public gimple_opt_pass {
+public:
+	cyc_complexity_pass() : gimple_opt_pass(cyc_complexity_pass_data, g) {}
+#if BUILDING_GCC_VERSION >= 5000
+	virtual unsigned int execute(function *) { return handle_function(); }
+#else
+	unsigned int execute() { return handle_function(); }
+#endif
+};
+}
+
+static struct opt_pass *make_cyc_complexity_pass(void)
+{
+	return new cyc_complexity_pass();
+}
+#else
+static struct opt_pass *make_cyc_complexity_pass(void)
+{
+	return &cyc_complexity_pass.pass;
+}
+#endif
+
+int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version)
+{
+	const char * const plugin_name = plugin_info->base_name;
+	struct register_pass_info cyc_complexity_pass_info;
+
+	cyc_complexity_pass_info.pass				= make_cyc_complexity_pass();
+	cyc_complexity_pass_info.reference_pass_name		= "ssa";
+	cyc_complexity_pass_info.ref_pass_instance_number	= 1;
+	cyc_complexity_pass_info.pos_op				= PASS_POS_INSERT_AFTER;
+
+	if (!plugin_default_version_check(version, &gcc_version)) {
+		error(G_("incompatible gcc/plugin versions"));
+		return 1;
+	}
+
+	register_callback(plugin_name, PLUGIN_INFO, NULL, &cyc_complexity_plugin_info);
+	register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &cyc_complexity_pass_info);
+
+	return 0;
+}