Thread (12 messages) 12 messages, 4 authors, 2016-02-09

Re: [PATCH 2/3] Add Cyclomatic complexity GCC plugin

From: Rasmus Villemoes <linux@rasmusvillemoes.dk>
Date: 2016-02-07 23:05:20

On Sun, Feb 07 2016, Emese Revfy [off-list ref] wrote:
quoted hunk ↗ jump to hunk
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
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help