Skip to content

[SILOpt] Hoist destroys for non-lexical alloc_stacks more aggressively. #60478

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

Previously, when hoisting destroy_addrs for alloc_stacks, deinit barriers were always considered barriers to hoisting. Here, that is changed so that hoisting only is barred when the alloc_stack whose destroy_addr is being hoisted is lexical.

Additionally, more non-lexical alloc_stacks are formed: only alloc_boxes whose lifetimes are protected via a lexical borrow scope get promoted to lexical alloc_stacks. This will become more significant when types and values are annotated @_eagerMove.

In order to do this safely, we must ensure that implicit lexical lifetimes are not removed. Address function arguments with a convention other than Indirect_Inout have implicit lexical lifetimes: e.g. SSADestroyHoisting respects deinit barriers when hoisting the the destroy_addrs of such arguments. Until we have begin_borrow_addr/end_borrow_addr, when inlining functions with such arguments, if the address passed to it has an alloc_stack as its storage base, mark that alloc_stack lexical.

@nate-chandler
Copy link
Contributor Author

@swift-ci please benchmark

@nate-chandler
Copy link
Contributor Author

@swift-ci please smoke test macOS platform

@nate-chandler nate-chandler requested a review from atrick August 10, 2022 00:25
@nate-chandler nate-chandler force-pushed the lexical_lifetimes/optimize_more_alloc_stack_destroys branch from d696bb4 to ad6f47c Compare August 10, 2022 21:46
@nate-chandler
Copy link
Contributor Author

@swift-ci please test

@nate-chandler
Copy link
Contributor Author

@swift-ci please benchmark

Copy link
Contributor

@atrick atrick left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! Thanks.

worklist.initializeRange(ABI->getUses());
while (auto *use = worklist.pop()) {
// See through mark_uninitialized instructions.
if (auto *mui = dyn_cast<MarkUninitializedInst>(use->getUser())) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hard-coding opcodes here (for mark_uninitialized) creates an implicit correctness dependency on SIL design. How will we find out if SILGen ever introduces new instructions in the same position as mark_uninitialized? Maybe we want a flag on alloc_box just at least as a verification mechanism?

Copy link
Contributor Author

@nate-chandler nate-chandler Aug 12, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added verification that begin_borrow [lexical]s whose operand's type is a SILBoxType is either an AllocBoxInst or a SILFunctionArgument (looking through copy_values, begin_borrows, and mark_uninitialized instructions) in 3df609f .

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AllocBoxToStack also now looks through to the uses of non-lexical begin_borrows to properly handle the case of repeated inlining where the first callee's SILFunctionArgument is non-lexical but the second callee's SILFunctionArgument is lexical in 896a464 .

@nate-chandler nate-chandler force-pushed the lexical_lifetimes/optimize_more_alloc_stack_destroys branch from ad6f47c to fdb20e1 Compare August 12, 2022 18:26
Previously, whenever an alloc_box that was promoted to an alloc_stack,
the new alloc_stack would be lexical.  The result was that alloc_boxes
which didn't need (or explicitly didn't want, in the case of eager move
vars) received lexical alloc_stacks.

Here, only add the lexical flag to the new alloc_stack instruction if
any of the box's uses are `begin_borrow [lexical]`.  That way,
alloc_boxes end up having lexical alloc_stacks only if they were
"lexical alloc_boxes".
When inlining a function to which an alloc_stack is passed (via any
convention that's not all of mutating, exclusive, and inout), mark the
alloc_stack as lexical.  Otherwise, destroy_addrs could be hoisted
through the inlined function in a way inconsistent with how they were
hoisted through the callee prior to inlining.
Previously, whenever an alloc_stack [lexical] was seen, optimization
bailed conservatively.

In the fullness of time, we should optimize an alloc_stack [lexical] so
long as:
(1) the root of the source of the store/copy_addr is lexical
(2) the range in which the alloc_stack [lexical] contains the value
    store'd/copy_addr'd into it (i.e. the range ending at
    destroy_addr/etc) is contained within the live range of that lexical
    root

Here, an incremental step in that direction is taken: if the base of the
accessed storage of the source of a copy_addr is a guaranteed function
argument, then we know
(1) the base is lexical--guaranteed function arguments are always
    lexical
(2) the range in which the alloc_stack contains the value copy_addr'd in
    is trivially contained within the range of that lexical root--the
    live range of a guaranteed function argument is the whole function

Added TODOs for the full optimization.
Require that lexical borrows of values which are instances of some
SILBoxType guard the lifetime of vars or closure captures; that's to
say, of AllocBoxInsts and SILFunctionArguments.

Look through a few instructions types to find those:
- copy_value - inserted by SILGen
- begin_borrow - inserted during inlining
- mark_uninitialized - inserted by SILGen
@nate-chandler nate-chandler force-pushed the lexical_lifetimes/optimize_more_alloc_stack_destroys branch from fdb20e1 to 3df609f Compare August 12, 2022 18:37
@nate-chandler
Copy link
Contributor Author

@swift-ci please test

@nate-chandler
Copy link
Contributor Author

@swift-ci please test source compatibility

@nate-chandler nate-chandler merged commit feecc51 into swiftlang:main Aug 15, 2022
@nate-chandler nate-chandler deleted the lexical_lifetimes/optimize_more_alloc_stack_destroys branch August 15, 2022 17:36
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