Hi David,

On Mon, 10 Sep 2012, David Malcolm wrote:

> Is it possible for you to post your work-in-progress code somewhere?

Attached.

> I know that you don't feel it's ready for committing, but I would find 
> it helpful - I'm interested in understanding the general approach, 
> rather than seeing completeness or perfection.

Some sort of brain dump follows:

The idea is as follows: as first cut an introspection API that is tied to 
compiler IR concepts rather than GCC specifics.  As such it should be 
implementable also for other compilers, at least the trivial things that 
every traditional compiler will have.  So, we have functions, basic 
blocks, instructions, operands and operators.  Nothing of that should 
relate to tree or gimple or RTL.

Take for instance the (included) dump-plugin.  The goal would be, that 
depending on where you'd put that dumper in the pass pipeline it would 
work _unchanged_ on GENERIC, on GIMPLE and on RTL.  That goal isn't 
reached yet, once because the internal iteration just isn't
implemented for e.g. RTL instruction stream, and once because the operand 
iterator API isn't well suited to the tree-like nesting in GENERIC and 
RTL currently.

[The intermediate goal was to redo the operand API to be tree-like at the 
base, and possibly write small wrappers to again expose the nicer 
interface that GIMPLE would provide (i.e. direct access to all read 
operands of an instruction).]

Another thing I want is simplicity.  E.g. only the bare minimum of types 
should be exposed.  Note how the API itself for instance doesn't expose 
different types of collections, only a general Range which can enumerate 
all things, depending on how it's used (though the implementation has 
runtime checks for wrong usage).

There are some questions to be solved, e.g. memory management for those 
objects that aren't directly tied to GCC objects, e.g. Ranges right now.  
I do have a strong feeling about the relation of e.g. plugin Instructions 
and GCC gimple/rtx, in the sense that plugin authors should _not_ be 
required to manage memory for those things (same for BBs, functions, 
operands).

There are also other things missing: e.g. operators.  The current thing 
doesn't have access to the TREE_CODE/gimple_expr_code/RTX_CODE, and hence 
can't differ between an add and a mul.  Obviously that's less than 
optimal.  But the codes exposed for the plugin should have no relation to 
GCC codes, but again be general concepts.  So, externally the plugin would 
export codes like "GCC_ADD/SUB/MUL", whose enum values will remain stable 
forever, and internally they're mapped from the tree/rtx codes (that 
mapping can changes as we add/remove some enum values from those).

Also types aren't included.  Though some things would be obvious: a 
gcc_type (Operand op) function, and some accessors like "gcc_arithmetic_p 
(Type)", "gcc_width (Type)", "gcc_unsigned_p (Type)" and so on.

Obviously most useful accessors to the individual objects are missing. 
Those accessors again should be fairly unrelated to GCC specific concepts, 
but I would envision things like "gcc_volatile_p (Instruction i)" or 
perhaps "gcc_reg_p (Operand)".

> In particular, as the maintainer of the gcc-python-plugin I want 
> something that will make my life easier.

Well, the current version 0.0 certainly will not make your life easier.  
It misses almost everything ;)  But my goal was to set a ground interface 
that I would be pleased to work with as plugin author, _and_ that is 
easily maintainable by GCC authors (in a way this is actually more 
important), with the hope that actual plugin authors would extend it 
according to above principles as they need.

> By that I mean: something that will make it easier to keep my plugin 
> compatible against "as many gcc versions as possible" (which currently 
> means 4.6 and 4.7, but I want to add 4.8 and so on), and minimize the 
> amount of recompiling I have to do over ABI issues within a GCC release.  

Yes, that's definitely the goal of my approach.  Few opaque types, few 
high level accessors, never to be changed again (ABI wise) in the future, 
...

> My plugin is currently implemented in C (requiring C++ would be a pain 
> for me, but would be doable, I think).

... and the API C only, yes, definitely.

I hope the above made some of the principles clear, even though the actual 
implementation is terribly lacking in features.


Ciao,
Michael.
Index: Makefile.in
===================================================================
--- Makefile.in	(revision 190803)
+++ Makefile.in	(working copy)
@@ -1451,6 +1451,7 @@ ALL_HOST_BACKEND_OBJS = $(GCC_OBJS) $(OB
 ALL_HOST_OBJS = $(ALL_HOST_FRONTEND_OBJS) $(ALL_HOST_BACKEND_OBJS)
 
 BACKEND = libbackend.a main.o @TREEBROWSER@ libcommon-target.a libcommon.a \
+	  plugin/pluginapi.o \
 	$(CPPLIB) $(LIBDECNUMBER)
 
 MOSTLYCLEANFILES = insn-flags.h insn-config.h insn-codes.h \
@@ -2671,6 +2672,10 @@ passes.o : passes.c $(CONFIG_H) $(SYSTEM
 plugin.o : plugin.c $(PLUGIN_H) $(CONFIG_H) $(SYSTEM_H) coretypes.h \
    $(DIAGNOSTIC_CORE_H) $(TREE_H) $(TREE_PASS_H) intl.h $(PLUGIN_VERSION_H) $(GGC_H)
 
+plugin/pluginapi.o : plugin/pluginapi.c plugin/pluginapi.h \
+   $(CONFIG_H) $(SYSTEM_H) coretypes.h $(CGRAPH_H) $(BASIC_BLOCK_H) \
+   $(GIMPLE_H) $(TREE_FLOW_H) $(TREE_PASS_H) $(TREE_PRETTY_PRINT_H)
+
 main.o : main.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) toplev.h $(DIAGNOSTIC_CORE_H)
 
 host-default.o : host-default.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
Index: configure.ac
===================================================================
--- configure.ac	(revision 190803)
+++ configure.ac	(working copy)
@@ -5135,7 +5135,7 @@ case ${CONFIG_HEADERS} in
   echo > cstamp-h ;;
 esac
 # Make sure all the subdirs exist.
-for d in $subdirs doc build common c-family
+for d in $subdirs doc build common c-family plugin
 do
     test -d $d || mkdir $d
 done
Index: configure
===================================================================
--- configure	(revision 190803)
+++ configure	(working copy)
@@ -28425,7 +28425,7 @@ case ${CONFIG_HEADERS} in
   echo > cstamp-h ;;
 esac
 # Make sure all the subdirs exist.
-for d in $subdirs doc build common c-family
+for d in $subdirs doc build common c-family plugin
 do
     test -d $d || mkdir $d
 done
Index: plugin/dump-plugin.c
===================================================================
--- plugin/dump-plugin.c	(revision 0)
+++ plugin/dump-plugin.c	(working copy)
@@ -0,0 +1,59 @@
+#include <stdio.h>
+
+#include <gcc-plugin.h>
+#include <pluginapi.h>
+
+int plugin_is_GPL_compatible;
+
+static void
+after_ipa_callback (void *gcc_data, void *user_data)
+{
+  Range funcs = gcc_all_functions ();
+  Function f;
+  while ((f = gcc_next_function (funcs)))
+    {
+      Range bbs = gcc_cfg (f);
+      Block bb;
+      fprintf (stdout, "\nFunction:\n");
+      while ((bb = gcc_next_bb (bbs)))
+	{
+	  Range stmts = gcc_stmts (bb);
+	  Stmt s;
+	  fprintf (stdout, "  BB:\n");
+	  while ((s = gcc_next_stmt (stmts)))
+	    {
+	      Range ops = gcc_outputs (s);
+	      Operand op;
+	      fprintf (stdout, "    ");
+	      while ((op = gcc_next_operand (ops)))
+		{
+		  fprintf (stdout, " ");
+		  gcc_print_operand (stdout, op);
+		}
+	      gcc_free_range (ops);
+	      fprintf (stdout, " <= someop(");
+	      ops = gcc_inputs (s);
+	      while ((op = gcc_next_operand (ops)))
+		{
+		  fprintf (stdout, " ");
+		  gcc_print_operand (stdout, op);
+		}
+	      gcc_free_range (ops);
+	      fprintf (stdout, ")\n");
+	    }
+	  fprintf (stdout, "\n");
+	  gcc_free_range (stmts);
+	}
+      gcc_free_range (bbs);
+    }
+  gcc_free_range (funcs);
+}
+
+int
+plugin_init (struct plugin_name_args *plugin_info,
+	     struct plugin_gcc_version *version)
+{
+  register_callback ("after_ip", PLUGIN_ALL_IPA_PASSES_END,
+		     &after_ipa_callback, NULL);
+  return 0;
+}
Index: plugin/pluginapi.c
===================================================================
--- plugin/pluginapi.c	(revision 0)
+++ plugin/pluginapi.c	(working copy)
@@ -0,0 +1,236 @@
+/* GCC plugin interface implementation.
+
+   Copyright 2012 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+
+#include "config.h"
+#include "system.h"
+
+/* Include plugin.h first, before the usual GCC headers, so we're
+   sure that it's self-contained.  */
+#include "pluginapi.h"
+
+#include "coretypes.h"
+/*#include "hard-reg-set.h"*/
+#include "cgraph.h"
+#include "basic-block.h"
+#include "gimple.h"
+#include "tree-flow.h"
+#include "tree-pass.h" /* For TDF_xxx.  */
+#include "tree-pretty-print.h"
+
+/* Several of our opaque types are in fact tagged types.  A statement
+   can be a tree (for GENERIC), a gimple or an RTX for instance.
+   We use the low bits of a pointer to encode this.  */
+
+#define TAG_TREE 1
+#define TAG_RTX 2
+#define TAG_GIMPLE 3
+
+#define TAG_BITS 2
+#define TAG_MASK (((uintptr_t)1 << TAG_BITS) - 1)
+
+#define TAGGED_TO_PTR(p) ((void *)((uintptr_t)p & ~TAG_MASK))
+#define PTR_TO_TAGGED(p,t) ((void *)((uintptr_t)p | (uintptr_t)t))
+#define PTR_TAG_P(p,t) (((uintptr_t)p & (uintptr_t)TAG_MASK) == t)
+
+#define STMT_TO_TREE(s) ((tree) TAGGED_TO_PTR (s))
+#define STMT_TO_GIMPLE(s) ((gimple) TAGGED_TO_PTR (s))
+#define STMT_TO_RTX(s) ((rtx) TAGGED_TO_PTR (s))
+#define TREE_TO_STMT(t) ((Stmt) PTR_TO_TAGGED (t, TAG_TREE))
+#define GIMPLE_TO_STMT(g) ((Stmt) PTR_TO_TAGGED (g, TAG_GIMPLE))
+#define RTX_TO_STMT(r) ((Stmt) PTR_TO_TAGGED (r, TAG_RTX))
+
+/* An operand can be RTX or tree.  */
+#define OPER_TO_TREE(o) ((tree) TAGGED_TO_PTR (o))
+#define OPER_TO_RTX(o) ((rtx) TAGGED_TO_PTR (o))
+#define TREE_TO_OPER(t) ((Operand) PTR_TO_TAGGED (t, TAG_TREE))
+#define RTX_TO_OPER(r) ((Operand) PTR_TO_TAGGED (t, TAG_RTX))
+   
+struct Operand_ {};
+struct Function_ {};
+struct Block_ {};
+struct Stmt_ {};
+
+void
+gcc_print_operand (FILE *f, Operand o)
+{
+  tree t = OPER_TO_TREE (o);
+  print_generic_expr (f, t, TDF_VOPS|TDF_MEMSYMS);
+}
+
+enum range_type
+{
+  RT_NONE,
+  RT_FUNCTION,
+  RT_BB,
+  RT_STMT_GIMPLE,
+  /* Possibly RT_STMT_RTL */
+  RT_OPERAND,
+  /* ??? RT_OPERAND_TREE / RT_OPERAND_RTL */
+};
+
+struct Range_
+{
+  enum range_type type;
+  unsigned len;
+  union
+    {
+      struct cgraph_node *cgnode;
+      basic_block bb;
+      gimple_stmt_iterator gsi;
+      ssa_op_iter opiter;
+    } u;
+};
+
+static Range
+get_range (enum range_type type)
+{
+  Range r = (Range)xcalloc (1, sizeof *r);
+  r->type = type;
+  r->len = -1;
+  return r;
+}
+
+void
+gcc_free_range (Range r)
+{
+  free (r);
+}
+
+Range
+gcc_all_functions (void)
+{
+  Range r = get_range (RT_FUNCTION);
+  r->u.cgnode = cgraph_first_function ();
+  return r;
+}
+
+Range
+gcc_cfg (Function f)
+{
+  Range r = get_range (RT_BB);
+  struct function *fun = (struct function *)f;
+  /* ??? For ignoring entry BB, ->next_bb.  */
+  r->u.bb = ENTRY_BLOCK_PTR_FOR_FUNCTION (fun);
+  return r;
+}
+
+Range
+gcc_stmts (Block b)
+{
+  Range r = get_range (RT_STMT_GIMPLE);
+  basic_block bb = (basic_block)b;
+  r->u.gsi = gsi_start_bb (bb);
+  return r;
+}
+
+Range
+gcc_phis (Block b)
+{
+  Range r = get_range (RT_STMT_GIMPLE);
+  basic_block bb = (basic_block)b;
+  r->u.gsi = gsi_start_phis (bb);
+  return r;
+}
+
+Range
+gcc_inputs (Stmt s)
+{
+  Range r = get_range (RT_OPERAND);
+  gimple g = STMT_TO_GIMPLE (s);
+  op_iter_init (&r->u.opiter, g, SSA_OP_ALL_USES);
+  r->u.opiter.iter_type = ssa_op_iter_use;
+  return r;
+}
+
+Range
+gcc_outputs (Stmt s)
+{
+  Range r = get_range (RT_OPERAND);
+  gimple g = STMT_TO_GIMPLE (s);
+  op_iter_init (&r->u.opiter, g, SSA_OP_ALL_DEFS);
+  r->u.opiter.iter_type = ssa_op_iter_def;
+  return r;
+}
+
+unsigned
+gcc_range_len (Range r ATTRIBUTE_UNUSED)
+{
+  return 0;
+}
+
+Function
+gcc_next_function (Range r)
+{
+  struct cgraph_node *node = r->u.cgnode;
+  tree decl;
+  Function ret;
+  if (!node)
+    return NULL;
+  r->u.cgnode = cgraph_next_function (r->u.cgnode);
+  decl = node->symbol.decl;
+  ret = (Function) DECL_STRUCT_FUNCTION (decl);
+  return ret;
+}
+
+Block
+gcc_next_bb (Range r)
+{
+  Block ret = (Block)r->u.bb;
+  if (ret)
+    r->u.bb = r->u.bb->next_bb;
+  return ret;
+}
+
+Stmt
+gcc_next_stmt (Range r)
+{
+  gimple ret;
+  if (gsi_end_p (r->u.gsi))
+    return NULL;
+  ret = gsi_stmt (r->u.gsi);
+  gsi_next (&r->u.gsi);
+  return GIMPLE_TO_STMT (ret);
+}
+
+Operand
+gcc_next_operand (Range r)
+{
+  ssa_op_iter * pi = &r->u.opiter;
+  tree op;
+  if (op_iter_done (pi))
+    return NULL;
+
+  if (pi->iter_type == ssa_op_iter_def)
+    {
+      def_operand_p pop = op_iter_next_def (pi);
+      if (!pop)
+	return NULL;
+      op = DEF_FROM_PTR (pop);
+    }
+  else
+    {
+      use_operand_p pop = op_iter_next_use (pi);
+      if (!pop)
+	return NULL;
+      op = USE_FROM_PTR (pop);
+    }
+  return TREE_TO_OPER (op);
+}
Index: plugin/pluginapi.h
===================================================================
--- plugin/pluginapi.h	(revision 0)
+++ plugin/pluginapi.h	(working copy)
@@ -0,0 +1,35 @@
+struct Function_;
+struct Variable_;
+struct Calledge_;
+
+struct Block_;
+struct Edge_;
+struct Stmt_;
+struct Operand_;
+
+struct Range_;
+
+typedef struct Range_ *Range;
+typedef struct Function_ *Function;
+typedef struct Block_ *Block;
+typedef struct Stmt_ *Stmt;
+typedef struct Operand_ *Operand;
+
+Range gcc_all_functions (void);
+Range gcc_cfg (Function);
+Range gcc_stmts (Block);
+Range gcc_phis (Block);
+Range gcc_inputs (Stmt);
+Range gcc_outputs (Stmt);
+
+void gcc_free_range (Range);
+
+unsigned gcc_range_len (Range);
+
+Function gcc_next_function (Range);
+Block gcc_next_bb (Range);
+Stmt gcc_next_stmt (Range);
+Operand gcc_next_operand (Range);
+
+void gcc_print_stmt (FILE *, Stmt);
+void gcc_print_operand (FILE *, Operand);

Reply via email to