This reorganization allows adding attributes that refer to types.
I need this for a @_specialize attribute with a type list.
PrintOptions.h and other headers depend on these enums. But Attr.h
defines a lot of classes that almost never need to be included.
The recent change to destructure tuples in SIL function return types
introduced some runtime changes where it was assumed that a SIL
function type like
$@convention(thin) () -> (@out X, @out Y)
Would have the same calling convention as the following C function:
void foo(void *X, void *Y);
Unfortunately, this only worked on x86-64, because the first @out
parameter in a SIL function type was lowered with the LLVM
'sret' attribute, which on i386 and ARM64 is not the same as the
first parameter to a function.
On i386, this manifested as a crash in a variety of executable tests
with a misaligned stack; on ARM64, a similar crash would occur because
the return value was initialized through the wrong register.
Hack around this by simply disabling 'sret' if a SIL function type
has multiple indirect return values.
Fixes <rdar://problem/24727411>.
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.
This is another incremental step toward protocol resilience.
To support resiliently adding requirements with default implementations,
we need to emit the witness thunk for each default requirement once,
and share it between conformances.
However, the body of the witness thunk can call witness methods from
the conformance of <Self : P>. Formerly, witness thunks were only emitted
with a concrete Self type, so any calls were resolved statically.
Now that Self can be abstract in a witness thunk signature, we have to
pass in the witness table and do the necessary gymnastics on both sides
of the call.
At the call site, the witness table is either abstract, concrete, or
undefined, as follows:
- If the unsubstituted Self type is concrete in the witness method
signature, no witness table is necessary; this is the case of a
concrete (non-default) witness thunk.
- If the unsubstituted Self type is abstract and the substituted Self
type is concrete, the witness table is accessed via direct reference.
- If the unsubstituted Self type is abstract and the substituted Self
type is also abstract, the witness table comes from type metadata
that was passed in to the function where the call is taking place.
Inside the body of the witness method thunk, we only bind the witness
table if Self is an abstract type; this rules out the first case above,
where the witness table is not needed and cannot be provided by the
caller.
The result of a SIL witness_method instruction now lowers as an
explosion containing two values, the function pointer itself and
the witness table.
Similarly, partial application thunks now grab the witness table and
package it up in the context.
Special care is taken to support function_ref + apply and
function_ref + partial_apply of @convention(witness_method) callees;
here, we can hit the case where we don't know the original conformance
because the callee is concrete, in which case we just pass in a null
pointer as the witness table.
Witness thunks with an abstract Self currently only work for protocols
without any associated type requirements; to support those, we need
to be able to fulfill associated type metadata from the witness
table for the <Self : P> conformance. This will be addressed as part
of @rjmccall's calling convention work.
Also I didn't make any attempt to support this for @objc protocols that
do not have a witness table. In this case, the extra parameter is not
necessary since we can perform dynamic dispatch on the 'self' value to
call requirements; however, @objc protocols will not support default
implementations, at least not in the near-term.
Update our usage of llvm's coverage API and fix the way we lower
instrprof_increment intrinsics.
This keeps us up-to-date with llvm/stable and makes instrumented IR
easier to read.
In the case where we generate a forwarding thunk with no polymorphic
arguments that forwards to a method that has polymorphic arguments, we
were grabbing the wrong type for the cast of the context argument. The
context argument, if there is one, should be after the polymorphic
arguments.
Fixes rdar://problem/23528633.
In a few places, we have to be careful about the distinction between
"empty in this resilience domain" versus "empty in all resilience
domains". Make callers think about this by adding a parameter instead
of relying on them to check isFixedSize() as necessary first.
While making this change I noticed that the code for checking if
types are empty when computing extra inhabitants of structs and enums
might be slightly wrong in the face of resilience; I will revisit
this later.
When enabled, generate closure functions with guaranteed conventions as their context parameters, and pass context arguments to them as guaranteed when possible. (When forming a closure by partial_apply, the partial apply still needs to take ownership of the parameters, regardless of their convention.)
This should cover most temporary buffers, except for those used by indirected value arguments, which need some cooperation with CallEmission to properly mark lifetime end after the call's completed.
when working with autoreleased result conventions, and stop
emitting autorelease_return and strong_retain_autoreleased in
SILGen.
The previous representation, in which strong_retain_autoreleased
was divorced from the call site, allowed it to "wander off" and
be cloned. This would at best would break the optimization, but
it could also lead to broken IR due to some heroic but perhaps
misguided efforts in IRGen to produce the exact required code
pattern despite the representational flaws.
The SIL pattern for an autoreleased result now looks exactly
like the pattern for an owned result in both the caller and
the callee. This should be fine as long as interprocedural
optimizations are conservative about convention mismatches.
Optimizations that don't wish to be conservative here should
treat a convention mismatch as an autorelease (if the callee
has an autoreleased result) or a retain (if the formal type
of the call has an autoreleased result).
Fixes rdar://23810212, which is an IRGen miscompile after the
optimizer cloned a strong_retain_autoreleased. There's no
point in adding this test case because the new SIL pattern
inherently prevents this transformation by construction.
The 'autorelease_return' and 'strong_retain_autoreleased'
instructions are now dead, and I will remove them in a
follow-up commit.
Modeling nonescaping captures as @inout parameters is wrong, because captures are allowed to share state, unlike 'inout' parameters, which are allowed to assume to some degree that there are no aliases during the parameter's scope. To model this, introduce a new @inout_aliasable parameter convention to indicate an indirect parameter that can be written to, not only by the current function, but by well-typed, well-synchronized aliasing accesses too. (This is unrelated to our discussions of adding a "type-unsafe-aliasable" annotation to pointer_to_address to allow for safe pointer punning.)
This is a bit of a hodge-podge of related changes that I decided
weren't quite worth teasing apart:
First, rename the weak{Retain,Release} entrypoints to
unowned{Retain,Release} to better reflect their actual use
from generated code.
Second, standardize the names of the rest of the entrypoints around
unowned{operation}.
Third, standardize IRGen's internal naming scheme and API for
reference-counting so that (1) there are generic functions for
emitting operations using a given reference-counting style and
(2) all operations explicitly call out the kind and style of
reference counting.
Finally, implement a number of new entrypoints for unknown unowned
reference-counting. These entrypoints use a completely different
and incompatible scheme for working with ObjC references. The
primary difference is that the new scheme abandons the flawed idea
(which I take responsibility for) that we can simulate an unowned
reference count for ObjC references, and instead moves towards an
address-only scheme when the reference might store an ObjC reference.
(The current implementation is still trivially takable, but that is
not something we should be relying on.) These will be tested in a
follow-up commit. For now, we still rely on the bad assumption of
reference-countability.
Handle such cases like partial applications of witness methods and applications of witness methods with substitutions.
Some of these uses-cases occur when there is a protocol defining an operator, a generic struct conforming to this protocol, and the operator conformance of this struct is expressed as a global function.
For example, if a @_fixed_layout struct A contains a resilient struct B
from the same module M, then inside M, A can have a fixed size, but
outside, A has a dynamic size because B is opaque. In this case, A is
not "universally fixed-size". This impacts multi-payload enums, because
if A is placed inside a multi-payload enum E which is lowered inside X,
we would get a fixed layout with spare bits, but lowering E outside of
X would yield a dynamic layout. This is incorrect.
Fix this by plumbing through a new predicate IsAlwaysFixedSize, which
is similar to IsPOD and IsBitwiseTakable, where a compound type inherits
the property if all leaf types exhibit it, and only use spare bits if
the original and substituted types have this property.
John and I discussed this and agreed that we only need two cases here,
not four. In the future this may be merged with ResilienceExpansion,
and become a struct with additional availability information, but
we're definitely sure we don't need four levels here.
This lets LLVM optimize out the predicate checks and initializer calls if the same global is accessed more than once in a row, and mirrors the use of __builtin_assume in the inlined code sequence of dispatch_once and os_once.
Swift SVN r32134
Bitfields are imported as computed properties with Clang-generated
accessors.
While we cannot represent them directly in SIL, we can still
synthesize a memberwise initializer, so also decouple that notion
from "has unreferenceable storage".
Fixes <rdar://problem/21702107>.
Swift SVN r31779
Previously we would ignore inout when bridging, but now we need
to take it into account for Clang-generated accessors.
Note that @block_storage must be special cased, because we always
require @inout to be specified together with @block_storage, and
@inout @block_storage is not a pointer type to some underlying
type, but rather a special block pointer type that comes directly
from the Clang AST context.
Swift SVN r31778
... by deleting some dead code. Thanks to John McCall for noting
that this entire codepath is a vestigal remnant from the days
of IRGenning directly from AST.
Fixes <rdar://problem/18406224>.
Swift SVN r31242
dealloc_ref [destructor] is the existing behavior. It expects the
reference count to have reached zero and the isDeallocating bit to
be set.
The new [constructor] variant first drops the initial strong
reference.
This allows DI to properly free uninitialized instances in
constructors. Previously this would fail with an assertion if the
runtime was built with debugging enabled.
Progress on <rdar://problem/21991742>.
Swift SVN r31142
The isDependentType() query is woefully misunderstood. Some places
seem to want it to mean "a generic type parameter of dependent member
type", which corresponds to what is effectively a type parameter in
the language, while others want it to mean "contains a type parameter
anywhere in the type". Tease out these two meanings in
isTypeParameter() and hasTypeParameter(), respectively, and sort out
the callers.
Swift SVN r29945
functions to create load/store instructions without alignment.
Fix a couple of places that were unnecessarily using this.
This includes patching up some very suspicious code for generating
"shadow copies" of explosions for debug info that's not using
the existing TypeInfo-based load/store facilities for some
reason; I left the existing pattern in place for now, but it's
probably bogus.
Swift SVN r29459
Share the code that does elementwise coercions, which already behaved correctly, with the code that does struct-to-struct coercions, which still had the overly-conservative constraint. Fixes rdar://problem/21294916.
Swift SVN r29399
@inout parameters can be nocapture and dereferenceable. @in, @in_guaranteed, and indirected @direct parameters can be noalias, nocapture, and dereferenceable.
Swift SVN r29353
if the only partially-applied argument is a Swift-refcountable
pointer. However, it doesn't require a new heap allocation,
so teach partial-application forwarding how to emit a thunk
when the only capture is directly usable as the context.
Fixes rdar://21084084.
or at least as long as we don't emit the throwing function
Swift SVN r29131
It's not worth burning more than three registers on a parameter, and doing so causes code size issues for large structs and enums. Make it so that values with more than three explosion members get passed indirectly, just like they get returned indirectly.
This time, modify emitPartialApplyForwarder not to attempt to 'tail' call the original function when indirect arguments get alloca'ed on the stack, which is UB, and don't use "byval", as suggested by John.
Swift SVN r29032
It's not worth burning more than three registers on a parameter, and doing so causes code size issues for large structs and enums. Make it so that values with more than three explosion members get passed indirectly, just like they get returned indirectly.
Swift SVN r29016
Using LLVM large integers to represent enum payloads has been causing compiler performance and code size problems with large types, and has also exposed a long tail of backend bugs. Replace them with an "EnumPayload" abstraction that manages breaking a large opaque binary value into chunks, along with masking, testing, and extracting typed data from the binary blob. For now, use a word-sized chunking schema always, though the architecture here is set up to eventually allow the use of an arbitrary explosion schema, which would benefit single-payload enums by allowing the payload to follow the explosion schema of the contained value.
This time, adjust the assertion in emitCompare not to perform a check before we've established that the payload is empty, since APInt doesn't have a 0-bit state and the default-constructed form is nondeterminisitic. (We should probably use a more-tailored representation for enum payload bit patterns than APInt or ClusteredBitVector.)
Swift SVN r28985
Using LLVM large integers to represent enum payloads has been causing compiler performance and code size problems with large types, and has also exposed a long tail of backend bugs. Replace them with an "EnumPayload" abstraction that manages breaking a large opaque binary value into chunks, along with masking, testing, and extracting typed data from the binary blob. For now, use a word-sized chunking schema always, though the architecture here is set up to eventually allow the use of an arbitrary explosion schema, which would benefit single-payload enums by allowing the payload to follow the explosion schema of the contained value.
Swift SVN r28982