On 13.03.20 00:44, Richard Biener wrote:
On Thu, Mar 12, 2020 at 5:31 PM Erick Ochoa
<erick.oc...@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!

Reply via email to