Skip to content

6.2: [DestroyAddrHoisting] Skip init_enum_data_addrs. #81959

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

Conversation

nate-chandler
Copy link
Contributor

@nate-chandler nate-chandler commented Jun 3, 2025

Explanation: Fix a miscompile introduced by DestroyAddrHoisting.

The pass rewrites destroy_addrs, deleting the original instructions and inserting new ones at locations it determines via backwards dataflow. The pass does not process destroys of subobjects. When hoisting destroys for an aggregate, if a destroy_addr of some field is encountered, the pass bails out.

Previously, though, it was inadvertently processing destroys of init_enum_data_addrs. The result was to delete the original destroy_addr(init_enum_data_addr(%mem)) and to insert a destroy_addr(%mem) at the new location. This transformation is incorrect in general; specifically, it is incorrect whenever the init_enum_data_addr is not followed by an inject_enum_addr before the destroy_addr(%mem). In order to destroy the whole enum, it must be known which case the enum is in, data which is provided by the inject_enum_addr instruction; so if that instruction does not appear between the init_enum_data_addr and the destroy_addr(%mem), the emitted code (which checks the enum case in order to determine how to destroy the enum) cannot behave correctly.

This was happening because the utility it relies on views init_enum_data_addrs as referring to the same memory as the enum out of which that instruction was projecting. This is accurate for many uses, but fails to account for the data provided by the inject_enum_addr.

Here, this is fixed by making the optimization bail out when seeing a destroy_addr(...(init_enum_data_addr())). This matches the behavior of the optimization when it is run on aggregates. For example, the optimization bails out when seeing destroy_addr %single_field where %single_field = struct_element_addr %singleton_struct, the destroy_addr of the single field projected out of a struct which consists of only that field.
Scope: Affects optimized code.
Issue: rdar://152431332
Original PR: #81952
Risk: Low, this adds a bailout to an optimization. Specifically, it makes bailing out of enums match the bailing out of structs and tuples.
Testing: Added test.
Reviewer: Meghana Gupta ( @meg-gupta ), Andrew Trick ( @atrick )

moveonlywrapper_to_copyable_box changes the type so it's a type cast not
an identity cast.
The new function stripAccessAndAccessStorageCasts is analogous to the
existing function stripAccessAndIdentityCasts but differs in that the
latter uses isAccessStorageIdentityCast whereas the new function uses
isAccessStorageCast.
A destroy of an `init_enum_data_addr` is not equivalent to a destroy of
the whole enum's address.  Treat such destroys just like destroys of
`struct_element_addr`s are treated: by bailing out.

rdar://152431332
@nate-chandler
Copy link
Contributor Author

@swift-ci please test

@nate-chandler nate-chandler marked this pull request as ready for review June 4, 2025 02:40
@nate-chandler nate-chandler requested a review from a team as a code owner June 4, 2025 02:40
@nate-chandler nate-chandler enabled auto-merge June 4, 2025 02:40
@nate-chandler nate-chandler merged commit 4225fbc into swiftlang:release/6.2 Jun 4, 2025
5 checks passed
@nate-chandler nate-chandler deleted the cherrypick/release/6.2/rdar152431332 branch June 4, 2025 17:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants