On Thu, 2017-11-02 at 10:46 -0400, Jason Merrill wrote:
> On Tue, Oct 31, 2017 at 5:09 PM, David Malcolm <dmalc...@redhat.com>
> wrote:
> > On Tue, 2017-10-24 at 09:53 -0400, Jason Merrill wrote:
> > > On Fri, Oct 20, 2017 at 5:53 PM, David Malcolm <dmalcolm@redhat.c
> > > om>
> > > wrote:
> > > > Design questions:
> > > > 
> > > > * The patch introduces a new kind of tree node, currently
> > > > called
> > > >   DECL_WRAPPER_EXPR (although it's used for wrapping constants
> > > > as
> > > > well
> > > >   as decls).  Should wrappers be a new kind of tree node, or
> > > > should
> > > > they
> > > >   reuse an existing TREE_CODE? (e.g. NOP_EXPR, CONVERT_EXPR,
> > > > etc).
> > > >     * NOP_EXPR: seems to be for use as an rvalue
> > > >     * CONVERT_EXPR: for type conversions
> > > >     * NON_LVALUE_EXPR: "Value is same as argument, but
> > > > guaranteed
> > > > not an
> > > >       lvalue"
> > > >       * but we *do* want to support lvalues here
> > > 
> > > I think using NON_LVALUE_EXPR for constants would be appropriate.
> > > 
> > > >     * VIEW_CONVERT_EXPR: viewing one thing as of a different
> > > > type
> > > >       * can it support lvalues?
> > > 
> > > Yes, the purpose of VIEW_CONVERT_EXPR is to support lvalues, it
> > > seems
> > > like the right choice.
> > > 
> > > Jason
> > 
> > Thanks.  I've been working on a new version of the patch using
> > those
> > tree codes, but have run into an issue.
> > 
> > In g++.dg/conversion/reinterpret1.C:
> > 
> >   // PR c++/15076
> > 
> >   struct Y { Y(int &); };
> > 
> >   int v;
> >   Y y1(reinterpret_cast<int>(v));  // { dg-error "" }
> > 
> > With trunk, this successfully generates an error:
> > 
> >   reinterpret1.C:6:6: error: cannot bind non-const lvalue reference
> > of type ‘int&’ to an rvalue of type ‘int’
> >    Y y1(reinterpret_cast<int>(v));  // { dg-error "" }
> >         ^~~~~~~~~~~~~~~~~~~~~~~~
> >   reinterpret1.C:3:12: note:   initializing argument 1 of
> > ‘Y::Y(int&)’
> >    struct Y { Y(int &); };
> >               ^
> > 
> > where internally there's a NON_LVALUE_EXPR around a VAR_DECL, where
> > both have the same type:
> > 
> > (gdb) call debug_tree (expr)
> >  <non_lvalue_expr 0x7ffff145f6e0
> >     type <integer_type 0x7ffff132e5e8 int public type_6 SI
> >         size <integer_cst 0x7ffff1331120 constant 32>
> >         unit-size <integer_cst 0x7ffff1331138 constant 4>
> >         align:32 warn_if_not_align:0 symtab:0 alias-set -1
> > canonical-type 0x7ffff132e5e8 precision:32 min <integer_cst
> > 0x7ffff13310d8 -2147483648> max <integer_cst 0x7ffff13310f0
> > 2147483647>
> >         pointer_to_this <pointer_type 0x7ffff1336a80>
> > reference_to_this <reference_type 0x7ffff144ca80>>
> > 
> >     arg:0 <var_decl 0x7ffff7ffbd80 v type <integer_type
> > 0x7ffff132e5e8 int>
> >         used public static tree_1 read SI /home/david/coding-3/gcc-
> > git-expr-vs-
> > decl/src/gcc/testsuite/g++.dg/conversion/reinterpret1.C:5:5 size
> > <integer_cst 0x7ffff1331120 32> unit-size <integer_cst
> > 0x7ffff1331138 4>
> >         align:32 warn_if_not_align:0 context <translation_unit_decl
> > 0x7ffff131e168 /home/david/coding-3/gcc-git-expr-vs-
> > decl/src/gcc/testsuite/g++.dg/conversion/reinterpret1.C>
> >         chain <type_decl 0x7ffff141a720 Y type <record_type
> > 0x7ffff144c150 Y>
> >             public decl_2 VOID /home/david/coding-3/gcc-git-expr-
> > vs-decl/src/gcc/testsuite/g++.dg/conversion/reinterpret1.C:3:8
> >             align:8 warn_if_not_align:0 context
> > <translation_unit_decl 0x7ffff131e168 /home/david/coding-3/gcc-git-
> > expr-vs-decl/src/gcc/testsuite/g++.dg/conversion/reinterpret1.C>
> > chain <function_decl 0x7ffff144f800 __cxa_call_unexpected>>>
> >     /home/david/coding-3/gcc-git-expr-vs-
> > decl/src/gcc/testsuite/g++.dg/conversion/reinterpret1.C:6:6 start:
> > /home/david/coding-3/gcc-git-expr-vs-
> > decl/src/gcc/testsuite/g++.dg/conversion/reinterpret1.C:6:6 finish:
> > /home/david/coding-3/gcc-git-expr-vs-
> > decl/src/gcc/testsuite/g++.dg/conversion/reinterpret1.C:6:29>
> > 
> > The problem is that this reinterpret cast "looks" just like one of
> > my
> > location wrappers.
> 
> Your code shouldn't strip a NON_LVALUE_EXPR around a VAR_DECL.

> > I see a similar issue with constants, where with:
> > 
> >   struct Y { Y(int &); };
> >   Y y1(reinterpret_cast<int>(42));
> > 
> > trunk generates an error like the above, but my code handles the
> >   NON_LVALUE_EXPR<int>(INTEGER_CST<int>(42))
> > as if it were a location wrapper around the INTEGER_CST, and thus
> > doesn't emit the error.
> 
> Why doesn't it emit the error?  We should get the same error whether
> or not we strip the wrapper.

Thanks: my stripping macro was over-zealous: it was stripping any
NON_LVALUE_EXPR or VIEW_CONVERT_EXPR where the type matched that of
the wrapped node.  I've added the additional condition that a
NON_LVALUE_EXPR has to be around a CONSTANT_CLASS_P, and
a VIEW_CONVERT_EXPR around a !CONSTANT_CLASS_P.

Here's an updated version of the patch (v2), now a patch kit (on top
of r254387).  I split it up thematically for ease of review, but all
the patches go together.

This version of the patch kit bootstraps and passes the regression
tests (on x86_64-pc-linux-gnu)

To do so, I've made some simplfications to how wrappers nodes are
added.

The previous patch added wrappers in the C++ parser around constants
and uses-of-declarations, along with some other places in the
parser (typeid, alignof, sizeof, offsetof).

This version takes a much more minimal approach: it only adds
location wrapper nodes around the arguments at callsites, thus
not adding wrapper nodes around uses of constants and decls in other
locations.

It keeps them for the other places in the parser (typeid, alignof,
sizeof, offsetof).

In addition, for now, each site that adds wrapper nodes is guarded
with !processing_template_decl, suppressing the creation of wrapper
nodes when processing template declarations.  This is to simplify
the patch kit so that we don't have to support wrapper nodes during
template expansion.

With this, we get a big usability win: we always have a location_t
for every argument at a callsite, and so various errors involving
mismatching arguments are much easier to read (as the pertinent
argument is underlined).

I marked this as "PR 43486" as it's a big step towards solving that
PR (which seeks to preserve locations all the way through to the
middle end), but much more would need to be done to solve it:

* this patch kit only adds wrappers to the C++ frontend, not to C

* as noted above, location_t wrapper nodes are only added at
  arguments of callsites (and a few other places), with some
  restrictions.

* none of the wrapper nodes survive past gimplification;
  it's not clear to me how best to preserve them into the
  middle-end.  But even without doing so, we get the big usability
  win.

The later parts of the patch kit add STRIP_ANY_LOCATION_WRAPPER uses
in various places where the tree code of an expression is examined,
so that such conditions use the code of the wrapped node, rather
than that of the wrapper.  One of the risks of the patch kit is that
although the testsuite passes, there are probably places in our code
which still need uses of STRIP_ANY_LOCATION_WRAPPER.


Performance of the patch kit
****************************

Benchmarking shows an apparent 2-3% in cc1plus wallclock compile-time
for kdecore.cc -O3 -g:

Compilation of kdecore.cc at -O3 with -g for x86_64-pc-linux-gnu: wall
      control: [56.55, 56.54, 56.68, 56.51, 56.45, 56.5, 56.45, 56.46, 56.49, 
56.5, 56.42, 56.37, 56.41, 56.55]
   experiment: [57.32, 58.37, 58.17, 58.18, 58.78, 58.48, 57.99, 58.16, 58.14, 
57.62, 58.36, 58.1, 57.71, 57.7]
Min: 56.370000 -> 57.320000: 1.02x slower
Avg: 56.491429 -> 58.077143: 1.03x slower
Significant (t=-15.14)
Stddev: 0.07655 -> 0.38426: 5.0199x larger

although I'm not quite sure why; the difference is in "phase setup", which
gains a large "wall" value (but not in usr or sys), whereas "phase parsing"
is unaffected:

unpatched:

 phase setup             :   0.00 ( 0%) usr   0.02 ( 0%) sys   0.02 ( 0%) wall  
  1488 kB ( 0%) ggc
 phase parsing           :   1.83 ( 4%) usr   0.82 (16%) sys   2.66 ( 5%) wall  
156603 kB (12%) ggc
 phase lang. deferred    :   0.30 ( 1%) usr   0.09 ( 2%) sys   0.38 ( 1%) wall  
 29861 kB ( 2%) ggc
 phase opt and generate  :  48.09 (94%) usr   4.28 (81%) sys  52.55 (93%) wall 
1085420 kB (84%) ggc
 phase last asm          :   0.86 ( 2%) usr   0.05 ( 1%) sys   0.92 ( 2%) wall  
 15806 kB ( 1%) ggc
 phase finalize          :   0.00 ( 0%) usr   0.01 ( 0%) sys   0.01 ( 0%) wall  
     0 kB ( 0%) ggc
 |name lookup            :   0.30 ( 1%) usr   0.13 ( 2%) sys   0.21 ( 0%) wall  
  4955 kB ( 0%) ggc
 |overload resolution    :   0.49 ( 1%) usr   0.06 ( 1%) sys   0.68 ( 1%) wall  
 27263 kB ( 2%) ggc
 garbage collection      :   0.77 ( 2%) usr   0.00 ( 0%) sys   0.77 ( 1%) wall  
     0 kB ( 0%) ggc
 [...]
 TOTAL                 :  51.08             5.27            56.54            
1289189 kB

patched:
 phase setup             :   0.01 ( 0%) usr   0.03 ( 1%) sys   1.91 ( 3%) wall  
  1488 kB ( 0%) ggc
 phase parsing           :   1.80 ( 4%) usr   0.84 (16%) sys   2.66 ( 5%) wall  
158066 kB (12%) ggc
 phase lang. deferred    :   0.29 ( 1%) usr   0.09 ( 2%) sys   0.39 ( 1%) wall  
 29861 kB ( 2%) ggc
 phase opt and generate  :  48.09 (94%) usr   4.27 (81%) sys  52.52 (90%) wall 
1085428 kB (84%) ggc
 phase last asm          :   0.82 ( 2%) usr   0.05 ( 1%) sys   0.89 ( 2%) wall  
 15806 kB ( 1%) ggc
 phase finalize          :   0.00 ( 0%) usr   0.01 ( 0%) sys   0.00 ( 0%) wall  
     0 kB ( 0%) ggc
 |name lookup            :   0.29 ( 1%) usr   0.07 ( 1%) sys   0.36 ( 1%) wall  
  4955 kB ( 0%) ggc
 |overload resolution    :   0.51 ( 1%) usr   0.07 ( 1%) sys   0.50 ( 1%) wall  
 27296 kB ( 2%) ggc
 garbage collection      :   0.79 ( 2%) usr   0.00 ( 0%) sys   0.78 ( 1%) wall  
     0 kB ( 0%) ggc
 TOTAL                 :  51.01             5.29            58.37            
1290660 kB

What's up with that "phase setup" change?  Did I mess up my testing
somehow?


...and a slight increase in GGC usage:

Compilation of kdecore.cc at -O3 with -g for x86_64-pc-linux-gnu: ggc
      control: [1289179.0, 1289189.0, 1289170.0, 1289186.0, 1289194.0, 
1289172.0, 1289176.0, 1289192.0, 1289189.0, 1289179.0, 1289172.0, 1289190.0, 
1289169.0, 1289185.0]
   experiment: [1290654.0, 1290660.0, 1290655.0, 1290659.0, 1290631.0, 
1290655.0, 1290650.0, 1290652.0, 1290642.0, 1290650.0, 1290658.0, 1290662.0, 
1290638.0, 1290655.0]
Mem max: 1289194.000 -> 1290662.000: 1.0011x larger

(this is with stripped binaries, and --enable-checking=release)

Testing with a simple file that includes all of the C++ standard library
(but doesn't do anything with it) shows no change in time, and GGC usage
in the parsing phase increasing 50kB from 149954 kB to 150004 kB.


Next steps?
***********

I'm working on extending the patch kit to add wrapper nodes at all
constants and uses-of-decls in the C++ parser, but of course this
could have some effect on time/memory, and require more uses of
STRIP_ANY_LOCATION_WRAPPER.

An alternative appoach is:

  "[PATCH] C++: use an optional vec<location_t> for callsites"
    https://gcc.gnu.org/ml/gcc-patches/2017-08/msg01392.html

which eschews wrapper nodes in favor of duplicating the C frontend's
workaround here (though Jason disliked this approach, when we discussed
it at Cauldron).

Thoughts?

(I'm keen on getting *some* solution for providing location_t values
for arguments at C++ callsites into gcc 8)


David Malcolm (14):
  C++: preserve locations within build_address
  Support for adding and stripping location_t wrapper nodes
  C++: add location_t wrapper nodes during parsing (minimal impl)
  Update testsuite to show improvements
  tree.c: strip location wrappers from integer_zerop etc
  Fix Wsizeof-pointer-memaccess*.c
  reject_gcc_builtin: strip any location wrappers
  cp/tree.c: strip location wrappers in lvalue_kind
  Strip location wrappers in null_ptr_cst_p
  warn_for_memset: handle location wrappers
  Handle location wrappers in string_conv_p
  C++: introduce null_node_p
  c-format.c: handle location wrappers
  pp_c_cast_expression: don't print casts for location wrappers

 gcc/c-family/c-common.c                            |   3 +
 gcc/c-family/c-common.h                            |   1 +
 gcc/c-family/c-format.c                            |   9 +-
 gcc/c-family/c-pretty-print.c                      |  66 +++++-
 gcc/c-family/c-warn.c                              |   8 +
 gcc/cp/call.c                                      |   6 +-
 gcc/cp/cp-tree.h                                   |  13 ++
 gcc/cp/cvt.c                                       |   2 +-
 gcc/cp/error.c                                     |   2 +-
 gcc/cp/except.c                                    |   2 +-
 gcc/cp/parser.c                                    |  30 ++-
 gcc/cp/tree.c                                      |   2 +
 gcc/cp/typeck.c                                    |   6 +-
 .../g++.dg/diagnostic/param-type-mismatch.C        |  27 +--
 .../g++.dg/plugin/diagnostic-test-expressions-1.C  | 260 +++++++++++++--------
 gcc/tree.c                                         |  59 +++++
 gcc/tree.h                                         |  26 +++
 17 files changed, 392 insertions(+), 130 deletions(-)

-- 
1.8.5.3

Reply via email to