Resilient enums are manipulated as opaque values.
Clients are still allowed to assume physical case indices and case
payload types for now -- we might add a level of indirection here,
which would require designing a new case dispatch mechanism.
Resilient enums are never constructed directly, only by calling
case constructor functions. Case constructors already get emitted,
however they're [transparent] -- this will change in a subsequent
patch.
We could save on code size by emitting an InjectEnumTag value
witness function that can construct any case given a physical case
number, rather than emitting constructors for each case, but for
now going through case constructor functions will suffice.
The previous patch added an assert, but it turns out we could still
end up in this code path if the payload was fixed-size *and*
address-only. This is not a very common case, so don't try to
optimize it.
In the indirect initializeWithCopy value witness, we had a
terrible hack where the *source* of the initialization was
modified, stripping and emplacing the tag bits before and
after the copy of the payload, respectively.
Since address-only types should not have spare bits at all,
replace the hack with an assertion.
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.
We were calling hasTypeParameter() on the interface type of the enum
element. Since enum elements are case constructors now, the interface
type was a GenericFunctionType, and since conceptually these cannot
contain free type variables, this would always return to false.
The right fix here is to pass down the unsubstituted type info and
look at the spare bits of that when doing multi-payload enum layout.
Now that this works, we can remove a FIXME that was added to patch
around this.
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.
Replace isSingle{Unknown,Swift}ReferenceCountedObject() with a single
entry point that also returns the reference counting style. Use this
in GenEnum to emit more specific entry points than native and unknown.
This will give a slight performance boost on Darwin, and enable use of
the blocks runtime on Linux.
Progress on <rdar://problem/23315750>.
Fixes two issues with the original patch:
- If numCaseBits was >= 32, the high bits of the tag were shifted
by an incorrect amount. In this case, the high bits were always
zero anyway, but the invalid shift triggered an assertion in
ARM64 codegen. Fixed to not generate the offending instructions
at all, since just loading the payload value is enough.
- When the payload is very small, the number of no-payload cases
could be greater than 2**payloadBits, requiring multiple payload
tags to represent them all. There was an arithmetic error in
this case.
This re-applies r31328.
Swift SVN r31365
The payload tag discriminates between payload cases, but empty cases
are stored in the common spare bits of the payload types, so the logic
here would report all empty cases as having the first empty case selected.
And when writing tests, I didn't cover enums with multiple empty *and*
non-empty cases. Oops...
Now we emit a little bit more code to assemble the correct case index
from both the payload tag and payload value, then select between the
two values depending on the payload tag.
Fixes <rdar://problem/22192074>.
Swift SVN r31328
We can still produce an undefined address for the empty value, even though we considered them as no-payload cases for layout purposes. Fixes rdar://problem/21515490.
Swift SVN r30490
Full type metadata isn't necessary to calculate the runtime layout of a dependent struct or enum; we only need the non-function data from the value witness table (size, alignment, extra inhabitant count, and POD/BT/etc. flags). This can be generated more efficiently than the type metadata for many types--if we know a specific instantiation is fixed-layout, we can regenerate the layout information, or if we know the type has the same layout as another well-known type, we can get the layout from a common value witness table. This breaks a deadlock in most (but not all) cases where a value type is recursive using classes or fixed-layout indirected structs like UnsafePointer. rdar://problem/19898165
This time, factor out the ObjC-dependent parts of the tests so they only run with ObjC interop.
Swift SVN r30266
Full type metadata isn't necessary to calculate the runtime layout of a dependent struct or enum; we only need the non-function data from the value witness table (size, alignment, extra inhabitant count, and POD/BT/etc. flags). This can be generated more efficiently than the type metadata for many types--if we know a specific instantiation is fixed-layout, we can regenerate the layout information, or if we know the type has the same layout as another well-known type, we can get the layout from a common value witness table. This breaks a deadlock in most (but not all) cases where a value type is recursive using classes or fixed-layout indirected structs like UnsafePointer. rdar://problem/19898165
Swift SVN r30243
In the case where there is a single tag bit and extra inhabitants, we
generate a conditional branch, but we weren't emitting both destination
blocks.
Fixes rdar://problem/21742335.
Swift SVN r30228
These will be used for reflection, and eventually to speed up generic
operations on single payload enums as well.
Progress on <rdar://problem/21739870>.
Swift SVN r30214
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
We were crashing grabbing the extra inhabitant mask, which does not
always exist. Instead, test to see if there are extra inhabitants and
only use that mask in the comparison if there are in fact extra
inhabitants in the enum layout.
Fixes rdar://problem/21514065.
Swift SVN r29662
If an enum has only a single tag bit, emit a cond_br instead of a switch, and if it has only one no-payload case, jump directly to the destination for that case instead of wasting time testing the bit pattern and branching to unreachable. Fixes rdar://problem/21093111.
Reapplying now that Adrian fixed the debug info issue this exposed.
Swift SVN r29202
This may be the cause of a crash and burn on the iOS builders:
Assertion failed: (Offset <= PieceOffset && "overlapping or duplicate pieces"), function finalize
Swift SVN r29027
If an enum has only a single tag bit, emit a cond_br instead of a switch, and if it has only one no-payload case, jump directly to the destination for that case instead of wasting time testing the bit pattern and branching to unreachable. Fixes rdar://problem/21093111.
Swift SVN r29023
The Linux assert() is apparently doing a positive test on the value,
whereas the Darwin assert() is negating it.
APInt has an operator!(), but APInt cannot be implicitly converted to a
bool, so directly testing the value caused issues only on the Linux
build.
JoeG says the asserts were testing pointer nullness before his recent
representation changes, and aren't meaningful with the new
representation, so they should just be removed.
Swift SVN r29011
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
Don't project every value witness from the metadata every time we need one; this wastes code size in a way LLVM can't really optimize since it doesn't know the metadata is immutable. The code size wins on the standard library are disappointingly small (stdlib only shrinks by 4KB), but this makes generic IR a lot more compact and easier to read.
Swift SVN r28095
Preparation to fix <rdar://problem/18151694> Add Builtin.checkUnique
to avoid lost Array copies.
This adds the following new builtins:
isUnique : <T> (inout T[?]) -> Int1
isUniqueOrPinned : <T> (inout T[?]) -> Int1
These builtins take an inout object reference and return a
boolean. Passing the reference inout forces the optimizer to preserve
a retain distinct from what’s required to maintain lifetime for any of
the reference's source-level copies, because the called function is
allowed to replace the reference, thereby releasing the referent.
Before this change, the API entry points for uniqueness checking
already took an inout reference. However, after full inlining, it was
possible for two source-level variables that reference the same object
to appear to be the same variable from the optimizer's perspective
because an address to the variable was longer taken at the point of
checking uniqueness. Consequently the optimizer could remove
"redundant" copies which were actually needed to implement
copy-on-write semantics. With a builtin, the variable whose reference
is being checked for uniqueness appears mutable at the level of an
individual SIL instruction.
The kind of reference count checking that Builtin.isUnique performs
depends on the argument type:
- Native object types are directly checked by reading the
strong reference count:
(Builtin.NativeObject, known native class reference)
- Objective-C object types require an additional check that the
dynamic object type uses native swift reference counting:
(Builtin.UnknownObject, unknown class reference, class existential)
- Bridged object types allow the dymanic object type check to be
bypassed based on the pointer encoding:
(Builtin.BridgeObject)
Any of the above types may also be wrapped in an optional. If the
static argument type is optional, then a null check is also performed.
Thus, isUnique only returns true for non-null, native swift object
references with a strong reference count of one.
isUniqueOrPinned has the same semantics as isUnique except that it
also returns true if the object is marked pinned regardless of the
reference count. This allows for simultaneous non-structural
modification of multiple subobjects.
In some cases, the standard library can dynamically determine that it
has a native reference even though the static type is a bridge or
unknown object. Unsafe variants of the builtin are available to allow
the additional pointer bit mask and dynamic class lookup to be
bypassed in these cases:
isUnique_native : <T> (inout T[?]) -> Int1
isUniqueOrPinned_native : <T> (inout T[?]) -> Int1
These builtins perform an implicit cast to NativeObject before
checking uniqueness. There’s no way at SIL level to cast the address
of a reference, so we need to encapsulate this operation as part of
the builtin.
Swift SVN r27887
Store the number of payload and no-payload cases, the case names, and a lazy case type accessor function for enums, like we do for stored properties of structs and classes. This will be useful for multi-payload runtime support, and should also be enough info to hack together a reflection implementation for enums.
For dynamic multi-payload enums to not be ridiculously inefficient, we'll need to track the size of the payload area in the enum, like we do the field offsets of generic structs and classes, so hack off a byte in the payload case count to track the offset of that field in metadata records. 16 million payloads ought to be enough for anyone, right? (and 256 words between the enum metadata's address point and the payload size offset)
Swift SVN r27789
This can come up now when generic multi-payload enums substitute in empty types for all their payloads. It's also an opportunity to factor things a bit so that they're easier to extend to dynamic cases.
Swift SVN r27783
We don't want to wait to revamp the runtime to track spare bits in order to get multi-payload enum cases working, so when lowering an enum, track when the generic enum type's layout is dependent, and constrain our use of spare bits when it is.
Swift SVN r27781
This is an internal-only affordance for the numerics team to be able to work on SIMD-compatible types. For now, it can only increase alignment of fixed-layout structs and enums; dynamic layout, classes, and other obvious extensions are left to another day when we can design a proper layout control design.
Swift SVN r27323
come up when pattern matching on optional. Instead of expanding to a
switch with a default and one case, expand to an icmp and condbr.
Swift SVN r26090