It it now possible to check if a function with a given name and a given linkage exists in one of the modules,
even if the current module contains a function with this name but a difference linkage.
This is useful e.g. for performing a lookup of pre-specializations.
We want to distinguish the special case of a library built with
-sil-serialize-all, from a SIL function that is [fragile] because
of an explicitly @_transparent or @inline(__always).
For now, NFC.
This was mistakenly reverted in an attempt to fix buildbots.
Unfortunately it's now smashed into one commit.
---
Introduce @_specialize(<type list>) internal attribute.
This attribute can be attached to generic functions. The attribute's
arguments must be a list of concrete types to be substituted in the
function's generic signature. Any number of specializations may be
associated with a generic function.
This attribute provides a hint to the compiler. At -O, the compiler
will generate the specified specializations and emit calls to the
specialized code in the original generic function guarded by type
checks.
The current attribute is designed to be an internal tool for
performance experimentation. It does not affect the language or
API. This work may be extended in the future to add user-visible
attributes that do provide API guarantees and/or direct dispatch to
specialized code.
This attribute works on any generic function: a freestanding function
with generic type parameters, a nongeneric method declared in a
generic class, a generic method in a nongeneric class or a generic
method in a generic class. A function's generic signature is a
concatenation of the generic context and the function's own generic
type parameters.
e.g.
struct S<T> {
var x: T
@_specialize(Int, Float)
mutating func exchangeSecond<U>(u: U, _ t: T) -> (U, T) {
x = t
return (u, x)
}
}
// Substitutes: <T, U> with <Int, Float> producing:
// S<Int>::exchangeSecond<Float>(u: Float, t: Int) -> (Float, Int)
---
[SILOptimizer] Introduce an eager-specializer pass.
This pass finds generic functions with @_specialized attributes and
generates specialized code for the attribute's concrete types. It
inserts type checks and guarded dispatch at the beginning of the
generic function for each specialization. Since we don't currently
expose this attribute as API and don't specialize vtables and witness
tables yet, the only way to reach the specialized code is by calling
the generic function which performs the guarded dispatch.
In the future, we can build on this work in several ways:
- cross module dispatch directly to specialized code
- dynamic dispatch directly to specialized code
- automated specialization based on less specific hints
- partial specialization
- and so on...
I reorganized and refactored the optimizer's generic utilities to
support direct function specialization as opposed to apply
specialization.
Temporarily reverting @_specialize because stdlib unit tests are
failing on an internal branch during deserialization.
This reverts commit e2c43cfe14, reversing
changes made to 9078011f93.
This attribute can be attached to generic functions. The attribute's
arguments must be a list of concrete types to be substituted in the
function's generic signature. Any number of specializations may be
associated with a generic function.
This attribute provides a hint to the compiler. At -O, the compiler
will generate the specified specializations and emit calls to the
specialized code in the original generic function guarded by type
checks.
The current attribute is designed to be an internal tool for
performance experimentation. It does not affect the language or
API. This work may be extended in the future to add user-visible
attributes that do provide API guarantees and/or direct dispatch to
specialized code.
This attribute works on any generic function: a freestanding function
with generic type parameters, a nongeneric method declared in a
generic class, a generic method in a nongeneric class or a generic
method in a generic class. A function's generic signature is a
concatenation of the generic context and the function's own generic
type parameters.
e.g.
struct S<T> {
var x: T
@_specialize(Int, Float)
mutating func exchangeSecond<U>(u: U, _ t: T) -> (U, T) {
x = t
return (u, x)
}
}
// Substitutes: <T, U> with <Int, Float> producing:
// S<Int>::exchangeSecond<Float>(u: Float, t: Int) -> (Float, Int)
It appears we were only using this to see if an associated type was
derived or defaulted. This code didn't mesh well with the other stuff
I was doing for default implementations, so I'd rather rip it out and
just rely on calling 'isImplicit' to check for derived associated
types instead.
Note that there's a small change of behavior -- if an associated type
is derived for one conformance, and then used as a witness in another,
we were previously only marking it as defaulted in the first one,
but now it is marked as defaulted in both. I do not believe this has
any meaningful consequences.
There's an immediate need for this in the core libs, and we have most of the necessary pieces on hand to make it easy to implement. This is an unpolished initial implementation, with the following limitations, among others:
- It doesn't support bridging error conventions,
- It relies on ObjC interop,
- It doesn't check for symbol name collisions,
- It has an underscored name with required symbol name `@cdecl("symbol_name")`, awaiting official bikeshed painting.
These APIs are useful e.g. for quickly finding pre-specialisations by their names.
The existence check is very light-weight and does not try to deserialize bodies of SIL functions.
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.
The two types are nearly identical, and Fixnum is only in the Swift branches of LLVM,
not in mainline LLVM.
I do want to add ++ to PointerEmbeddedInt and fix some of this ugliness, but that'll
have to go through LLVM review, so it might take a bit.
Introduce Fix-Its to aid migration from selectors spelled as string
literals ("foo:bar:", which is deprecated), as well as from
construction of Selector instances from string literals
(Selector("foo:bar"), which is still acceptable but not recommended),
to the #selector syntax. Jump through some hoops to disambiguate
method references if there are overloads:
fixits.swift:51:7: warning: use of string literal for Objective-C
selectors is deprecated; use '#selector' instead
_ = "overloadedWithInt:" as Selector
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#selector(Bar.overloaded(_:) as (Bar) -> (Int) -> ())
In the cases where we cannot provide a Fix-It to a #selector
expression, we wrap the string literal in a Selector(...) construction
to suppress the deprecation warning. These are also easily searchable
in the code base.
This also means we're doing more validation of the string literals
that go into Selector, i.e., that they are well-formed selectors and
that we know about some method that is @objc and has that
selector. We'll warn if either is untrue.
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.
And use project_box to get to the address value.
SILGen now generates a project_box for each alloc_box.
And IRGen re-uses the address value from the alloc_box if the operand of project_box is an alloc_box.
This lets the generated code be the same as before.
Other than that most changes of this (quite large) commit are straightforward.
Since resilience is a property of the module being compiled,
not decls being accessed, we need to record which types are
resilient as part of the module.
Previously we would only ever look at the @_fixed_layout
attribute on a type. If the flag was not specified, Sema
would slap this attribute on every type that gets validated.
This is wasteful for non-resilient builds, because there
all types get the attribute. It was also apparently wrong,
and I don't fully understand when Sema decides to validate
which decls.
It is much cleaner conceptually to just serialize this flag
with the module, and check for its presence if the
attribute was not found on a type.
Introduce a new attribute, swift3_migration, that lets us describe the
transformation required to map a Swift 2.x API into its Swift 3
equivalent. The only transformation understood now is "renamed" (to
some other declaration name), but there's a message field where we can
record information about other changes. The attribute can grow
somewhat (e.g., to represent parameter reordering) as we need it.
Right now, we do nothing but store and validate this attribute.
As part of this, use a different enum for parsed generic requirements.
NFC except that I noticed that ASTWalker wasn't visiting the second
type in a conformance constraint; fixing this seems to have no effect
beyond producing better IDE annotations.
This eliminates some minor overheads, but mostly it eliminates
a lot of conceptual complexity due to the overhead basically
appearing outside of its context.
The main idea here is that we really, really want to be
able to recover the protocol requirement of a conformance
reference even if it's abstract due to the conforming type
being abstract (e.g. an archetype). I've made the conversion
from ProtocolConformance* explicit to discourage casual
contamination of the Ref with a null value.
As part of this change, always make conformance arrays in
Substitutions fully parallel to the requirements, as opposed
to occasionally being empty when the conformances are abstract.
As another part of this, I've tried to proactively fix
prospective bugs with partially-concrete conformances, which I
believe can happen with concretely-bound archetypes.
In addition to just giving us stronger invariants, this is
progress towards the removal of the archetype from Substitution.
If a global variable in a module we are compiling has a type containing
a resilient value type from a different module, we don't know the size
at compile time, so we cannot allocate storage for the global statically.
Instead, we will use a buffer, just like alloc_stack does for archetypes
and resilient value types.
This adds a new SIL instruction but does not yet make use of it.
Having a separate address and container value returned from alloc_stack is not really needed in SIL.
Even if they differ we have both addresses available during IRGen, because a dealloc_stack is always dominated by the corresponding alloc_stack in the same function.
Although this commit quite large, most changes are trivial. The largest non-trivial change is in IRGenSIL.
This commit is a NFC regarding the generated code. Even the generated SIL is the same (except removed #0, #1 and @local_storage).
A protocol conformance needs to know what declarations satisfy requirements;
these are called "witnesses". For a value (non-type) witness, this takes the
form of a ConcreteDeclRef, i.e. a ValueDecl plus any generic specialization.
(Think Array<Int> rather than Array<T>, but for a function.)
This information is necessary to compile the conformance, but it causes
problems when the conformance is used from other modules. In particular,
the type used in a specialization might itself be a generic type in the
form of an ArchetypeType. ArchetypeTypes can't be meaningfully used
outside their original context, however, so this is a weird thing to
have to deal with. (I'm not going to go into when a generic parameter is
represented by an ArchetypeType vs. a GenericTypeParamType, partially
because I don't think I can explain it well myself.)
The above issue becomes a problem when we go to use the conformance from
another module. If module C uses a conformance from module B that has a
generic witness from module A, it'll think that the archetypes in the
specialization for the witness belong in module B. Which is just wrong.
It turns out, however, that no code is using the full specializations for
witnesses except for when the conformance is being compiled and emitted.
So this commit sidesteps the problem by just not serializing the
specializations that go with the ConcreteDeclRef for a value witness.
This doesn't fix the underlying issue, so we should probably still see
if we can either get archetypes from other contexts out of value witness
ConcreteDeclRefs, or come up with reasonable rules for when they're okay
to use.
rdar://problem/23892955
Under -enable-infer-default-arguments, the Clang importer infers some
default arguments for imported declarations. Rather than jumping
through awful hoops to make sure that we create default argument
generators (which will likely imply eager type checking), simply
handle these cases as callee-side expansions.
This makes -enable-infer-default-arguments usable, fixing
rdar://problem/24049927.
This is something that we have wanted for a long time and will enable us to
remove some hacks from the compiler (i.e. how we determine in the ARC optimizer
that we have "fatalError" like function) and also express new things like
"noarc".