Properly cast the result of a devirtualized partial_apply, because this may be required in case of classes implementing protocols. More specifically, it came up when there is a derived class of a class implementing an initializer required by the protocol.
Fixes rdar://31459426 (SR-4501) and rdar://31479426 (SR-3476)
Also, add a third [serializable] state for functions whose bodies we
*can* serialize, but only do so if they're referenced from another
serialized function.
This will be used for bodies synthesized for imported definitions,
such as init(rawValue:), etc, and various thunks, but for now this
change is NFC.
It looks like the devirtualizer used to have problems computing
method types in the presence of generic substitutions, covariant
returns and other things, so it would bail if a perticular set
of pre-conditions was not met on the types of original method call
and the devirtualized method call.
I don't think any of this is necessary anymore. If this patch
introduces any regressions, we need to fix the root cause instead
of re-introducing this logic.
It is important to de-serialize the devirtualized function (and its callees), especially because we must make sure that all transparent functions are de-serialized.
SILCombine did not do that. But as we have the same optimization in the Devirtualizer, it's not needed to duplicate the code in SILCombine.
The only reason we had this peephole in SILCombine is that the Devirtualizer pass could not handle partial applies.
So with this change the Devirtualizer can now also handle partial applies.
Fixes rdar://problem/30544344 (again, after my first attempt failed)
This predicate can be used to check if a given call can be devirtualized. One of the clients of this new API will be the inliner, which may want to check if a given method call becomes devirtualizable after inlining.
This reverts commit 1b3d29a163, reversing
changes made to b32424953e.
We're seeing a handful of issues from turning on inlining of generics,
so I'm reverting to unblock the bots.
It is now possible to check for any apply if it can be devirtualized without actually performing the deirtualization. This could be used e.g. by inlining heuristics.
SubstitutionList is going to be a more compact representation of
a SubstitutionMap, suitable for inline allocation inside another
object.
For now, it's just a typedef for ArrayRef<Substitution>.
In several places, we construct a SubstitutionMap by taking
generic parameters from one SubstitutionMap up to a certain
depth, with the rest coming from a second SubstitutionMap.
Factor this out into a new utility method, to help with
hiding the internal representation of SubstitutionMap from
clients.
This was meant to be NFC, but it actually fixes a crash in
the devirtualizer, because the old logic there was slightly
wrong, so I added a test for this.
Separate formal lowered types from SIL types.
The SIL type of an argument will depend on the SIL module's conventions.
The module conventions are determined by the SIL stage and LangOpts.
Almost NFC, but specialized manglings are broken incidentally as a result of
fixes to the way passes handle book-keeping of aruments. The mangler is fixed in
the subsequent commit.
Otherwise, NFC is intended, but quite possible do to rewriting the logic in many
places.
Most of this involved sprinkling ValueOwnershipKind::Owned in many places. In
some of these places, I am sure I was too cavalier and I expect some of them to
be trivial. The verifier will help me to track those down.
On the other hand, I do expect there to be some places where we are willing to
accept guaranteed+trivial or owned+trivial. In those cases, I am going to
provide an aggregate ValueOwnershipKind that will then tell SILArgument that it
should disambiguate using the type. This will eliminate the ackwardness from
such code.
I am going to use a verifier to fix such cases.
This commit also begins the serialization of ValueOwnershipKind of arguments,
but does not implement parsing of value ownership kinds. That and undef are the
last places that we still use ValueOwnershipKind::Any.
rdar://29791263
If a generic parameter was substituted for Self, we have to be careful
to not erase Self.Type down to a concrete metatype.
Also, teach the devirtualizer that a metatype of Self type does not
have an exact static type.
We preserve the current behavior of assuming Any ownership always and use
default arguments to hide this change most of the time. There are asserts now in
the SILBasicBlock::{create,replace,insert}{PHI,Function}Argument to ensure that
the people can only create SILFunctionArguments in entry blocks and
SILPHIArguments in non-entry blocks. This will ensure that the code in tree
maintains the API distinction even if we are not using the full distinction in
between the two.
Once the verifier is finished being upstreamed, I am going to audit the
createPHIArgument cases for the proper ownership. This is b/c I will be able to
use the verifier to properly debug the code. At that point, I will also start
serializing/printing/parsing the ownershipkind of SILPHIArguments, but lets take
things one step at a time and move incrementally.
In the process, I also discovered a CSE bug. I am not sure how it ever worked.
Basically we replace an argument with a new argument type but return the uses of
the old argument to refer to the old argument instead of a new argument.
rdar://29671437
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 simplifies the SILType substitution APIs and brings them in line with Doug and Slava's refactorings to improve AST-level type substitution. NFC intended.
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()
The witness thunks for default witnesses are different from the
witness thunks for normal witnesses, because default witnesses take
'Self' (the whole conforming type) rather than having it substituted
away. Cope with this difference while still substituting the innermost
generic parameters for a generic requirement.
Reimplement the witness matching logic used for generic requirements
so that it properly models the expectations required of the witness,
then captures the results in the AST. The new approach has a number of
advantages over the existing hacks:
* The constraint solver no longer requires hacks to try to tangle
together the innermost archetypes from the requirement with the
outer archetypes of the context of the protocol
conformance. Instead, we create a synthetic set of archetypes that
describes the requirement as it should be matched against
witnesses. This eliminates the infamous 'SelfTypeVar' hack.
* The type checker no longer records substitutions involving a weird
mix of archetypes from different contexts (see above), so it's
actually plausible to reason about the substitutions of a witness. A
new `Witness` class contains the declaration, substitutions, and all
other information required to interpret the witness.
* SILGen now uses the substitution information for witnesses when
building witness thunks, rather than computing all of it from
scratch. ``substSelfTypeIntoProtocolRequirementType()` is now gone
(absorbed into the type checker, and improved from there), and the
witness-thunk emission code is simpler. A few other bits of SILGen
got simpler because the substitutions can now be trusted.
* Witness matching and thunk generation involving generic requirements
and nested generics now works, based on some work @slavapestov was
already doing in this area.
* The AST verifier can now verify the archetypes that occur in witness substitutions.
* Although it's not in this commit, the `Witness` structure is
suitable for complete (de-)serialization, unlike the weird mix of
archetypes previously present.
Fixes rdar://problem/24079818 and cleans up an area that's been messy
and poorly understood for a very, very long time.
- 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