Skip to content
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

[release/6.0] [mono] Use SROA-friendly struct type declarations #59060

Merged

Conversation

imhameed
Copy link
Contributor

Backport of #59007 to release/6.0

Customer Impact

Programs compiled using Mono LLVM can intermittently crash in the GC when copying value types that contain managed references. We previously generated type declarations of the form %"type.name.here" = type { i8, i8, i8, ... }, which can cause SROA to load and store managed references using a non-atomic sequence of single-byte loads and stores.

Testing

CI, with both the llvmaot and llvmfullaot lanes on x64 and arm64. Additionally hand-verified that the generated code satisfies sgen's requirements.

Risk

Minor. We only depend on the size and alignment of LLVM struct types and not their contents. The only exception to this happens when LLVM's SROA pass unrolls bulk copies.

LLVM's SROA can decompose loads and stores of aggregate type into a
sequence of aggregate-element-typed loads and stores. Before this
change, Mono translates .NET-level value types into LLVM IR-level
structs containing nothing but `i8` elements.

When a value type field has reference type, and a value of this value
type is copied using a `memcpy` intrinsic or an LLVM IR load followed by
a store, LLVM will emit code that loads managed references in multiple
byte-sized fragments before reconstructing the original pointer using a
sequence of ALU ops. This causes sgen to fail to pin the referent.

This change works around this by translating value types to LLVM IR
structs with pointer-sized fields. Packed value types with non-standard
alignment will be translated into LLVM IR structs containing
alignment-sized fields.

Note that this does not completely guarantee that the code we generate
will respect sgen's requirements. No specific guarantees are provided
about the translation of non-atomic LLVM IR loads and stores to machine
code. And we'll need some alternative means (perhaps a special
`gc_copy_unaligned` runtime call or similar) to copy packed or
misaligned value types that contain managed references. For stronger
LLVM IR-level guarantees, we'll want to make use of unordered atomic
loads and stores and unordered atomic memcpy, but that work is out of
scope for this change.

See:
- https://github.com/dotnet/llvm-project/blob/release/11.x/llvm/lib/Transforms/Scalar/SROA.cpp#L3371-L3388
- https://github.com/dotnet/llvm-project/blob/release/11.x/llvm/lib/Transforms/Scalar/SROA.cpp#L3327-L3340
@imhameed
Copy link
Contributor Author

@marek-safar this will need your approval to be included in RC2. The original PR has already been approved, and is only waiting on the "ubuntu.1804.armarch.open" Helix pool to start processing jobs again.

@marek-safar marek-safar added this to the 6.0.0 milestone Sep 14, 2021
@marek-safar marek-safar merged commit 8abe506 into dotnet:release/6.0 Sep 15, 2021
@ghost ghost locked as resolved and limited conversation to collaborators Nov 3, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants