Commit Graph

80 Commits

Author SHA1 Message Date
Andrew Trick
f46d79149d ClosureLifetimeFixup review feedback 2023-08-10 18:51:48 -07:00
Andrew Trick
9c24933bd4 Fix compiler crashes with consuming and borrowing keywords.
Without this fix, the new 'consuming' and 'borrowing' keywords cannot
be used with trivial types. Which means, for example, they can't be
used in macro expansions that work on various types.

Fixes patterns like:

public func test1(i: consuming Int) -> Int {
  takeClosure { [i = copy i] in i }
}

public func test2(i: borrowing Int) -> Int {
  takeClosure { [i = copy i] in i }
}

public func test3(i: consuming Int) -> Int {
  takeClosure { i }
}

// Sadly, test4 is still incorrectly diagnosed.
public func test4(i: borrowing Int) -> Int {
  takeClosure { i }
}

Fixes rdar://112795074 (Crash compiling function that has a macro annotation and uses `consuming`)
2023-08-10 11:17:45 -07:00
Evan Wilde
f3ff561c6f [NFC] add llvm namespace to Optional and None
This is phase-1 of switching from llvm::Optional to std::optional in the
next rebranch. llvm::Optional was removed from upstream LLVM, so we need
to migrate off rather soon. On Darwin, std::optional, and llvm::Optional
have the same layout, so we don't need to be as concerned about ABI
beyond the name mangling. `llvm::Optional` is only returned from one
function in
```
getStandardTypeSubst(StringRef TypeName,
                     bool allowConcurrencyManglings);
```
It's the return value, so it should not impact the mangling of the
function, and the layout is the same as `std::optional`, so it should be
mostly okay. This function doesn't appear to have users, and the ABI was
already broken 2 years ago for concurrency and no one seemed to notice
so this should be "okay".

I'm doing the migration incrementally so that folks working on main can
cherry-pick back to the release/5.9 branch. Once 5.9 is done and locked
away, then we can go through and finish the replacement. Since `None`
and `Optional` show up in contexts where they are not `llvm::None` and
`llvm::Optional`, I'm preparing the work now by going through and
removing the namespace unwrapping and making the `llvm` namespace
explicit. This should make it fairly mechanical to go through and
replace llvm::Optional with std::optional, and llvm::None with
std::nullopt. It's also a change that can be brought onto the
release/5.9 with minimal impact. This should be an NFC change.
2023-06-27 09:03:52 -07:00
Joe Groff
ed2cbca04f ClosureLifetimeFixup: Remove copy of borrowed move-only nonescaping captures when possible.
SILGen introduces a copy of the capture, because the semantics of escaping partial_apply's
requires the closure to take ownership of the parameters. We don't know when a closure is
strictly nonescaping or its final lifetime until ClosureLifetimeFixup runs, but that replaces
the consume of the copy with a borrow of the copy normally, hoping later passes fix it up.
We can't wait that long for move-only types, which can't be copied, so try to remove the
copy up front when the copy lives long enough and has no interfering uses other than the
partial_apply. rdar://110137169
2023-06-20 12:10:31 -07:00
Andrew Trick
280761f0d1 [move-only] Fix SILOptimizer code motion to preserve value deinits
Multiple code motion and ARC related passes were removing struct/enum
deinits.

Passes fixed include:
- SILCombine
- EarlyCodeMotion
- ReleaseHoisting
- *many* passes that rely on ARC analysis (RCIndentity)
2023-06-06 09:17:53 -07:00
Andrew Trick
f7d30d4f8b [move-only] Fix SILOptimizer expansion to preserve deinits.
Many basic SIL passes were silently deleting the struct deinit:
- SROA
- Mem2Reg
- RLE
- DSE
- FunctionSignatureOpts
- LowerAggregates

Fixes rdar://109849028 ([move-only] LowerAggregateInstrs eliminates struct deinitialization)
2023-06-06 09:17:53 -07:00
Erik Eckstein
dc3cb18029 Swift Optimizer: add the MandatoryPerformanceOptimizations pass
As a replacement for the old MandatoryGenericSpecializer

The pass it not enabled yet in the pass pipeline
2023-05-11 08:11:44 +02:00
Joe Groff
69e4b95fb8 SIL: Model noescape partial_applys with ownership in OSSA.
Although nonescaping closures are representationally trivial pointers to their
on-stack context, it is useful to model them as borrowing their captures, which
allows for checking correct use of move-only values across the closure, and
lets us model the lifetime dependence between a closure and its captures without
an ad-hoc web of `mark_dependence` instructions.

During ownership elimination, We eliminate copy/destroy_value instructions and
end the partial_apply's lifetime with an explicit dealloc_stack as before,
for compatibility with existing IRGen and non-OSSA aware passes.
2023-02-16 21:43:53 -08:00
Nate Chandler
9ad44a5056 [ClosureLifetimeFixup] Dealloc args on frontier.
Previously, the dealloc_stacks created for the alloc_stacks used to pass
@in_guaranteed arguments to on_stack closures were created after the
users of the closure.  When SILGen created these alloc_stacks in the
same block as the users, this happened to work.  Now that
AddressLowering creates such alloc_stacks elsewhere, this approach
results in invalid SIL.

Here, the dealloc_stacks are instead at the end of each block in the
dominance frontier of the alloc_stack.
2022-12-13 11:46:47 -08:00
Erik Eckstein
8ca0143279 Remove uses of std::iterator
It's deprecated in C++17
2022-11-14 09:35:40 +01:00
Nate Chandler
7ea336367d [NFC] Port isDeinitBarrier to Swift.
Added new C++-to-Swift callback for isDeinitBarrier.

And pass it CalleeAnalysis so it can depend on function effects.  For
now, the argument is ignored.  And, all callers just pass nullptr.

Promoted to API the mayAccessPointer component predicate of
isDeinitBarrier which needs to remain in C++.  That predicate will also
depends on function effects.  For that reason, it too is now passed a
BasicCalleeAnalysis and is moved into SILOptimizer.

Also, added more conservative versions of isDeinitBarrier and
maySynchronize which will never consider side-effects.
2022-10-18 21:23:22 -07:00
Meghana Gupta
b7c23edfe6 Fix SILCombine of partial_apply to correctly extend store_borrow when needed 2022-08-16 15:08:23 -07:00
Andrew Trick
b517cce16f Move InstructionDeleter into its own header.
Add file-level comments on the utility's purpose and intended API
usage.

Cleanup API comments.
2021-11-18 11:38:08 -08:00
Erik Eckstein
dc8d4821dc SILOptimizer: extract predictable access and dead alloc optimizations into stand-alone utility functions 2021-10-28 18:43:14 +02:00
Erik Eckstein
49351c4759 SILOptimizer: extract the peephole optimization for Builtin.canBeClass into a separate utility. 2021-10-28 18:43:14 +02:00
Andrew Trick
55e0523b95 Prepare replaceAllUses[AndErase]() API support for terminators
Setup the API for use with SimplifyCFG first, so the OSSA RAUW utility
can be redesigned around it. The functionality is disabled because it
won't be testable until that's all in place.
2021-10-13 10:57:15 -07:00
Nate Chandler
cac03a6e77 [SIL] Let addArgumentToBranch accept plural args.
Previously, the addArgumentToBranch only allowed one to add a single
additional argument to a branch.  It then verified the argument count.
That is a problem if multiple arguments have to be added to arrive at
the correct argument count.

Specifically, that was a problem when running Mem2Reg on a lexical
alloc_stack, where three new phi arguments are added.

Here, the function name is changed to addArgumentsToBranch (plural
arguments) and the function accepts a SmallVector<SILValue> rather than
a single SILValue, allowing one to add all the arguments that are
necessary in order to verify that the resulting number of arguments is
correct.
2021-09-27 20:29:45 -07:00
Meghana Gupta
6c74c0ff2b Merge pull request #39097 from meg-gupta/rlefix
Fix an edge case in OSSA RLE for loops
2021-08-31 14:15:11 -07:00
Meghana Gupta
5b3c687bf1 Fix an edge case in OSSA RLE for loops
In OSSA RLE for loops, in certain cases SSAUpdater will not create a new
SILPhiArgument to be used as the forwarding value. Based on dominator info
it may return the newly copied available value as the forwarding value.
This newly copied available value in the dominating predecessor
will have destroy values at leaking blocks.

Rename makeNewValueAvailable to makeValueAvailable and handle users so that only
additional required destroy_values are inserted.
2021-08-31 09:47:42 -07:00
Meghana Gupta
6bafc8498d Remove end_lifetime being considered as an end of scope marker (#38851)
OSSA rauw cleans up end of scope markers before rauw'ing.
This can lead to inadvertant deleting of end_lifetime, later
resulting in an ownership verifier error indicating a leak.

This PR stops treating end_lifetime scope ending like end_borrow/end_access.
2021-08-12 13:49:06 -07:00
Andrew Trick
8e4c27daaa BasicBlockCloner: support for updating DeadEndBlocks.
DeadEndBlocks is used by low-level OSSA utilities. It needs to be
valid whenever OSSA transformations is being done.
2021-07-17 18:31:25 -07:00
Andrew Trick
74e928b39e Add -enable-ossa-simplifycfg and -enable-ossa-jumpthread-simplifycfg
as temporary flags to gradually stage in OSSA tests.
2021-07-17 18:31:25 -07:00
Andrew Trick
d0443be70e Expose the InstructionDeleter's callbacks
so they don't need to be passed around on the side everywhere.
2021-07-01 20:36:02 -07:00
Andrew Trick
b734bb3a92 Expose hasOnlyEndOfScopeOrDestroyUses as a utility
for cross-file use.
2021-07-01 20:34:48 -07:00
Andrew Trick
0407a4e34a Add UpdatingInstructionIterator.
Track in-use iterators and update them both when instructions are
deleted and when they are added.

Safe iteration in the presence of arbitrary changes now looks like
this:

    for (SILInstruction *inst : deleter.updatingRange(&bb)) {
      modify(inst);
    }
2021-06-02 07:38:27 -07:00
Andrew Trick
4a8cb7a42b Move InstModCallbacks into its own header.
Required to break circular dependence when introducing
UpdatingInstructionIterator.

Also, this is a lot of detail that doesn't belong in the general
InstOptUtils APIs. It's not something people should ever reach for.
2021-06-02 07:38:27 -07:00
Andrew Trick
da6b136322 Update comments for code review. 2021-06-02 07:38:27 -07:00
Andrew Trick
dde6a370c3 InstructionDeleter rewrite
Clarify the API. Make it suitable for use everywhere in the
compiler. We should try to standardize on it and allow it to do the
OSSA fixup more often.

Add InstructionDeleter::updatingIterator() factory so we never
normally need to use InstModCallbacks.

Fix bugs in which notifyWillBeDeleted() was being called on invalid
SIL. The bugs are easily exposed just by removing copy_value side
effects, but that will be in the follow-up commit.

Call notifyWillBeDeleted() only when identifying new dead instructions
that the client may not know about. Give the client control over
force-deleting instructions. When doing its own lifetime fixups, the
client may force-delete a set of related instructions. Invoking
callbacks for these force-deleted instructions is wrong.

TODO: partial_apply support is only partial. I disabled the buggy
cases. This should be easy to fix but requires designing some
InstructionDeleter test cases.
2021-06-02 07:38:27 -07:00
Michael Gottesman
456dfc9708 [sil-optimizer] Add LLVM_ATTRIBUTE_UNUSED to InstModCallback::on* methods.
InstModCallback is a value type and as such the original callback struct is not
being modified. Instead, a new InstModCallback struct is returned that is the
old callback + assignment of the passed in callback to the appropriate
field. Thus it makes sense to put this attribute on these methods so that we get
a warning if one does not use the new returned callback (otherwise, why would
one call this method?!). More likely a bug.
2021-04-30 14:34:02 -07:00
Michael Gottesman
b6bfea1f39 [sil-optimizer] Get rid of the InstModCallback constructors in favor of onDelete/onCreatedNewInst/etc.
Without this when constructing an InstModCallback it is hard to distinguish
which closure is meant for which operation when passed to the constructor of
InstModCallback (if this was in Swift, we could use argument labels, but we do
not have such things in c++).

This new value type sort of formulation makes it unambiguous which callback is
used for what when constructing one of these.
2021-04-26 23:33:33 -07:00
Michael Gottesman
e5d0a489d4 [sil-optimizer] Add comments to InstModCallback that explains why we have both notifyWillBeDeletedFunc and deleteInstFunc. 2021-04-26 23:33:33 -07:00
Michael Gottesman
7b55cbc669 [sil-optimizer] Make InstructionDeleter and related APIs to use an InstModCallback instead of a notification callback.
I recently have been running into the issue that many of these APIs perform the
deletion operation themselves and notify the caller it is going to delete
instead of allowing the caller to specify how the instruction is deleted. This
causes interesting semantic issues (see the loop in deleteInstruction I
simplified) and breaks composition since many parts of the optimizer use
InstModCallbacks for this purpose.

To fix this, I added a notify will be deleted construct to InstModCallback. In a
similar way to the rest of it, if the notify is not set, we do not call any code
implying that we should have good predictable performance in loops since we will
always skip the function call.

I also changed InstModCallback::deleteInst() to notify before deleting so we
have a default safe behavior. All previous use sites of this API do not care
about being notified and the only new use sites of this API are in
InstructionDeleter that perform special notification behavior (it notifies for
certain sets of instructions it is going to delete before it deletes any of
them). To work around this, I added a bool to deleteInst to control this
behavior and defaulted to notifying. This should ensure that all other use sites
still compose correctly.
2021-04-26 16:37:43 -07:00
Michael Gottesman
71fd7f9cb2 Merge pull request #37003 from gottesmm/pr-af8aa6d23b297a3ff4a3237f2dfe6fec12673023
[ownership] Change CanonicalOSSALifetime to use an InstModCallback.
2021-04-22 07:11:52 -07:00
Michael Gottesman
c3c2b84e48 [ownership] Change CanonicalOSSALifetime to use an InstModCallback.
This enables passes to use this as a utility that properly composes with how the
pass maintains its state. If an InstModCallback isn't passed in, we use the
default InstModCallback which should be cheap (always succeeding check for
nullptr + call inline default callback).
2021-04-21 22:09:55 -07:00
Michael Gottesman
8f76815307 [inst-opt-utils] If InstModCallback::setUseValueFunc isn't set, just call RAUW directly rather than calling the default setUseValueFunc.
This guarantees that a default InstModCallback() call to RAUW doesn't have any
overhead.

Just a little optimization I saw.
2021-04-21 21:20:43 -07:00
swift-ci
44ed14e646 Merge pull request #36138 from atrick/comment-deleteinst 2021-02-24 14:25:02 -08:00
Andrew Trick
717e1a1005 Comment the eliminateDeadInstruction and related APIs.
When the underlying utility was changed for OSSA, it changed the
semantics of the callback, which breaks the way I've always used a
deletion callback to update iterators.

/// \p callback is called on each deleted instruction before deleting any
/// instructions. This way, the SIL is valid in the callback. However, the
/// callback cannot be used to update instruction iterators since other
/// instructions to be deleted remain in the instruction list.
2021-02-24 11:23:31 -08:00
Andrew Trick
ba9f52071b OSSA: simplify-cfg support for trivial block arguments.
Enable most simplify-cfg optimizations as long as the block arguments
have trivial types. Enable most simplify CFG unit tests cases.

This massively reduces the size of the CFG during OSSA passes.

Test cases that aren't supported in OSSA yet have been moved to a
separate test file for disabled OSSA tests,

Full simplify-cfg support is currently blocked on OSSA utilities which
I haven't checked in yet.
2021-02-23 22:47:59 -08:00
Andrew Trick
0c09d42447 Comment OSSA APIs makeNewValueAvailable & endLifetimeAtLeakingBlocks 2021-02-23 16:54:37 -08:00
Andrew Trick
d50f220018 Add a makeUserIteratorRange API
To allow a value's use-list to be pased into an LLVM API that expects
an llvm::iterator_range<SILInstruction *>.
2021-02-23 16:54:37 -08:00
Meghana Gupta
ecb5d65d6d Fix lifetime of intermediate phis created by RLE
We were adjusting the lifetime of the final phi created by the
SSAUpdater. The intermediate phi's lifetime needs to be adjusted as
well.
2021-02-02 21:54:09 -08:00
Erik Eckstein
d33ea9f350 SIL: remove the JointPostDominanceSetComputer helper struct.
Instead make `findJointPostDominatingSet` a stand-alone function.
There is no need to keep the temporary SmallVector alive across multiple calls of findJointPostDominatingSet for the purpose of re-using malloc'ed memory. The worklist usually contains way less elements than its small size.
2021-02-02 10:20:35 +01:00
Michael Gottesman
2fad943df0 [sil-combine] Update convert_function canonicalization for ownership.
Some notes:

1. I moved the identity round-trip case to InstSimplify since that is where
   optimizations like that are.

2. I did not update in this commit the code that eliminates convert_function
   when it is only destroyed. In a subsequent commit I am going to implement
   that in a general way and apply it to all forwarding instructions.

3. I implemented eliminating convert_function with ownership only uses in a
   utility so that I can reuse it for other similar optimizations in SILCombine.
2021-01-28 12:10:16 -08:00
Erik Eckstein
e98c527319 SILOptimizer: remove the unused findApplyFromDevirtualizedResult utility function 2021-01-27 16:40:14 +01:00
Eric Miotto
8e7f9c9cbd Revert "SIL: let SingleValueInstruction only inherit from a single SILNode." 2021-01-26 10:02:24 -08:00
Erik Eckstein
5ad332f6cd SILOptimizer: remove the unused findApplyFromDevirtualizedResult utility function 2021-01-25 09:30:04 +01:00
Michael Gottesman
2243ffefa4 Merge pull request #35461 from gottesmm/ossa-interior-ptr-fixup
[ownership] Implement Interior Pointer handling API for RAUWing addresses
2021-01-20 09:53:48 -08:00
Meghana Gupta
66ef200105 Enable RLE on OSSA 2021-01-17 23:39:03 -08:00
Michael Gottesman
aa38be6d98 [inst-simplify] Hide simplifyInstruction in favor of using simplifyAndReplaceAllSimplifiedUsesAndErase.
Currently all of these places in the code base perform simplifyInstruction and
then a replaceAllSimplifiedUsesAndErase(...). This is a bad pattern since:

1. simplifyInstruction assumes its result will be passed to
   replaceAllSimplifiedUsesAndErase. So by leaving these as separate things, we
   allow for users to pointlessly make this mistake.

2. I am going to implement in a subsequent commit a utility that lifetime
   extends interior pointer bases when replacing an address with an interior
   pointer derived address. To do this efficiently, I want to reuse state I
   compute during simplifyInstruction during the actual RAUW meaning that if the
   two operations are split, that is difficult without extending the API. So by
   removing this, I can make the transform and eliminate mistakes at the same
   time.
2021-01-17 20:08:24 -08:00
Michael Gottesman
2b73378ddb [sil] Improve comment on swift::replaceSingleUse. 2021-01-14 11:49:35 -08:00