On Fri, Aug 09, 2024 at 12:58:34PM -0400, Jason Merrill wrote:
> On 8/8/24 1:37 PM, Marek Polacek wrote:
> > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
> > 
> > -- >8 --
> > The problem in this PR is that we ended up with
> > 
> >    {.rows=(&<PLACEHOLDER_EXPR struct Widget>)->n,
> >     .outer_stride=(&<PLACEHOLDER_EXPR struct MatrixLayout>)->rows}
> > 
> > that is, two PLACEHOLDER_EXPRs for different types on the same level
> > in one { }.  That should not happen; we may, for instance, neglect to
> > replace a PLACEHOLDER_EXPR due to CONSTRUCTOR_PLACEHOLDER_BOUNDARY on
> > the constructor.
> > 
> > The same problem happened in PR100252, which I fixed by introducing
> > replace_placeholders_for_class_temp_r.  That didn't work here, though,
> > because r_p_for_c_t_r only works for non-eliding TARGET_EXPRs: replacing
> > a PLACEHOLDER_EXPR with a temporary that is going to be elided will
> > result in a crash in gimplify_var_or_parm_decl when it encounters such
> > a loose decl.
> > 
> > But leaving the PLACEHOLDER_EXPRs in is also bad because then we end
> > up with this PR.
> > 
> > TARGET_EXPRs for function arguments are elided in gimplify_arg.  The
> > argument will get a real temporary only in get_formal_tmp_var.  One
> > idea was to use the temporary that is going to be elided anyway, and
> > then replace_decl it with the real object once we get it.  But that
> > didn't work out: one problem is that we elide the TARGET_EXPR for an
> > argument before we create the real temporary for the argument, and
> > when we get it, the context that this was a TARGET_EXPR for an argument
> > has been lost.  We're also in the middle end territory now, even though
> > this is a C++-specific problem.
> 
> How complex!
> 
> > I figured that since the to-be-elided temporary is going to stay around
> > until gimplification, the front end is free to use it.  Once we're done
> > with things like store_init_value, which replaces PLACEHOLDER_EXPRs with
> > the decl it is initializing, we can turn those to-be-elided temporaries
> > into PLACEHOLDER_EXPRs again, so that cp_gimplify_init_expr can replace
> > them with the real object once available.  The context is not lost so we
> > do not need an extra flag for these makeshift temporaries.
> 
> Clever, that makes a lot of sense.  But I wonder if we can avoid the problem
> more simply than working around it?
> 
> I see that the get_formal_tmp_var happens directly from gimplify_arg, so it
> strips the TARGET_EXPR to avoid a temporary...and then immediately turns
> around and creates a new temporary.
> 
> Would it work to stop stripping the TARGET_EXPR in gimplify_arg and
> therefore stop setting TARGET_EXPR_ELIDING_P in convert_for_arg_passing?

Well, it does fix the ICE.  But then a number of testcases fail :(.
For instance, pr23372.C.  .gimple diff w/ and w/o stripping the TARGET_EXPR:

@@ -1,6 +1,9 @@
 void g (struct A * a)
 {
-  f (MEM[(const struct A &)a]);
+  struct A D.2829;
+
+  D.2829 = MEM[(const struct A &)a];
+  f (D.2829);
 }

The extra copy is there even in .optimized with -O2.


It's always sad when we have to add complicated code just to work around
a corner case, but the above pessimization looks pretty important :(.

Marek

Reply via email to