Commit Graph

267 Commits

Author SHA1 Message Date
Meghana Gupta
cdbd0f4743 Fix SimplifyCFG::simplifyArgs for OSSA 2023-01-08 00:15:12 -08:00
Meghana Gupta
3660a1e6a9 Remove borrow scope adjustment for @guaranteed phi args 2023-01-06 23:50:07 -08:00
Meghana Gupta
900d8c3f63 Add ossa unit tests for SimplifyCFG::simplifyTermWithIdenticalDestBlocks 2023-01-06 23:50:07 -08:00
Meghana Gupta
73cd7a9dc1 Add ossa unit tests for SimplifyCFG::simplifySwitchEnumUnreachableBlocks 2023-01-06 23:50:07 -08:00
Meghana Gupta
1fc0d0aba1 SimplifyCFG: Modify DestBB before replacing branch target 2023-01-06 23:50:07 -08:00
Meghana Gupta
94f8841374 Fix SimplifyCFG::simplifySwitchEnumBlock for OSSA 2023-01-06 23:50:07 -08:00
Meghana Gupta
ff4ab7de11 Enable SimplifyCFG::canonicalizeSwitchEnums and add unit tests 2022-10-21 23:08:43 -07:00
Meghana Gupta
97013100dc [NFC] Move SimplifyCFG class to its own header so that it can be accessed by the unit test infra 2022-10-21 16:48:28 -07:00
Erik Eckstein
ecbcacdecf SIL Analysis: Rename InvalidationKind::FunctionData to InvalidationKind::Effects
This invalidation kind is used when a compute-effects pass changes function effects.
Also, let optimization passes which don't change effects only invalidate the `FunctionBody` and not `Everything`.
2022-10-20 09:20:28 +02:00
Andrew Trick
8f34d9cc2f Add a comment regarding an optimizer rule for self-loops. 2022-10-04 13:27:48 -07:00
Josh Soref
730b16c569 Spelling siloptimizer
* access
* accessed
* accesses
* accessor
* acquiring
* across
* activated
* additive
* address
* addresses'
* aggregated
* analysis
* and
* appropriately
* archetype
* argument
* associated
* availability
* barriers
* because
* been
* beginning
* belongs
* beneficial
* blocks
* borrow
* builtin
* cannot
* canonical
* canonicalize
* clazz
* cleanup
* coalesceable
* coalesced
* comparisons
* completely
* component
* computed
* concrete
* conjunction
* conservatively
* constituent
* construct
* consuming
* containing
* covered
* creates
* critical
* dataflow
* declaration
* defined
* defining
* definition
* deinitialization
* deliberately
* dependencies
* dependent
* deserialized
* destroy
* deterministic
* deterministically
* devirtualizes
* diagnostic
* diagnostics
* differentiation
* disable
* discipline
* dominate
* dominates
* don't
* element
* eliminate
* eliminating
* elimination
* embedded
* encounter
* epilogue
* epsilon
* escape
* escaping
* essential
* evaluating
* evaluation
* evaluator
* executing
* existential
* existentials
* explicit
* expression
* extended
* extension
* extract
* for
* from
* function
* generic
* guarantee
* guaranteed
* happened
* heuristic
* however
* identifiable
* immediately
* implementation
* improper
* include
* infinite
* initialize
* initialized
* initializer
* inside
* instruction
* interference
* interferes
* interleaved
* internal
* intersection
* intractable
* intrinsic
* invalidates
* irreducible
* irrelevant
* language
* lifetime
* literal
* looks
* materialize
* meaning
* mergeable
* might
* mimics
* modification
* modifies
* multiple
* mutating
* necessarily
* necessary
* needsmultiplecopies
* nonetheless
* nothing
* occurred
* occurs
* optimization
* optimizing
* original
* outside
* overflow
* overlapping
* overridden
* owned
* ownership
* parallel
* parameter
* paths
* patterns
* pipeline
* plottable
* possible
* potentially
* practically
* preamble
* precede
* preceding
* predecessor
* preferable
* preparation
* probably
* projection
* properties
* property
* protocol
* reabstraction
* reachable
* recognized
* recursive
* recursively
* redundant
* reentrancy
* referenced
* registry
* reinitialization
* reload
* represent
* requires
* response
* responsible
* retrieving
* returned
* returning
* returns
* rewriting
* rewritten
* sample
* scenarios
* scope
* should
* sideeffects
* similar
* simplify
* simplifycfg
* somewhat
* spaghetti
* specialization
* specializations
* specialized
* specially
* statistically
* substitute
* substitution
* succeeds
* successful
* successfully
* successor
* superfluous
* surprisingly
* suspension
* swift
* targeted
* that
* that our
* the
* therefore
* this
* those
* threshold
* through
* transform
* transformation
* truncated
* ultimate
* unchecked
* uninitialized
* unlikely
* unmanaged
* unoptimized key
* updataflow
* usefulness
* utilities
* villain
* whenever
* writes

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>
2022-10-03 18:31:33 -04:00
Erik Eckstein
653b6ecc33 fix a crash/hang in SimplifyCFG.
Jump threading in an unreachable CFG region can lead to a crash (in an assert compiler) or hang (in an no-assert compiler) in `ValueBase::replaceAllUsesWith`.

Unfortunately I couldn't come up with an isolated SIL test case.

rdar://92267349
2022-04-25 16:48:59 +02:00
Andrew Trick
2fd4de411e [SIL-opaque] Removed [Unconditional]CheckedCastValue 2022-03-22 17:04:13 -07:00
Andrew Trick
83b01d8ebe Improve the SILPhiArgument API
This subclass of SILArgument should be eliminated--it's not always a
phi, and whether it is a "phi argument" has nothing whatsoever to do
with the opcode. That is a property of a value's uses, not a property of the
value.

Until then, provide a logical and useful API within the type. This
often avoids the need to explicitly cast to a SILPhiArgument type and
avoids a lot of boilerplate in code that deals with phis.

Note: PhiOperand and PhiValue are improved abstractions on top of this
API. But the SILArgument-level API is still an important bridge
between SILArgument and other phi abstractions.
2022-02-15 13:28:46 -08:00
Erik Eckstein
8fe36eedd8 SILPassManager: improve bisecting for debugging the optimizer
* Add the possibility to bisect the individual transforms of SILCombine and SimplifyCFG.
   To do so, the `-sil-opt-pass-count` option now accepts the format `<n>.<m>`, where `m` is the sub-pass number.
   The sub-pass number limits the number of individual transforms in SILCombine or SimplifyCFG.

* Add an option `-sil-print-last` to print the SIL of the currently optimized function before and after the last pass, which is specified with `-sil-opt-pass-count`.
2022-02-09 13:25:30 +01: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
Andrew Trick
a5b1b5c3f8 SILOptimizer OSSA support for switch_enum & checked_cast_br
To create OSSA terminator results, use:
- OwnershipForwardingTermInst::createResult(SILType ValueOwnershipKind)
- SwitchEnumInst::createDefaultResult()

Add support for passing trivial values to nontrivial forwarding
ownership. This effectively converts None to Guaranteed ownership.

This is essential for handling ".none" enums as trivial values while
extracting a nontrivial payload with switch_enum. This converts None
to Guaranteed ownership. Generates a copy if needed to convert back to
Owned ownership.
2021-09-07 22:50:46 -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
Andrew Trick
19007a63b1 SimplifyCFG add tracing 2021-07-17 19:37:12 -07:00
Andrew Trick
ca1c46b09a OSSA: SimplifyCFG. Add DeadEndBlocks and pass it to jump-threading. 2021-07-17 18:31:25 -07:00
Andrew Trick
e6ec4e4691 SimplifyCFG OSSA support for trivial switch_enum. 2021-07-17 18:31:25 -07:00
Meghana Gupta
54933624f1 Add IsInfiniteJumpThreadingBudget for testing 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
Meghana Gupta
c46acc0f9c OSSA: SimplifyCFG. Only jump thread for trivial dest block args.
Support for non-trivial args will be added separately.
2021-07-17 18:31:25 -07:00
Andrew Trick
8a45b5fa2c OSSA: Support SimplifyCFG tryJumpThreading for testing.
This will be gated by a testing flag while tests are staged in.
2021-07-17 18:31:25 -07:00
OneUpWallStreet
25df5d2c48 Fixed some common grammatical errors in the comments. (#38248) 2021-07-05 01:00:48 -07:00
Erik Eckstein
b3a7792d1d Reinstate "SIL: add a StackList data structure with zero cost operations."
... with a fix for a non-assert build crash: I used the wrong ilist type for SlabList. This does not explain the crash, though. What I think happened here is that llvm miscompiled and put the llvm_unreachable from the Slab's deleteNode function unconditionally into the SILModule destructor.
Now by using simple_ilist, there is no need for a deleteNode at all.
2021-04-13 13:49:45 +02:00
Arnold Schwaighofer
ddfdf4779d Revert "SIL: add a StackList data structure with zero cost operations." 2021-04-12 12:48:16 -07:00
Erik Eckstein
0456d95cb0 SIL: Use StackList in BasicBlockWorklist and BasicBlockSetVector
plus: I moved both data structures into a separate header file.
2021-04-11 14:07:26 +02:00
Andrew Trick
e9d0b08706 Add utilities to support OSSA update after running SSAUpdater.
This directly adds support to BasicBlockCloner for updating OSSA.

It also adds a much more general-purpose GuaranteedPhiBorrowFixup
utility which can be used for more complicated SSA updates, in which
multiple phis need to be created. More generally, it handles adding
nested borrow scopes for guaranteed phis even when that phi is used by
other guaranteed phis.
2021-03-18 00:14:13 -07:00
Michael Gottesman
19dd90674d Merge pull request #36167 from gottesmm/pr-761936430320990a32c8dfb2f85d27f171f186ba
[simplify-cfg] Only check if we can remove releases by performing simple jump threading if our block argument is not a trivial type.
2021-03-13 13:00:03 -08:00
Slava Pestov
7ccc41a7b7 SIL: Preliminary support for 'apply [noasync]' calls
Refactor SILGen's ApplyOptions into an OptionSet, add a
DoesNotAwait flag to go with DoesNotThrow, and sink it
all down into SILInstruction.h.

Then, replace the isNonThrowing() flag in ApplyInst and
BeginApplyInst with getApplyOptions(), and plumb it
through to TryApplyInst as well.

Set the flag when SILGen emits a sync call to a reasync
function.

When set, this disables the SIL verifier check against
calling async functions from sync functions.

Finally, this allows us to add end-to-end tests for
rdar://problem/71098795.
2021-03-04 22:41:46 -05:00
Meghana Gupta
1f89d9ff89 Verify critical edges when -sil-verify-all is enabled 2021-03-03 23:45:56 -08:00
Michael Gottesman
34e4e42642 [simplify-cfg] Only check if we can remove releases by performing simple jump threading if our block argument is not a trivial type.
Eliminates unnecessary work and reduces compile time.
2021-02-25 12:21:49 -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
Michael Gottesman
142c3bd1fc [simplify-cfg] Enable some simple opts during ownerships on br, cond_br that do not involve objects directly.
Just to reduce the size of the CFG.
2021-02-12 23:20:17 -08:00
Michael Gottesman
6c255734ba [simplify-cfg] Enable remove unreachable blocks to shrink the CFG a bit. 2021-02-12 23:20:17 -08:00
Erik Eckstein
214b7a9929 Use the new BasicBlockWorklist utility in various places in the compiler.
It's a refactoring which simplifies the code.
NFC.
2021-02-12 11:15:55 +01:00
Erik Eckstein
fe10f98cf0 SIL: rename the SILBitfield.h header file to BasicBlockBits.h
NFC
2021-02-12 11:15:55 +01:00
Andrew Trick
67863c55b6 Revert "SimplifyCFG: fix an infinite jump-threading loop."
This reverts commit fe928d57ac.

This causes an ASAN failure. Reverting until it can be debugged.
2021-01-28 23:46:23 -08:00
Andrew Trick
0b2a6267f6 Revert "Comment SimplifyCFG JumpThreadingCost."
This reverts commit 7a1065cfc2.
2021-01-28 23:46:12 -08:00
Andrew Trick
7a1065cfc2 Comment SimplifyCFG JumpThreadingCost.
Explain how this actually works since it isn't directly obvious.
2021-01-27 16:34:02 -08:00
Andrew Trick
e5e2cf1f62 Merge pull request #35608 from atrick/guard-simplify-loops
Add a safeguard to SimplifyCFG tryJumpThreading to avoid infinite loop peeling
2021-01-27 16:19:27 -08:00
Erik Eckstein
fe928d57ac SimplifyCFG: fix an infinite jump-threading loop.
The JumpThreadingCost map in Simplify CFG is used to prevent infinite jump threading loops.
There was a missing update of the cost for blocks which are cloned:
Jump threading loops were prevented for infinitely cloning the original block, but not for re-cloning the cloned block.

A test case is already added in 8948f7565a

rdar://73357726, [SR-14068]
2021-01-27 14:54:25 +01:00
Erik Eckstein
f48191966c SILOptimizer: use BasicBlockSet instead of SmallPtrSet in various transformations.
It reduces compile time.
2021-01-27 10:31:17 +01:00
Andrew Trick
8b2098445e Add a safeguard to SimplifyCFG tryJumpThreading to avoid infinite loop peeling
rdar://73644659 (Add a safeguard to SimplifyCFG tryJumpThreading to avoid infinite loop peeling)

A case of infinite loop peeling was exposed recently:

([SR-14068]: Compiling with optimisation runs indefinitely for grpc-swift)

It was trivially fixed here:

---
commit 8948f7565a (HEAD -> fix-simplifycfg-tramp, public/fix-simplifycfg-tramp)
Author: Andrew Trick <atrick@apple.com>
Date:   Tue Jan 26 17:02:37 2021

Fix a SimplifyCFG typo that leads to unbounded optimization
---

However, that fix isn't a strong guarantee against this behavior. The
obvious complete fix is that jump-threading should not affect loop
structure. But changing that requires a performance investigation. In
the meantime this change introduces a simple mechanism that guarantees
that a loop header is not repeatedly cloned.

This safeguard is worthwhile because jump-threading across loop
boundaries is kicking in more frequently now the critical edges are
being split within SimplifyCFG.

Note that it is both necessary and desirable to split critical edges
between transformations so that SIL remains in a valid state. That
allows other code in SimplifyCFG to call arbitrary SIL utilities,
allows verifying SimplifyCFG by running verification between
transformation, and simplifies the patters that SimplifyCFG itself
needs to consider.
2021-01-26 19:42:19 -08:00
Andrew Trick
8948f7565a Fix a SimplifyCFG typo that leads to unbounded optimization
Fixes rdar://73357726 ([SR-14068]: Compiling with optimisation runs
indefinitely for grpc-swift)

The root cause of this problem is that SimplifyCFG::tryJumpThreading
jump threads into loops, effectively peeling loops. This is not the
right way to implement loop peeling. That belongs in a loop
optimization pass. There's is simply no sane way to control jump
threading if it is allowed across loop boundaries, both from the
standpoint of requiring optimizations to terminate and from the
standpoint of reducing senseless code bloat.

SimplifyCFG does have a mechanism to avoid jump-threading into loop in
most cases. That mechanism would actually prevent the infinite loop
peeling in this particular case if it were implemented correctly. But
the original implementation circa 2014 appears to have a typo.

This commit fixes that obvious bug. I do not think it's a sufficient
to ensure we never see the bad behavior. I will file separate bugs for
the broader issue.

This bad behavior was exposed incidentally by splitting critical
edges. Without edge splitting, SimplifyCFG::simplifyBlocks only
performs "jump threading" once, creating a critical edge to the loop
header. Because simplifyBlocks works under the assumption that there
are no critical edges, it never attempts to perform jump threading
again. In other words, the presence of the critical edge "breaks" the
optimization, preventing it from continuing as intended.

With edge splitting, the simplifyBlocks worklist performs "jump
threading" followed by "jump to trampoline" removal, which creates a
new loop-back edge to the original loop header. This is fine. However,
simplifyBlocks iteratively attempts all optimizations up to a fix
point and it does not stop at loop headers! So, splitting the critical
edge causes simplifyBlocks to work as intended, which leads to
infinite loop peeling. The end result is an infinite sequence of
nested loops. Each peeled iteration is actually within the parent
loop.
2021-01-26 17:05:37 -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
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
c026e95cce [ownership] Extract out SILOwnershipKind from ValueOwnershipKind into its own type and rename Invalid -> Any.
This makes it easier to understand conceptually why a ValueOwnershipKind with
Any ownership is invalid and also allowed me to explicitly document the lattice
that relates ownership constraints/value ownership kinds.
2020-11-10 14:29:11 -08:00