On 12.03.20 08:48, Jan Hubicka wrote:
Hello,
Hello,
I am trying to find out the arguments of functions which are undefined
during LTO.
Basically:
gcc_assert(in_lto_p && !cnode->definition)
// Do we have arguments?
gcc_assert(DECL_ARGUMENTS(cnode->decl)) // fails
// No, we don't.
As I understand it, functions which are not defined are ones which have have
been declared external.
LTO works in a way that function bodies are loaded from the stream on
demand (using node->get_body or node->get_untransformed_body calls).
Declaration of function parameters are part of function body and that is
why they are missing.
You can get all bodies if you experiment with your pass using the call
above. If you want real LTO pass working at whole propgram eventualy you
will need avoid reading all bodies (or WPA stage will be slow and memory
hungry) and store info you need into summaries.
Thanks. I did tried getting node->get_untransformed_body() and
node->get_body() and for undefined functions which were not compiled
with -flto (such as the ones on glibc) an epected exception is triggered.
Take for example the following simple ipa-pass that I have made only for
this example (can be applied to
54e69cb00da0b50e4fa228a0617e4e8713bbc998 (upstream/master, gcc-master)
Author: GCC Administrator <gccad...@gcc.gnu.org>
Date: Fri Mar 13 00:16:15 2020 +0000)
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index fa9923bb270..92421fe500e 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1399,6 +1399,7 @@ OBJS = \
incpath.o \
init-regs.o \
internal-fn.o \
+ ipa-hello-world.o \
ipa-cp.o \
ipa-sra.o \
ipa-devirt.o \
diff --git a/gcc/common.opt b/gcc/common.opt
index fa9da505fc2..df807e4e388 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -3392,4 +3392,8 @@ fipa-ra
Common Report Var(flag_ipa_ra) Optimization
Use caller save register across calls if possible.
+fipa-hello-world
+Common Report Var(flag_ipa_hello_world) Optimization
+TBD
+
; This comment is to ensure we retain the blank line above.
diff --git a/gcc/ipa-hello-world.c b/gcc/ipa-hello-world.c
new file mode 100644
index 00000000000..402c62c6b59
--- /dev/null
+++ b/gcc/ipa-hello-world.c
@@ -0,0 +1,84 @@
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "tree.h"
+#include "gimple-expr.h"
+#include "predict.h"
+#include "alloc-pool.h"
+#include "tree-pass.h"
+#include "cgraph.h"
+#include "diagnostic.h"
+#include "fold-const.h"
+#include "gimple-fold.h"
+#include "symbol-summary.h"
+#include "tree-vrp.h"
+#include "ipa-prop.h"
+#include "tree-pretty-print.h"
+#include "tree-inline.h"
+#include "ipa-fnsummary.h"
+#include "ipa-utils.h"
+#include "tree-ssa-ccp.h"
+#include "stringpool.h"
+#include "attribs.h"
+
+
+#include <set>
+
+static unsigned int
+iphw_execute()
+{
+ cgraph_node *node = NULL;
+ std::set<cgraph_node *> functions;
+ FOR_EACH_FUNCTION(node)
+ {
+ functions.insert(node);
+ }
+
+ FOR_EACH_DEFINED_FUNCTION(node)
+ {
+ functions.erase(node);
+ }
+
+ for (auto it = functions.cbegin(); it != functions.cend(); ++it)
+ {
+ cgraph_node *undefined_function = *it;
+ if (dump_file) fprintf(dump_file, "getting function body for %s\n",
undefined_function->name());
+
+ //undefined_function->get_untransformed_body();
+ undefined_function->get_body();
+ }
+ return 0;
+}
+
+namespace {
+const pass_data pass_data_ipa_hello_world =
+{
+ SIMPLE_IPA_PASS,
+ "hello-world",
+ OPTGROUP_NONE,
+ TV_NONE,
+ (PROP_cfg | PROP_ssa),
+ 0,
+ 0,
+ 0,
+ 0,
+};
+
+class pass_ipa_hello_world : public simple_ipa_opt_pass
+{
+public:
+ pass_ipa_hello_world (gcc::context *ctx)
+ : simple_ipa_opt_pass(pass_data_ipa_hello_world, ctx)
+ {}
+
+ virtual bool gate(function*) { return flag_ipa_hello_world; }
+ virtual unsigned execute (function*) { return iphw_execute(); }
+};
+} // anon namespace
+
+simple_ipa_opt_pass*
+make_pass_ipa_hello_world (gcc::context *ctx)
+{
+ return new pass_ipa_hello_world (ctx);
+}
diff --git a/gcc/passes.def b/gcc/passes.def
index 2bf2cb78fc5..66f333f81dc 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -149,6 +149,7 @@ along with GCC; see the file COPYING3. If not see
NEXT_PASS (pass_ipa_profile);
NEXT_PASS (pass_ipa_icf);
NEXT_PASS (pass_ipa_devirt);
+ NEXT_PASS (pass_ipa_hello_world);
NEXT_PASS (pass_ipa_cp);
NEXT_PASS (pass_ipa_sra);
NEXT_PASS (pass_ipa_cdtor_merge);
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index a1207a20a3c..377dda689cc 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -501,6 +501,7 @@ extern ipa_opt_pass_d *make_pass_ipa_fn_summary
(gcc::context *ctxt);
extern ipa_opt_pass_d *make_pass_ipa_inline (gcc::context *ctxt);
extern simple_ipa_opt_pass *make_pass_ipa_free_lang_data (gcc::context
*ctxt);
extern simple_ipa_opt_pass *make_pass_ipa_free_fn_summary
(gcc::context *ctxt);
+extern simple_ipa_opt_pass *make_pass_ipa_hello_world (gcc::context *ctxt);
extern ipa_opt_pass_d *make_pass_ipa_cp (gcc::context *ctxt);
extern ipa_opt_pass_d *make_pass_ipa_sra (gcc::context *ctxt);
extern ipa_opt_pass_d *make_pass_ipa_icf (gcc::context *ctxt);
Compile the following program:
#include <stdio.h>
int
main ()
{
puts("hello world\n");
}
And you get the following exception while trying to get the body of
function "puts".
[eochoa@osprey1 temp]$ $HOME/code/gcc-inst/bin/gcc -flto
-fipa-hello-world -fdump-ipa-hello-world -o a.out a.c
during IPA pass: hello-world
lto1: internal compiler error: Segmentation fault
0xbb88d7 crash_signal
/home/eochoa/code/gcc/gcc/toplev.c:328
0xa37830 lto_get_decl_name_mapping(lto_file_decl_data*, char const*)
/home/eochoa/code/gcc/gcc/lto-section-in.c:372
0x6f3e37 cgraph_node::get_untransformed_body()
/home/eochoa/code/gcc/gcc/cgraph.c:3859
0x6f40b3 cgraph_node::get_body()
/home/eochoa/code/gcc/gcc/cgraph.c:3901
0x16007db iphw_execute
/home/eochoa/code/gcc/gcc/ipa-hello-world.c:49
0x16007db execute
/home/eochoa/code/gcc/gcc/ipa-hello-world.c:76
Please submit a full bug report,
with preprocessed source if appropriate.
Please include the complete backtrace with any bug report.
See <https://gcc.gnu.org/bugs/> for instructions.
lto-wrapper: fatal error: /home/eochoa/code/gcc-inst/bin/gcc returned 1
exit status
compilation terminated.
/usr/bin/ld: error: lto-wrapper failed
collect2: error: ld returned 1 exit status
ipa-prop already stores nunber and types of arguments that may be all
you need.
I believe that, when building an application with -flto, the only functions
which are not visible during LTO **and** are declared external are functions
defined in libraries which have not been compiled with -flto. An example of
this is glibc.
Indeed, I have implemented an analysis pass in gcc which prints out
undefined functions, and it prints out the following:
undefined function __gcov_merge_add
undefined function fopen
undefined function printf
undefined function __builtin_putchar
undefined function calloc
undefined function __gcov_merge_topn
undefined function strtol
undefined function free
... and more
Now, I am not interested in the bodies of these. I am only interested in
determining the type of the arguments passed to these functions. However,
when I call the following function:
See ipa_get_type
Thanks for the lead, I did not know about ipa_get_type.
I looked at uses of ipa_get_type and see that it takes ipa_node_params
as a parameter. However, IPA_NODE_REF returns NULL for functions not
compiled with -flto (such as ones in glibc).
//undefined_function->get_untransformed_body(); // <-- segfault puts
//undefined_function->get_body(); // <-- segfault for function puts
//
class ipa_node_params *info;
info = IPA_NODE_REF (undefined_function);
gcc_assert(info); // <-- segfaults for function puts
Erick
Honza
```
void
print_parameters_undefined_functions(const cgraph_node *cnode)
{
gcc_assert(cnode);
gcc_assert(in_lto_p);
gcc_assert(!cnode->definition);
tree function = cnode->decl;
gcc_assert(function);
enum tree_code code = TREE_CODE (function);
bool is_function_decl = FUNCTION_DECL == code;
gcc_assert (is_function_decl);
log("about to print decl_arguments(%s)\n", cnode->name());
for (tree parm = DECL_ARGUMENTS (function); parm; parm = DECL_CHAIN(parm))
{
log("hello world\n");
}
```
I never see "hello world" but I do see "about to print...".
Does anyone have any idea on how to obtain the arguments to undefined
functions?
The only way I see to do this, is to walk through the gimple instructions,
find GIMPLE_CALL statements and look at the argument list at that moment.
But I was wondering if there's a more efficient way to do it.
Thanks!