Help with getting started with adding IPA-related attribute

Daniel Santos daniel.santos@pobox.com
Fri May 5 07:24:00 GMT 2017


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



More information about the Gcc mailing list