I develop a GCC plugin that instruments the applications being compiled. The applications are written in C and are built with GCC 4.7 (4.8 and 4.9 are also an option) on an x86 Linux system.
My plugin implements a compilation pass which is placed after "ssa" standard pass and operates on GIMPLE representation. Among other things, I need to implement the following but currently cannot figure out how to do it correctly.
When processing a C function, I need to insert the code at its beginning that copies its arguments to the local variables I create, for future processing.
My first naive implementation looked as follows:
tree p;
gimple_seq seq = NULL;
gimple_stmt_iterator gsi = gsi_start_bb(single_succ(ENTRY_BLOCK_PTR));
for (p = DECL_ARGUMENTS(current_function_decl); p; p = DECL_CHAIN(param)) {
tree copy_par;
copy_par = create_tmp_var(TREE_TYPE(p), NULL);
add_referenced_var(copy_par);
copy_par = make_ssa_name(copy_par, NULL);
g = gimple_build_assign(copy_par, p);
SSA_NAME_DEF_STMT(copy_par) = g;
gimple_seq_add_stmt_without_update (&seq, g);
... // more processing here
}
...
gsi_insert_seq_before (&gsi, seq, GSI_SAME_STMT);
This way, however, an invalid assignment of the parameter declaration to a variable is created according to a dump:
gimple_assign <parm_decl, D.2206_11, par, NULL>
D.2206_11
corresponds to the local variable I created, par
- the argument of the function I want to copy.
GCC crashes at some later pass as a result, trying to process this added statement. I suppose this is because p
is not the variable holding the value of the respective argument but a declaration of that variable. Is it this way? And how to get that variable?
I tried using gimple_build_assign_with_ops(NOP_EXPR, copy_par, p, NULL_TREE)
instead of gimple_build_assign()
but it did not do either. GCC still crashes at the same place. I can provide the backtrace but I feel I am just missing something fundamental.
I also looked at traversal of trees starting from TYPE_ARG_TYPES (TREE_TYPE (current_function_decl))
and further via TREE_CHAIN(...)
but that seems to give the types of the arguments rather than the respective variables.
So, the question is, how to add copying of the function's arguments properly.
Note Perhaps, this could be done with the help of MELT or GCC Python plugin, but in this project, I need to perform all transformations of the code using only what GCC itself provides.
I found that copying of the arguments works with GCC 4.8 and 4.9 but not with 4.7. Here is the code that works for me now (instrument_fentry()
performs the copying).
To avoid the copies being removed at the later compile passes, I made the corresponding variables volatile.
In addition, if there were no SSA_NAME with default definition statement specified for a given parameter (see SSA_NAME_IS_DEFAULT_DEF()
), I added such SSA_NAMEs with GIMPLE_NOPs as the defining statements.
This has worked OK with GCC 4.8 and 4.9 so far, so it looks like a bug in GCC 4.7 or some change of rules between GCC 4.7 and 4.8. I could not pinpoint the exact commit though.