Question about undefined functions' parameters during LTO
Erick Ochoa
erick.ochoa@theobroma-systems.com
Fri Mar 13 08:51:09 GMT 2020
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 <gccadmin@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!
More information about the Gcc
mailing list