New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[SR-12845] Pointers to values of address-only types should not be always marked nocapture (and maybe noalias) #55291
Comments
In general, we assume that memory access within the Swift runtime is not visible to LLVM when compiling Swift code. Maybe we'd like it to be visible, but that requires a lot of work plumbing Swift types through LLVM, maybe using TBAA. Also, I think we want to make assumptions about Swift types that don't apply to C++ types, so we better have a way for IRGen to tell them apart. Is it possible for a Swift struct to contain a C++ class without the type system knowing? Can we force Swift structs to opt-in to this feature via conformance? Or do we need to assume the worst about every Swift struct that doesn't have a fixed layout? |
Thanks for taking a look, Andy! So judging from your response I think you agree that we have a bug at least for C++ types – could you confirm?
If there is a resilience or generics boundary, the type system might know that it can't know. If a module exposes a resilient struct, it might include a C++ class by value now or in future.
Since we're just talking about cases where there is an abstraction boundary (like resilience), I think it would be acceptable. For values of non-concrete types in generic functions these LLVM attributes probably don't matter for optimization (right?) since code does not directly access the pointed-to memory anyway. However, Swift's typical approach for library evolution is not to opt into flexibility, but to opt out of it – so it would be another attribute like |
That sounds reasonable to me, but I really haven't thought about C++ support. My biggest concern with hiding C++ types within Swift types would be if the C++ type is non-copyable. Maybe we simply ban that outright. @rjmccall has given this some thought. |
Noncopyable C++ types are a separate issue. There can be copyable C++ types that are address-only because they are non-trivially copyable, because, for example, they care about their memory location. for example, |
C++ things can certainly end up visible to LLVM. If we need to be more conservative about `noalias` and `nocapture` when passing types that we don't fully understand statically, that seems reasonable to me. For the most important such case — an opaque generic type, or at least a type containing one — It's highly unlikely that there would be any interesting LLVM-level optimizations that `nocapture` would enable anyway, since all property accesses on a generic type would be done via opaque accessors. |
@swift-ci create |
Additional Detail from JIRA
md5: e4f14f97860551c0ab6bdf0ea47d957c
Issue Description:
Based on my understanding, I don't think pointers to values of address-only types can be always marked
nocapture
(and maybenoalias
as well).Here's a Swift example with corresponding LLVM IR:
I think we can't mark an indirectly returned value of address-only type
Test
asnocapture
because the address of the weak reference is registered in the side table. I thinknoalias
is wrong for the same reason.One could argue that maybe it is kinda-OK in the case of Swift address-only types that contain weak references because all manipulations of the side table are hidden from LLVM in the runtime, which is compiled separately. However, C++ address-only types can violate the expectations of
nocapture
andnoalias
in inline functions that are visible to LLVM, possibly leading to miscompiles.Compare with Clang's code generation. Return values in C++:
Parameters in C++:
The text was updated successfully, but these errors were encountered: