The client of this interface naturally expects to get back the
incoming phi value. Ignoring dominance and SIL ownership, the incoming
phi value and the block argument should be substitutable.
This method was actually returning the incoming operand for
checked_cast and switch_enum terminators, which is deeply misleading
and has been the source of bugs.
If the client wants to peek though casts, and enums, it should do so
explicitly. getSingleTerminatorOperand[s]() will do just that.
Allows a SIL pass to follow a def-use chain through phis.
Other terminators can also propagate values through block arguments, but they
always need special handling.
This in the case of insertFunctionArgument requires a ValueOwnershipKind to be
specified since we use that for transformations of function argument lists that
are only correct after the transformation is complete. This only occurs in
FunctionSignatureOptimizations.
On the other hand, createFunctionArgument is only used to construct completely
new argument lists, so we can instead just rely on the function we are in rather
than require the user to pass it in.
rdar://29791263
For a long time, we have:
1. Created methods on SILArgument that only work on either function arguments or
block arguments.
2. Created code paths in the compiler that only allow for "function"
SILArguments or "block" SILArguments.
This commit refactors SILArgument into two subclasses, SILPHIArgument and
SILFunctionArgument, separates the function and block APIs onto the subclasses
(leaving the common APIs on SILArgument). It also goes through and changes all
places in the compiler that conditionalize on one of the forms of SILArgument to
just use the relevant subclass. This is made easier by the relevant APIs not
being on SILArgument anymore. If you take a quick look through you will see that
the API now expresses a lot more of its intention.
The reason why I am performing this refactoring now is that SILFunctionArguments
have a ValueOwnershipKind defined by the given function's signature. On the
other hand, SILBlockArguments have a stored ValueOwnershipKind. Rather than
store ValueOwnershipKind in both instances and in the function case have a dead
variable, I decided to just bite the bullet and fix this.
rdar://29671437
This was already done for getSuccessorBlocks() to distinguish getting successor
blocks from getting the full list of SILSuccessors via getSuccessors(). This
commit just makes all of the successor/predecessor code follow that naming
convention.
Some examples:
getSingleSuccessor() => getSingleSuccessorBlock().
isSuccessor() => isSuccessorBlock().
getPreds() => getPredecessorBlocks().
Really, IMO, we should consider renaming SILSuccessor to a more verbose name so
that it is clear that it is more of an internal detail of SILBasicBlock's
implementation rather than something that one should consider as apart of one's
mental model of the IR when one really wants to be thinking about predecessor
and successor blocks. But that is not what this commit is trying to change, it
is just trying to eliminate a bit of technical debt by making the naming
conventions here consistent.
Before this commit all code relating to handling arguments in SILBasicBlock had
somewhere in the name BB. This is redundant given that the class's name is
already SILBasicBlock. This commit drops those names.
Some examples:
getBBArg() => getArgument()
BBArgList => ArgumentList
bbarg_begin() => args_begin()
In a bunch of use-cases we use stripSinglePredecessorArgs to eliminate this
case. There is no reason to assume that this is being done in the caller of
RCIdentity. Lets make sure that we handle this case here.
rdar://24156136
This improves the quality of code but more importantly makes it easier to ensure
that new terminators are handled in this code since all of the switches are now
covered switches.
These aren't really orthogonal concerns--you'll never have a @thick @cc(objc_method), or an @objc_block @cc(witness_method)--and we have gross decision trees all over the codebase that try to hopscotch between the subset of combinations that make sense. Stop the madness by eliminating AbstractCC and folding its states into SILFunctionTypeRepresentation. This cleans up a ton of code across the compiler.
I couldn't quite eliminate AbstractCC's information from AST function types, since SIL type lowering transiently created AnyFunctionTypes with AbstractCCs set, even though these never occur at the source level. To accommodate type lowering, allow AnyFunctionType::ExtInfo to carry a SILFunctionTypeRepresentation, and arrange for the overlapping representations to share raw values.
In order to avoid disturbing test output, AST and SILFunctionTypes are still printed and parsed using the existing @thin/@thick/@objc_block and @cc() attributes, which is kind of gross, but lets me stage in the real source-breaking change separately.
Swift SVN r27095
One common problem in swift code is the "reforming enum problem". What
happens here is that we have some enum %0 : $Optional<T> and we break it
apart and reform it as a new enum as in the following:
bb9:
...
switch_enum %0 : $Optional<T>, #Optional.None: bb10,
#Optional.Some: bb11
bb10:
%1 = enum $Optional<U>, #Optional.None
br bb12(%1 : $Optional<U>)
bb11:
%2 = some_cast_to_u %0 : ...
%3 = enum $Optional<U>, #Optional.Some, %2 : $U
br bb12(%3 : $Optional<U>)
bb12(%4 : $Optional<U>):
retain_value %0 : $Optional<T> // id %5
release_value %4 : $Optional<U> // id %6
We really would like to know that a retain on %4 is equivalent to a
retain on %0 so we can eliminate the retain, release pair. To be able to
do that safely, we need to know that along all paths %0 and %4 either:
1. Both refer to the same RCIdentity directly. An example of this is the
edge from bb11 -> bb12).
2. Both refer to the "null" RCIdentity (i.e. do not have a payload). An
example of this is the edge from bb10 -> bb12.
Only in such cases is it safe to match up %5, %6 and eliminate them. If
this is not true along all paths like in the following:
bb9:
...
cond_br %foo, bb10, bb11
bb10:
%1 = enum $Optional<U>, #Optional.None
br bb12(%1 : $Optional<U>)
bb11:
%2 = some_cast_to_u %0 : ...
%3 = enum $Optional<U>, #Optional.Some, %2 : $U
br bb12(%3 : $Optional<U>)
bb12(%4 : $Optional<U>):
retain_value %0 : $Optional<T> // id %5
release_value %4 : $Optional<U> // id %6
then we may have that %0 is always non-payloaded coming into bb12. Then
by matching up %0 and %4, if we go from bb9 -> bb11, we will lose a
retain.
Perf Changes:
TITLE..................OLD...........NEW...........NEW/OLD
LevenshteinDistance....1398195.00....1177397.00....0.84
Memset.................26541.00......23701.00......0.89
CaptureProp............5603.00.......5031.00.......0.90
ImageProc..............1281.00.......1196.00.......0.93
InsertionSort..........109828.00.....104129.00.....0.95
StringWalk.............6813.00.......7456.00.......1.09
Chars..................27182.00......30443.00......1.12
The StringWalk, Chars are both reproducible for me. When I turn back on parts of
the recursion (I took the recursion out to make this change more conservative),
the Chars regression goes away, but the StringWalk stays. I have not had a
chance to look at what is going on with StringWalk.
rdar://19724405
Swift SVN r25339
SILFunction::hasSelfArgument() returns true if the SILFunction has a
calling convention with self.
SILArgument::isSelf() returns true if the SILArgument is the last
argument of the first BB of a function for which
SILFunction::hasSelfArgument() is true.
Swift SVN r22378
SILArgument::getIncomingValues() takes in an out array parameter and attempts to
gather up all values from the SILArguments parents predecessors whose value the
SILArgument could take on.
This will let me refactor the single predecessor handling code to also handle
multiple predecessors in a simple way.
Swift SVN r21864