Commit Graph

102 Commits

Author SHA1 Message Date
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
Michael Gottesman
1e4d3d2e97 [sil-inst-opt] Add a new utility swift::replaceSingleUse.
Given an Operand *op, this API executes op->set(newSILValue) except that:

1. If the user of op is an end scope, this API no-opts. This API is only used in
   contexts where we are rewriting uses and are not interesting in end scope
   instructions since we are moving uses from one scope to another scope.

2. If the user of op is not an end scope, but is a lifetime ending use of
   op->get(), we insert a destroy_value|end_borrow as appropriate on op->get()
   to ensure op->get()'s lifetime is still ended. We assume that if
   op->getUser() is lifetime ending, that our caller has ensured that we can end
   newValue's lifetime.
2021-01-13 10:43:41 -08:00
Michael Gottesman
1b14b5bcee [sil] Move swift::replaceAllUsesAndErase from Analysis/SimplifyInstruction -> Utils/InstOptUtils
This is a low level API already being used in multiple places besides
InstSimplify (e.x.: Utils/OwnershipOptUtils), so it makes sense to move it into
InstOptUtil.
2021-01-13 10:43:41 -08:00
Michael Gottesman
4600aa7ddc [sil-inst-opt] Rename the internal madeChange bool in InstModCallback to wereAnyCallbacksInvoked.
This makes it clear that we are not talking about a madeChange in a general
sense and are instead just tracking if /any/ of our callbacks were invoked. This
is still useful enough for our users and will prevent confusion.
2021-01-04 16:47:13 -08:00
Michael Gottesman
2f6ffae4b0 [sil-inst-opt] Change InstModCallbacks to specify a setUseValue callback instead of RAUW callbacks.
This allows for me to do a couple of things improving quality/correctness/ease of use:

1. I reimplemented InstMod's RAUW and RAUW/erase helpers on top of
   setUseValue/deleteInst. Beyond allowing the caller to specify less things, we
   gain an orthogonality preventing bugs like overriding erase/RAUW but not
   overriding erase or having the erase used in erase/RAUW act differently than
   the erase for deleteInst.

2. There were a bunch of places using InstModCallback that also were setting
   uses without having the ability for InstModCallbacks perform it (since it
   only supported RAUW). This is an anti-pattern and could cause subtle bugs to
   be introduced by appropriate state in the caller not being updated.
2021-01-04 16:47:13 -08:00
Michael Gottesman
0de00d1ce4 [sil-inst-opt] Improve performance of InstModCallbacks by eliminating indirect call along default callback path.
Specifically before this PR, if a caller did not customize a specific callback
of InstModCallbacks, we would store a static default std::function into
InstModCallbacks. This means that we always would have an indirect jump. That is
unfortunate since this code is often called in loops.

In this PR, I eliminate this problem by:

1. I made all of the actual callback std::function in InstModCallback private
   and gave them a "Func" postfix (e.x.: deleteInst -> deleteInstFunc).

2. I created public methods with the old callback names to actually call the
   callbacks. This ensured that as long as we are not escaping callbacks from
   InstModCallback, this PR would not result in the need for any source changes
   since we are changing a call of a std::function field to a call to a method.

3. I changed all of the places that were escaping inst mod's callbacks to take
   an InstModCallback. We shouldn't be doing that anyway.

4. I changed the default value of each callback in InstModCallbacks to be a
   nullptr and changed the public helper methods to check if a callback is
   null. If the callback is not null, it is called, otherwise the getter falls
   back to an inline default implementation of the operation.

All together this means that the cost of a plain InstModCallback is reduced and
one pays an indirect function cost price as one customizes it further which is
better scalability.

P.S. as a little extra thing, I added a madeChange field onto the
InstModCallback. Now that we have the helpers calling the callbacks, I can
easily insert instrumentation like this, allowing for users to pass in
InstModCallback and see if anything was RAUWed without needing to specify a
callback.
2021-01-04 12:51:55 -08:00
Michael Gottesman
259d2bb182 [ownership] Commit a generic replaceAllUsesAndEraseFixingOwnership api and enable SimplifyInstruction on OSSA.
This is a generic API that when ownership is enabled allows one to replace all
uses of a value with a value with a differing ownership by transforming/lifetime
extending as appropriate.

This API supports all pairings of ownership /except/ replacing a value with
OwnershipKind::None with a value without OwnershipKind::None. This is a more
complex optimization that we do not support today. As a result, we include on
our state struct a helper routine that callers can use to know if the two values
that they want to process can be handled by the algorithm.

My moticiation is to use this to to update InstSimplify and SILCombiner in a
less bug prone way rather than just turn stuff off.

Noting that this transformation inserts ownership instructions, I have made sure
to test this API in two ways:

1. With Mandatory Combiner alone (to make sure it works period).

2. With Mandatory Combiner + Semantic ARC Opts to make sure that we can
   eliminate the extra ownership instructions it inserts.

As one can see from the tests, the optimizer today is able to handle all of
these transforms except one conditional case where I need to eliminate a dead
phi arg. I have a separate branch that hits that today but I have exposed unsafe
behavior in ClosureLifetimeFixup that I need to fix first before I can land
that. I don't want that to stop this PR since I think the current low level ARC
optimizer may be able to help me here since this is a simple transform it does
all of the time.
2020-12-09 11:53:56 -08:00
Meghana Gupta
483321c360 Enable ArrayElementValuePropagation on ownership SIL 2020-11-04 11:54:47 -08:00
Meghana Gupta
e2a9bf2009 Fix use-after-free in SILCombine (#34145)
SILCombine maintains a worklist of instructions and deleting of instructions is valid only via callbacks that remove them from the worklist as well. It calls swift::tryDeleteDeadClosure which in turn calls SILBuilder apis like emitStrongRelease/emitReleaseValue/emitDestroyValue which can delete instructions via SILInstruction::eraseFromParent leaving behind a stale entry in SILCombine's worklist causing a crash.

This PR adds swift::emitDestroyOperation which correctly calls the appropriate InstModCallbacks on added/removed instructions. This comes from swift::releasePartialApplyCapturedArg which was handling creation of destroys with callbacks correctly.
2020-10-01 20:57:40 -07:00
Brent Royal-Gordon
dd726a0015 [NFC] Avoid repeatedly instantiating std::function 2020-09-01 12:54:55 -07:00
Erik Eckstein
63c275c45f SILOptimizer: move String concatination optimization from SILCombine/ConstantFolding to StringOptimization.
This simplifies some code and it's not required to try this optimization on every run of SILCombine and ConstantPropagation.
2020-08-04 16:16:11 +02:00
Erik Eckstein
662f03ec4c SILCombine: optimize casts of existential boxes.
Optimize the unconditional_checked_cast_addr in this pattern:

   %box = alloc_existential_box $Error, $ConcreteError
   %a = project_existential_box $ConcreteError in %b : $Error
   store %value to %a : $*ConcreteError
   %err = alloc_stack $Error
   store %box to %err : $*Error
   %dest = alloc_stack $ConcreteError
   unconditional_checked_cast_addr Error in %err : $*Error to ConcreteError in %dest : $*ConcreteError

to:
   ...
   retain_value %value : $ConcreteError
   destroy_addr %err : $*Error
   store %value to %dest $*ConcreteError

This lets the alloc_existential_box become dead and it can be removed in following optimizations.
The same optimization is also done for conditional_checked_cast_addr.

There is also an implication for debugging:
Each "throw" in the code calls the runtime function swift_willThrow. The function is used by the debugger to set a breakpoint and also add hooks.
This optimization can completely eliminate a "throw", including the runtime call.
So, with optimized code, the user might not see the program to break at a throw, whereas in the source code it is actually throwing.
On the other hand, eliminating the existential box is a significant performance win and we don't guarantee any debugging behavior for optimized code anyway. So I think this is a reasonable trade-off.
I added an option "-Xllvm -keep-will-throw-call" to keep the runtime call which can be used if someone want's to reliably break on "throw" in optimized builds.

rdar://problem/66055678
2020-07-29 21:57:51 +02:00
Suyash Srijan
acf72bdf26 [SILOptimizer] Simplify 'calleesAreStaticallyKnowable' to handle both abstract functions and enum element decls (#32968) 2020-07-20 16:44:30 +01:00
Meghana Gupta
013387eceb Update Devirtualizer's analysis invalidation (#31284)
* Update Devirtualizer's analysis invalidation

castValueToABICompatibleType can change CFG, Devirtualizer uses this api but doesn't check if it modified the cfg
2020-04-27 18:30:33 -07:00
Michael Gottesman
c3fb485c7d [sil-combine] Refactor rewriteApplyCallee -> cloneFullApplySiteReplacingCallee and move into InstOptUtils.h.
I am going to use this in mandatory combine, and it seems like a generally
useful transformation.

I also updated the routine to construct its own SILBuilder that injects a user
passed in SILBuilderContext eliminating the bad pattern of passing in
SILBuilders.

This should be an NFC change.
2020-04-23 20:33:14 -07:00
Suyash Srijan
f724d1ff85 [SE-0280] Enum cases as protocol witnesses (#28916)
* [Typechecker] Allow enum cases without payload to witness a static get-only property with Self type protocol requirement

* [SIL] Add support for payload cases as well

* [SILGen] Clean up comment

* [Typechecker] Re-enable some previously disabled witness matching code

Also properly handle the matching in some cases

* [Test] Update typechecker tests with payload enum test cases

* [Test] Update SILGen test

* [SIL] Add two FIXME's to address soon

* [SIL] Emit the enum case constructor unconditionally when an enum case is used as a witness

Also, tweak SILDeclRef::getLinkage to update the 'limit' to 'OnDemand' if we have an enum declaration

* [SILGen] Properly handle a enum witness in addMethodImplementation

Also remove a FIXME and code added to workaround the original bug

* [TBDGen] Handle enum case witness

* [Typechecker] Fix conflicts

* [Test] Fix tests

* [AST] Fix indentation in diagnostics def file
2020-03-28 10:44:01 +00:00
Meghana Gupta
8e800e49bf Recommit #29812 with fixes (#30342) 2020-03-13 19:34:16 -07:00
Rintaro Ishizaki
ccbc26d947 Revert "Use in_guaranteed for let captures (#29812)"
This reverts commit 13b9915c6f.
2020-03-10 16:08:08 -07:00
Meghana Gupta
13b9915c6f Use in_guaranteed for let captures (#29812)
* Use in_guaranteed for let captures

With this all let values will be captured with in_guaranteed convention
by the closure. Following are the main changes :

SILGen changes:
- A new CaptureKind::Immutable is introduced, to capture let values as in_guaranteed.
- SILGen of in_guaranteed capture had to be fixed.
  in_guaranteed captures as per convention are consumed by the closure. And so SILGen should not generate a destroy_addr for an in_guaranteed capture.
  But LetValueInitialization can push Dealloc and Release states of the captured arg in the Cleanup stack, and there is no way to access the CleanupHandle and disable the emission of destroy_addr while emitting the captures in SILGenFunction::emitCaptures.
  So we now create, temporary allocation of the in_guaranteed capture iduring SILGenFunction::emitCaptures without emitting destroy_addr for it.

SILOptimizer changes:
- Handle in_guaranteed in CopyForwarding.
- Adjust dealloc_stack of in_guaranteed capture to occur after destroy_addr for on_stack closures in ClosureLifetimeFixup.

IRGen changes :
  - Since HeapLayout can be non-fixed now, make sure emitSize is used conditionally
  - Don't consider ClassPointerSource kind parameter type for fulfillments while generating code for partial apply forwarder.
    The TypeMetadata of ClassPointSource kind sources are not populated in HeapLayout's NecessaryBindings. If we have a generic parameter on the HeapLayout which can be fulfilled by a ClassPointerSource, its TypeMetaData will not be found while constructing the dtor function of the HeapLayout.
    So it is important to skip considering sources of ClassPointerSource kind, so that TypeMetadata of a dependent generic parameters gets populated in HeapLayout's NecessaryBindings.
2020-03-10 12:23:02 -07:00
Michael Gottesman
621573e839 [semantic-arc-opts] Refactor out convert to guarantee code into a method on LiveRange.
Should be NFC.

I am doing this since when I am eliminating phi webs, I need this exact
functionality.
2020-03-05 11:49:36 -08:00
Erik Eckstein
85789367a3 SILOptimizer: restructure the apply(partial_apply) peephole and the dead partial_apply elimination optimizations
Changes:

* Allow optimizing partial_apply capturing opened existential: we didn't do this originally because it was complicated to insert the required alloc/dealloc_stack instructions at the right places. Now we have the StackNesting utility, which makes this easier.

* Support indirect-in parameters. Not super important, but why not? It's also easy to do with the StackNesting utility.

* Share code between dead closure elimination and the apply(partial_apply) optimization. It's a bit of refactoring and allowed to eliminate some code which is not used anymore.

* Fix an ownership problem: We inserted copies of partial_apply arguments _after_ the partial_apply (which consumes the arguments).

* When replacing an apply(partial_apply) -> apply and the partial_apply becomes dead, avoid inserting copies of the arguments twice.

These changes don't have any immediate effect on our current benchmarks, but will allow eliminating curry thunks for existentials.
2020-02-11 12:48:39 +01:00
Ravi Kandhadai
ec9844b2d9 [SIL Optimization] Add a new mandatory pass for unrolling forEach
calls over arrays created from array literals. This enables optimizing
further the output of the OSLogOptimization pass, and results in
highly-compact and optimized IR for calls to the new os log API.

<rdar://58928427>
2020-02-07 20:06:29 -08:00
Ravi Kandhadai
a12fe9ae3b [SIL Optimization] Fix a bug in the identification of dead constant
evaluable calls. The fix makes the check more conservative and
assumes that calls with generic arguments are not dead, as generic
functions with arbitrary side-effects can be invoked through them.

Also, add a few helper functions to the InstructionDeleter utility
that will enable deleting an instruction along with its users.
2020-01-24 19:00:16 -08:00
Ravi Kandhadai
935686460c [SIL Optimization] Create a new utility InstructionDeleter to delete instructions
and eliminate dead code. This is meant to be a replacement for the utility:
recursivelyDeleteTriviallyDeadInstructions. The new utility performs more aggresive
dead-code elimination for ownership SIL.

This patch also migrates most non-force-delete uses of
recursivelyDeleteTriviallyDeadInstructions to the new utility.
and migrates one force-delete use of recursivelyDeleteTriviallyDeadInstructions
(in IRGenPrepare) to use the new utility.
2019-12-18 13:17:17 -08:00
Michael Gottesman
113c22a680 [sil] Move partial apply combiner code from SILCombiner into InstOptUtils.h/SILCombinerApplyVisitor.cpp.
This is in preparation for moving this into the mandatory combiner.
2019-12-11 14:48:19 -08:00
Erik Eckstein
402e228b39 SIL: add a table in SILModule to mark method declarations as externally visible.
This is needed for cross-module-optimization: CMO marks functions as inlinable. If a private or internal method is referenced from such an inlinable function, it must not be eliminated by dead function elimination after serialization (a method is basically an AbstractFunctionDecl).
For SILFunctions we can do this by simply setting the linkage, but for methods we need another mechanism.
2019-12-03 14:37:01 +01:00
Erik Eckstein
d88edadb60 BasicCalleeAnalysis: fix computation of class method callees if an overridden function has a different ABI
In such a case the overridden function gets a new separate vtable entry.
With this change, the computation of class method callees only uses the information in sil_vtables (instead of ClassDecl members).

Fixes a compiler crash in various optimization passes.
rdar://problem/56146633
2019-10-22 11:27:21 +02:00
Jordan Rose
a1ea211f22 Add llvm::iterator_range to LLVM.h
If we're going to get rid of swift::IteratorRange, let's make
llvm::iterator_range easy to use.

No functionality change.
2019-10-08 15:24:06 -07:00
Jordan Rose
7b0d081965 Remove IteratorRange in favor of llvm::iterator_range
Now that llvm::iterator_range has 'empty', there's not enough reason to
keep our own version of it in the Swift repo.

No functionality change.
2019-10-08 11:23:28 -07:00