Question about undefined functions' parameters during LTO
Erick Ochoa
erick.ochoa@theobroma-systems.com
Fri Mar 13 09:05:19 GMT 2020
On 13.03.20 00:44, Richard Biener wrote:
> On Thu, Mar 12, 2020 at 5:31 PM Erick Ochoa
> <erick.ochoa@theobroma-systems.com> wrote:
>>
>> 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.
>>
>> 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:
>>
>> ```
>> 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 argument types or the actual arguments to all calls? "hello world" sounds
> like you want actual arguments. For those you need to look at the callgraph
> edges to the cgraph node of the external functions (node->callers) and there
> at the call stmts - which will not be available in WPA mode.
>
I'm interested in the argument types to all calls of undefined
functions. I have better defined what I mean by "undefined functions" in
a sibling thread: https://gcc.gnu.org/pipermail/gcc/2020-March/231817.html
So, for example, what I'm trying to do is the following:
+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;
+ const char *name = undefined_function->name();
+ gcc_assert(name);
+ if (dump_file) fprintf(dump_file, "getting function arguments for
%s\n", name);
+
+ gcc_assert(undefined_function->decl);
+ for (tree parm = DECL_ARGUMENTS (undefined_function->decl); parm;
parm = DECL_CHAIN (parm))
+ {
+ tree type = TREE_TYPE(parm);
+ if (dump_file) fprintf(dump_file, "I want the type, do I have
it? %s\n", type ? "true" : "false");
+ }
+ }
+ return 0;
+}
I have added the complete patch below, however the function iphw_execute
encapsulates the logic I am trying at the moment.
The problem is that while this program runs, DECL_ARGUMENTS returns NULL
and therefore the loop is never entered. This is true for functions that
have arguments, such as puts/malloc/... and others in glibc.
I suspect this is because glibc is not compiled with -flto (I don't
believe it is possible to compile glibc with -flto) and during the
compilation of a simple hello world the only reference to "puts" is an
extern declaration in stdio.h
So, do you think there's a way to obtain the argument types without
having to iterate over gimple code and look for GIMPLE_CALL and look for
undefined functions, then look at the arguments and their types?
Thanks!
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..5f71f3a411d
--- /dev/null
+++ b/gcc/ipa-hello-world.c
@@ -0,0 +1,90 @@
+#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;
+ const char *name = undefined_function->name();
+ gcc_assert(name);
+ if (dump_file) fprintf(dump_file, "getting function arguments for
%s\n", name);
+
+ gcc_assert(undefined_function->decl);
+ for (tree parm = DECL_ARGUMENTS (undefined_function->decl); parm;
parm = DECL_CHAIN (parm))
+ {
+ tree type = TREE_TYPE(parm);
+ if (dump_file) fprintf(dump_file, "I want the type, do I have
it? %s\n", type ? "true" : "false");
+ }
+ }
+ 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);
>>
>> 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