Audience: You are expected to be an advanced GCC user (fluent with command-line), and to have successfully downloaded and installed GCC MELT on your computer (probably under GNU/Linux running a recent version -preferably 4.7 or later- of GCC). You have read the tutorial on how to use GCC MELT and then the tutorial on the MELT domain specific language. You may want to have a look at GCC internals documentation (each released version of GCC has its own).
Remember that without any mode given with
the -fplugin-arg-melt-mode=mode
program
argument to gcc
or g++
,
the MELT plugin don't do anything
useful. You should choose a name for your mode (which should not
clash with existing mode names given by the help mode
with -fplugin-arg-melt-mode=help
). Imagine that we
want to implement a mode which counts the functions defined in the
client source code which have a single integer argument. Let's
name this mode count1int.
We need to install a new mode, by creating one instance
of class_melt_mode
then passing it
to install_melt_mode
. That instance, which
we name 'count1int_mode
contains a
function, here count1int_docmd
, doing the
real job. We'll define
that count1int_docmd
function
below (but it should appear first in
your MELT source code file, before count1int_mode
):
(definstance count1int_mode class_melt_mode :named_name '"count1int" :meltmode_help '"install a pass counting functions with a single integer argument." :meltmode_fun count1int_docmd ) (install_melt_mode count1int_mode)The string literals should be quoted, since they are values!
count1int_docmd
, should usually install one -or several- GCC pass[es] coded in MELT. Of course it could do other mode-specific initialization (e.g. connecting to some database server).
The GCC compiler is running a lot (more
than 200 when optimizing!)
of passes. You'll
want to add your own pass within them. There are several kind of
passes, the simplest being plain gimple passes. A pass has
some name (we suggest to start the name
with melt_
to avoid collision with existing passes
names), it also has a optional gate function
deciding if the pass should be run or skipped, and an execute
function doing the actual job.
We obviously need a global counter, as a boxed value:
(define count1int_counter (box 0))
An important issue is to understand where should your own pass be
added. It is difficult to answer. Look into
files gcc/passes.c
and gcc/tree-pass.h
of
your GCC compiler source code (you
probably should download the source code of your gcc
compiler, to be able to study it). You could add your pass
after cfg (the control flow graph pass), or phiopt, etc...
Our count1int_docmd function, referenced
by coutin1int_mode
,
is creating and installing a pass, instance
of class_gcc_gimple_pass
:
(defun count1int_docmd (cmd moduldata)
(let ( (count1intpass
(instance class_gcc_gimple_pass
:named_name '"melt_count1intpass"
:gccpass_exec count1intpass_exec
:gccpass_data (make_maptree discr_map_trees 100)
))
)
(install_melt_pass_in_gcc count1intpass :after '"cfg" 0)
(debug "count1int_mode installed pass=" count1intpass)
(return cmd) ;return non-nil to continue compilation
))
The MELT pass has a
field :gccpass_data
to keep some arbitrary data for
client convenience. Here it is an hash-map keyed
by :tree
stuff (we'll use that to avoid
processing several times the same C function in the
compiled code). Our pass is so simple that we don't need
any gate function (but you could give one using
the :gccpass_gate
field).
Our pass is simple, but it has to figure out if it encounters an
already seen C function (because
the GCC compiler is complex enough to be
able to process several times some functions of the input source
code). The current function declaration (as
some :tree
stuff) is given by
the cfun_decl
primitive. We use the pass' client data.
(defun count1intpass_exec (pass) (let ( (trmap (get_field :gccpass_data pass)) (curfun (cfun_decl)) ) (match curfun (?(tree_function_decl ?tname ?tres) (if (maptree_get trmap curfun) (return)This is incomplete. We need to figure out if the function has one integer formal argument. We still need to inform the user about the counted number of functions, e.g. by registering a function to be done before exiting using;;already seen function
(let ( (oldcnt (get_int count1int_counter)) ) (maptree_put trmap curfun :true);; incomplete: should figure out if the function has one single formal.
)) ) (?_;; not a function, but a variable, a top level asm, ...
(return)) ) ))
at_exit_first
.