- Look through BB arguments with multiple predecessors.
- Provide a new helper function to figure out the exact type of the underlying object. It will be used by subsequent commits to improve the escape analysis.
SILType substitutions are still done with the old form, and until
BoundGenericTypes hold conformances, we still have to pass around
a ModuleDecl in a few places we really shouldn't, but one step
at a time.
When devirtualizing witness method and class method calls, we
transform apply instructions operating on the result of a SIL
witness_method or class_method instruction to direct calls of
a function_ref.
The generic signature of the dynamic call site might not match
the generic signature of the static thunk, so the substitution
list from the dynamic apply instruction cannot be used directly;
instead, we must transform it to a substitution list suitable
for the static thunk.
- With witness methods, the method is called using the protocol
requirement's signature, <Self : P, ...>, however the
witness thunk has a generic signature derived from the
concrete witness.
For example, the requirement might have a signature
<Self : P, T>, where the concrete witness thunk might
have a signature <X, Y>, where the concrete conforming type
is G<X, Y>.
At the call site, we substitute Self := G<X', Y'>; however
to be able to call the witness thunk directly, we need to
form substitutions X := X' and Y := Y'.
- A similar situation occurs with class methods when the
dynamically-dispatched call is performed against a derived
class, but devirtualization actually finds the method on a
base class of the derived class.
The base class may have a different number of generic
parameters than the derived class, either because the
derived class makes some generic parameters of the base
class concrete, or if the derived class introduces new
generic parameters of its own.
In both cases, we need to consider the generic signature of the
dynamic call site (the protocol requirement or the derived
class method) as well as the generic signature of the static
thunk, and carefully remap the substitutions from one form
into another.
Previously the optimizer would implicitly rely on substitutions
being in AllArchetypes order, in particular that concatenating
outer substitutions with inner substitutions makes sense.
This assumption is about to go away, so this patch refactors
the optimizer to use some new abstractions for remapping
substitution lists.
One minor revision: this lifts the proposed restriction against
overriding a non-open method with an open one. On reflection,
that was inconsistent with the existing rule permitting non-public
methods to be overridden with public ones. The restriction on
subclassing a non-open class with an open class remains, and is
in fact consistent with the existing access rule.
'fileprivate' is considered a broader level of access than 'private',
but for now both of them are still available to the entire file. This
is intended as a migration aid.
One interesting fallout of the "access scope" model described in
758cf64 is that something declared 'private' at file scope is actually
treated as 'fileprivate' for diagnostic purposes. This is something
we can fix later, once the full model is in place. (It's not really
/wrong/ in that they have identical behavior, but diagnostics still
shouldn't refer to a type explicitly declared 'private' as
'fileprivate'.)
As a note, ValueDecl::getEffectiveAccess will always return 'FilePrivate'
rather than 'Private'; for purposes of optimization and code generation,
we should never try to distinguish these two cases.
This should have essentially no effect on code that's /not/ using
'fileprivate' other than altered diagnostics.
Progress on SE-0025 ('fileprivate' and 'private')
- Don't crash if a class_method instruction could not be devirtualized.
- Improve devirtualization of methods with generic parameters and using dependent types.
- Fix a bug in isBindableToSuperclassOf, uncovered while fixing the original bug reported in SR-1206.
This bug could lead in certain cases to invocations of a wrong method from the base class, instead
of using a method from a derived class.
rdar://25891588 and SR-1206
Two fixes to optimization passes to maintain restrictions about what
[fragile] functions can reference:
- When devirtualizing witness methods, don't devirtualize if the caller
is fragile and the callee is not. This matches existing logic in
class devirtualization.
- When performing generic or function signature specialization, don't
specialize non-fragile functions referenced from fragile functions.
Since @_transparent functions are allowed to call 'static inline'
imported functions, also be sure to mark the foreign-to-native thunk
for such a function as [fragile].
With this patch, the standard library and performance test suite
now build with -enable-resilience.
No new tests for this stuff here -- the existing tests together
with an -enable-resilience build provide coverage.
Closes out <https://bugs.swift.org/browse/SR-267> and
<https://bugs.swift.org/browse/SR-268>.
In many places, we're interested in whether a type with archetypes *might be* a superclass of another type with the right bindings, particularly in the optimizer. Provide a separate Type::isBindableToSuperclassOf method that performs this check. Use it in the devirtualizer to fix rdar://problem/24993618. Using it might unblock other places where the optimizer is conservative, but we can fix those separately.
We ignore substitutions from the conformance, using the Self type
substitution from the call site instead.
The new SILFunctionType::getDefaultWitnessMethodProtocol() method
is used to figure out what "shape" the Self substitutions need
to take.
This is cleaner than it was before the method was added, but is
still a bit of a hack; more and more it appears that we need to
stop thinking of witness_method as a separate calling convention,
and design what @rjmccall described as "abstraction patterns for
generic signatures" instead.
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.
SILValue.h/.cpp just defines the SIL base classes. Referring to specific instructions is a (small) kind of layering violation.
Also I want to keep SILValue small so that it is really just a type alias of ValueBase*.
NFC.
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.
This eliminates some minor overheads, but mostly it eliminates
a lot of conceptual complexity due to the overhead basically
appearing outside of its context.
Use ClassHierarchyAnalysis to check if a given method is effectively final, i.e. cannot be overridden.
This replaces the old approach based on using isKnownFinal, which was weaker because it didn't use the ClassHierarchyAnalysis.
It is now able to cover some new cases where the instance is a parameter of a function. If it can be proven that the static type of instance cannot be derived, then it's static type is also a dynamic type of the instance.
The new functionality is not directly triggered in the current setup, because isKnownFinalMethod is currently invoked before it and subsumes this cases. But getInstanceWithExactDynamicType got this functionality anyways to be self-contained, so that it can be used in other contexts, where it is not invoked after isKnownFinalMethod.
(libraries now)
It has been generally agreed that we need to do this reorg, and now
seems like the perfect time. Some major pass reorganization is in the
works.
This does not have to be the final word on the matter. The consensus
among those working on the code is that it's much better than what we
had and a better starting point for future bike shedding.
Note that the previous organization was designed to allow separate
analysis and optimization libraries. It turns out this is an
artificial distinction and not an important goal.