Similarly to how we've always handled parameter types, we
now recursively expand tuples in result types and separately
determine a result convention for each result.
The most important code-generation change here is that
indirect results are now returned separately from each
other and from any direct results. It is generally far
better, when receiving an indirect result, to receive it
as an independent result; the caller is much more likely
to be able to directly receive the result in the address
they want to initialize, rather than having to receive it
in temporary memory and then copy parts of it into the
target.
The most important conceptual change here that clients and
producers of SIL must be aware of is the new distinction
between a SILFunctionType's *parameters* and its *argument
list*. The former is just the formal parameters, derived
purely from the parameter types of the original function;
indirect results are no longer in this list. The latter
includes the indirect result arguments; as always, all
the indirect results strictly precede the parameters.
Apply instructions and entry block arguments follow the
argument list, not the parameter list.
A relatively minor change is that there can now be multiple
direct results, each with its own result convention.
This is a minor change because I've chosen to leave
return instructions as taking a single operand and
apply instructions as producing a single result; when
the type describes multiple results, they are implicitly
bound up in a tuple. It might make sense to split these
up and allow e.g. return instructions to take a list
of operands; however, it's not clear what to do on the
caller side, and this would be a major change that can
be separated out from this already over-large patch.
Unsurprisingly, the most invasive changes here are in
SILGen; this requires substantial reworking of both call
emission and reabstraction. It also proved important
to switch several SILGen operations over to work with
RValue instead of ManagedValue, since otherwise they
would be forced to spuriously "implode" buffers.
As there are no instructions left which produce multiple result values, this is a NFC regarding the generated SIL and generated code.
Although this commit is large, most changes are straightforward adoptions to the changes in the ValueBase and SILValue classes.
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
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
constructor in SILBasicBlock::createArgument.
By default the argument is nullptr so any place that currently does not
need to pass in the ValueDecl will not need to be updated given the new
behavior.
Swift SVN r22379
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
Together these allow you to find the specific cond_br argument that will be
passed to a BB by performing:
CBI->getArgForBB(BB, BBArg->getIndex())
Swift SVN r21326
If we have BB args that are only used in a struct/tuple extract, and
that are generated in each predecessor with a struct/tuple instruction,
retype the BB arg and replace the argument with what would have been the
extracted value.
This provides more opportunties for jump threading to kick in.
Swift SVN r16509
A SILArgument is a function argument if the argument's parent BB is the entry BB
of the function containing the argument.
This is an interesting distinction since function arguments have special
aliasing properties with respect to indirect arguments which normal basic block
arguments do not.
Swift SVN r14012
take a const ValueBase* instead of a SILValue, implement SILArgument
cases for a few visitors and opt others out explicitly, and assert
that classes in the SIL value hierarchy override their superclass's
classof.
Swift SVN r4705