Thanks for the help, Martin!

On 05/03/2017 03:42 AM, Martin Jambor wrote:
Hi,

On Sat, Apr 29, 2017 at 06:28:31AM -0500, Daniel Santos wrote:
Brievity is not my forte, so let me start with the questions.  Can somebody
please point me to the pass and/or function where gcc

1.) decides rather or not to inline a function,
There are two inlining passes.  Early-inliner that works in
topological order and inlines (almost) only when the result is
expected to be smaller than uninlined code.  Then there is a full IPA
inlining pass, which can take advantage of LTO and heuristics that
allows code to grow.

To understand both, you really need to read most of ipa-inline*.[ch]
files.  The exact places where the decisions are made are:
   - early_inline_small_functions() and want_early_inline_function_p()
     in ipa-inline.c for early inlining, and
   - the IPA inliner has a few phases and sub-phases itself, see the
     helper functions in ipa_inline() and especially in
     inline_small_functions().  Alternatively, you want to check out
     all functions which call inline_call().

This is a treasure trove of information and I appreciate it. Maybe I can make a goal of writing a guide to this as a means of learning it better and having something to give back. There is a lot I need to learn about IPA and how the CFG is generated (as well as how it estimates code size, speed and such). I've found some nice work from IIT Bombay, although it's a bit out of date (https://www.cse.iitb.ac.in/grc/intdocs/gcc-conceptual-structure.html). I also recently discovered -fdump-ipa-all, but I tried it yet.

I often have to explicitly "always_inline" and/or "flatten" cases where a large static function has only one caller. Inlining would make the caller much larger, but the result would be smaller and faster than the sum of the two -- this is one thing I want to investigate to see if it can be improved.

2.) decides rather or not to make a .constprop version of a
function,
Check out the places that call create_specialized_node() in ipa-cp.c,
namely templated decide_about_value() and the end of
decide_whether_version_node(), which however just checks the flag
do_clone_for_all_contexts set earlier in estimate_local_effects().

I figured this one out after some work, but my understanding of the CFG is still very weak so I can't yet fully understand all of how it works.

3.) a good pass (when all constant propagation is done) to search for fn
parameters and variables (marked with an attribute) that were not
constproped away, and finally
The attributes must be accepted by the front-end.  For example in C
and C++ this is done in gcc/c-family/c-attribs.c.  Afterwards any pass
or any code in the compiler can use lookup_attribute on the
PARM_DECL tree representing the parameter.

Got it.

4.) what mechanism should I use for that search?  (iterate through the tree
to find them and then see if they have rtl?  I haven't worked in this area
yet.
No, I do not think you want to operate on the RTL level (though I have
only very briefly skimmed through the rest of your email).  Use the
gimple/tree representation as I wrote above.  Look at for example
ipa_populate_param_decls() in ipa-prop.c to see how to iterate over
all PARM_DECLs of a function.


Hope this helps,

Martin

This is a great example. I figured out part of this by examining tree structures in memory while debugging -- a slow process. I ended up figuring out where the tree is expanded into RTL in the "expand" pass and I setup a check in expand_expr_real_1() for when it's expanding an SSA_NAME expression. My thought was to wait until the last possible moment for some pass to optimize it away. Now I just need to figure out how to only emit the warning/error once. I'm guessing I want to append something to the tree node for that SSA_NAME? (and then I'm not warning in duplicate for other versioned nodes)

But I'll have to do this loop in order to figure out when to behave differently in decide_whether_version_node().

I have a crude patch with the base functionality -- to warn or error when a parameter or variable declared with __attribute__((constprop)) still exists by the time we expand to RTL, but I have a lot more to learn before I can make this really useful for C metaprogramming.

diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
index f2a88e147ba..5ec7b615e24 100644
--- a/gcc/c-family/c-attribs.c
+++ b/gcc/c-family/c-attribs.c
@@ -139,6 +139,7 @@ static tree handle_bnd_variable_size_attribute (tree *, 
tree, tree, int, bool *)
 static tree handle_bnd_legacy (tree *, tree, tree, int, bool *);
 static tree handle_bnd_instrument (tree *, tree, tree, int, bool *);
 static tree handle_fallthrough_attribute (tree *, tree, tree, int, bool *);
+static tree handle_constprop_attribute (tree *, tree , tree , int , bool *);
/* Table of machine-independent attributes common to all C-like languages. @@ -345,6 +346,8 @@ const struct attribute_spec c_common_attribute_table[] =
                              handle_bnd_instrument, false },
   { "fallthrough",         0, 0, false, false, false,
                              handle_fallthrough_attribute, false },
+  { "constprop",                 0, 0, false, false, false,
+                             handle_constprop_attribute, false },
   { NULL,                     0, 0, false, false, false, NULL, false }
 };
@@ -3173,3 +3176,15 @@ handle_fallthrough_attribute (tree *, tree name, tree, int,
   *no_add_attrs = true;
   return NULL_TREE;
 }
+
+static tree
+handle_constprop_attribute (tree *node, tree name, tree ARG_UNUSED (args),
+                           int flags, bool *no_add_attrs)
+{
+  if (!DECL_P (*node) || !(VAR_P (*node) || TREE_CODE (*node) == PARM_DECL))
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored", name);
+      *no_add_attrs = true;
+    }
+  return NULL_TREE;
+}
diff --git a/gcc/common.opt b/gcc/common.opt
index 4021622cf5c..93dd10e0771 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -557,6 +557,10 @@ Wcast-align
 Common Var(warn_cast_align) Warning
 Warn about pointer casts which increase alignment.
+Wconstprop
+Common Var(warn_constprop) Warning
+Warn when an __attribute__((constprop)) fails to constant-propagate away.
+
 Wcpp
 Common Var(warn_cpp) Init(1) Warning
 Warn when a #warning directive is encountered.
diff --git a/gcc/expr.c b/gcc/expr.c
index 29ebad3a061..c8aba05a76e 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -9717,6 +9717,16 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode 
tmode,
       }
case SSA_NAME:
+      {
+       tree var = SSA_NAME_VAR (exp);
+       /* TODO: Don't repeat warning for same declaration.  */
+       if (var && lookup_attribute ("constprop", DECL_ATTRIBUTES (var)))
+         {
+           warning (OPT_Wconstprop, "Expression %q+D is not constant in this 
context", var);
+           /* TODO: Set something so we don't repeat this warning.  */
+         }
+      }
+
       /* ??? ivopts calls expander, without any preparation from
          out-of-ssa.  So fake instructions as if this was an access to the
         base variable.  This unnecessarily allocates a pseudo, see how we can


Thanks again,
Daniel

Reply via email to