[cfe-dev] Can indirect class parameters be noalias?

Hal Finkel via cfe-dev cfe-dev at lists.llvm.org
Fri Jul 31 11:24:45 PDT 2020


On 7/31/20 12:43 PM, John McCall wrote:
>
> n 31 Jul 2020, at 7:35, Hal Finkel wrote:
>
>     On 7/29/20 9:00 PM, John McCall via cfe-dev wrote:
>
>         On 29 Jul 2020, at 17:42, Richard Smith wrote:
>
>         On Wed, 29 Jul 2020 at 12:52, John McCall <rjmccall at apple.com>
>         wrote:
>
>         ...
>
>         I think concretely, the escape hatch doesn't stop things from
>         going wrong,
>         because -- as you note -- even though we *could* have made a copy,
>         it's
>         observable whether or not we *did* make a copy. For example:
>
>         I would say that it’s observable whether the parameter
>         variable has
>         the same address as the argument. That doesn’t /have/ to be
>         the same
>         question as whether a copy was performed: we could consider
>         there to be
>         a formal copy (or series of copies) that ultimately creates
>         /an/ object
>         at the same address, but it’s not the /same/ object and so
>         pointers
>         to the old object no longer validly pointer to it. But I guess
>         that
>         would probably violate the lifetime rules, because it would
>         make accesses
>         through old pointers UB when in fact they should at worst
>         access a valid
>         object that’s just unrelated to the parameter object.
>
>     I think that it would be great to be able to do this, but
>     unfortunately, I think that the point that you raise here is a key
>     issue. Whether or not the copy is performed is visible in the
>     model, and so we can't simply act as though there was a copy when
>     optimizing. Someone could easily have code that looks like:
>
>     Foo DefaultX;
>
>     ...
>
>     void something(Foo &A, Foo &B) {
>
>       if (&A == &B) { ... }
>
>     }
>
>     void bar(Foo X) { something(X, DefaultX); }
>
> This example isn’t really on point; a call like |bar(DefaultX)| 
> obviously cannot just pass the address of |DefaultX| as a by-value 
> argument without first proving a lot of stuff about how |foo| uses 
> both its parameter and |DefaultX|. I think |noalias| is actually a 
> subset of what would have to be proven there.
>

Yes, I apologize. You're right: my pseudo-code missed the point. So the 
record is clear, let me rephrase:

Foo *DefaultX = nullptr;
...
Foo::Foo() { if (!DefaultX) DefaultX = this; }
...
void bar(Foo X) { something(X, *DefaultX); }
...
bar(Foo{});

I think that's closer to what we're talking about.


> In general, the standard is clear that you cannot rely on escaping a 
> pointer to/into a trivially-copyable pr-value argument prior to the 
> call and then rely on that pointer pointing into the corresponding 
> parameter object. Implementations are /allowed/ to introduce copies. 
> But it does seem like the current wording would allow you to rely on 
> that pointer pointing into /some/ valid object, at least until the end 
> of the caller’s full-expression. That means that, if we don’t 
> guarantee to do an actual copy of the argument, we cannot make it UB 
> to access the parameter variable through pointers to the argument 
> temporary, which is what marking the parameter as |noalias| would do.
>
> So I guess the remaining questions are:
>
>   * Is this something we can reasonably change in the standard?
>

This is the part that I'm unclear about. What change would we make?



>   * Are we comfortable setting |noalias| in C if the only place that
>     would break is with a C++ caller?
>

Out of curiosity, if you take C in combination with our 
statement-expression extension implementation 
(https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html), and 
notwithstanding the statement in the GCC manual about returns by value 
(i.e., the part just before where it says, "Therefore the this pointer 
observed by Foo is not the address of a."), is there any relationship to 
this topic?

Thanks again,

Hal


> John.
>
>     As Richard's example shows, the code doesn't need to explicitly
>     compare the addresses to detect the copy either. Any code that
>     reads/writes to the objects can do it. A perhaps-more-realistic
>     example might be:
>
>       int Cnt = A.RefCnt; ++A.RefCnt; ++B.RefCnt; if (Cnt + 1 !=
>     A.RefCnt) { /* same object case */ }
>
>     The best suggestion that I have so far is that we could add an
>     attribute like 'can_copy' indicating that the optimizer can make a
>     formal copy of the argument in the callee and use that instead of
>     the original pointer if that seems useful. I can certainly imagine
>     a transformation such as LICM making use of such a thing (although
>     the cost modeling would probably need to be fairly conservative).
>
>      -Hal
>
>         ...
>
>         John.
>
>
>         _______________________________________________
>         cfe-dev mailing list
>         cfe-dev at lists.llvm.org
>         https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
>         <https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev>
>
>     -- 
>     Hal Finkel
>     Lead, Compiler Technology and Programming Languages
>     Leadership Computing Facility
>     Argonne National Laboratory
>
-- 
Hal Finkel
Lead, Compiler Technology and Programming Languages
Leadership Computing Facility
Argonne National Laboratory

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20200731/803c64a6/attachment.html>


More information about the cfe-dev mailing list