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

John McCall via cfe-dev cfe-dev at lists.llvm.org
Wed Jul 29 12:52:48 PDT 2020


Clang IRGen currently doesn’t mark indirect parameters as `noalias`.  
Considerations:

- A lot of targets don’t pass struct arguments indirectly outside of 
C++, but some do, notably AArch64.

- In a pure C world, we would always be able to mark such parameters 
`noalias`, because arguments are r-values and there’s no way to have a 
pointer to an r-value.

- ObjC `__weak` references can have pointers to them from the ObjC 
runtime.  You can’t pass a weak reference immediately as an argument 
because `__weak` is a qualifier and qualifiers are ignored in calls, but 
you can put one in a struct and pass that, and that struct has to be 
passed indirectly.  Arguably such a parameter cannot be `noalias` 
because of the pointer from the runtime, but then again, ObjC code 
isn’t allowed to directly access the weak reference (it has to call 
the runtime), which means that no accesses that LLVM can actually see 
violate the `noalias` restriction.

- C++ parameters of non-trivially-copyable class type cannot be marked 
`noalias`: it is absolutely permitted to escape a pointer to `this` 
within a constructor and to replace that pointer whenever the object is 
moved.  This is both well-defined and sometimes useful.

- It’s actually possible to escape a pointer to *any* C++ object 
within its constructor, and that pointer remains valid for the duration 
of the object’s lifetime.  And you can do this with NRVO, too, so you 
don’t even need to have a type with non-trivial constructors, as long 
as the object isn’t copied.  Note that this even messes up the C case, 
which is really unfortunate: arguably we need to pessimize C code 
because of the possibility it might interoperate with C++.

- But I think there’s an escape hatch here.  C++ has a rule which is 
intended to give implementation extra leeway with passing and returning 
trivial types, e.g. to pass them in registers.  This rule is C++ 
[class.temporary]p3, which says that implementations can create an extra 
temporary object to pass an object of type `X` as long as “each copy 
constructor, move constructor, and destructor of X is either trivial or 
deleted, and X has at least one non-deleted copy or move constructor”. 
  This object is created by (trivially) copy/move-initializing from the 
argument/return object.  Arguably we can consider any type that 
satisfies this condition to be *formally* copied into a new object as 
part of passing or returning it.  We don’t need to *actually* do the 
copy, I think, we just need to consider a copy to have been done in 
order to formally disrupt any existing pointers to the object.  
(Although arguably you aren’t allowed to copy an object into a new 
object at the original object’s current address; it would be an 
unfortunate consequence of this wording if we had to either forgo 
optimization or do an unnecessary copy here.)

Thoughts?

John.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20200729/eb53f7df/attachment.html>


More information about the cfe-dev mailing list