Hello,
I am working on an interprocedural analysis (ipa) and transformation for
GCC.
The optimizations is called ipa-initcall-cp because it copies and
propagates
values assign to constants (with static lifetime) as in the case of
calling
an initialization function.
I am new to gcc compiler development, but I already have a working
implementation for ipa-initcall-cp and can be found here [0].
ipa-initcall-cp
is currently implemented as a SIMPLE_IPA_PASS and is able to compile
code for
some benchmarks. The current limitation is that when compiling with
ipa-initcall-cp, one needs to specify the flag `-flto-partition=none`. I
would
like to ask a few questions as a sanity check:
The GCC internal documentation says the following [0]
To facilitate [...] communication [between the different LTO stages],
the GCC
callgraph infrastructure implements virtual clones [...]
A virtual clone in the callgraph is a function that has no associated
body,
just a description of how to create its body based on a different
function.
The description of function modifications includes adjustments to the
function's signature [...], substitutions to perform on the function
body
Looking at the code, I was able to find several examples of clones
(virtual and
other types). The examples that I have been able to find, modify a
function's body but it is all done through the parameters:
* vec<ipa_replace_map *, gc> *tree_map
* ipa_param_adjustments *param_adjustments
(These are found in several functions defined on gcc/cgraphclones.c)
Looking at the definition for ipa_replace_map
(defined on gcc/cgraph.h:713)
```
struct GTY(()) ipa_replace_map
{
/* The new (replacing) tree. */
tree new_tree;
/* Parameter number to replace, when old_tree is NULL. */
int parm_num;
}
```
suggests that the only replacements possible are those that replace a
parameter
with a tree. Furthermore, the comments suggest that previously the
capability
to replace any arbitrary old_tree with new_tree was possible.
Question #1: Is there a way to replace arbitrary old_trees for
new_trees?
Question #2: If there is a way, what is the way to do so?
This is necessary for ipa-initcall-cp because functions might access
global
variables with static life-time and therefore have no impact on the
method's parameters.
So far, instead of using ipa_replace map and parameter adjustments, what
ipa-initcall-cp does is it modifies the original function, and at the
end of
ipa-initcall-cp it creates a clone (with the modified function) and
removes
the original function. I would like to keep around the original
function, as
it seems that it might be necessary for linking without
-flto-partition=none.
It might also be a source of linking errors in some other programs.
As a result, another alternative I have explored is to create a clone
and only
modify the clone.
Question #3: How does creating a clone affect an IPA_REF?
More concretely: If I have the following code
```
static void
propagate_constant_to_read(tree write_val, struct ipa_ref* ref) {
gcc_assert(ref->use == IPA_REF_LOAD);
symtab_node *f_node = ref->referring;
cgraph_node *f_cnode = dyn_cast<cgraph_node *> (f_node);
f_cnode->get_untransformed_body();
cgraph_node *clone = f_cnode->create_clone(/* ... */);
gimple *read_stmt = ref->stmt;
gcc_assert(gimple_code(read_stmt) == GIMPLE_ASSIGN);
gcc_assert(gimple_num_ops(read_stmt) == 2);
tree old_lhs = gimple_op(read_stmt, 0);
push_cfun(clone);
gimple *use_stmt;
imm_use_iterator use_iter;
FOR_EACH_IMM_USE_STMT (use_stmt, use_iter, old_lhs)
{
// replace old use with write...
}
pop_cfun();
}
```
Can I still use ipa_ref/read_stmt but now in the context of the clone?
Will I be iterating over the uses in clone or the uses in f_cnode?
Question #4: Is there a way to map the ipa_ref in one function to the
ipa_ref
in its clones?
Thanks! Any help will be greatly appreciated!
[0] https://gcc.gnu.org/onlinedocs/gccint/IPA.html#IPA