Commit Graph

167 Commits

Author SHA1 Message Date
Arnold Schwaighofer
f538dd7075 Fix Enums with multiple payloads of < 32bit and empty payloads.
This used to crash because the code storing empty payload enum tag values would
use the bit width of the tag (32 bit) as the minimum unit to store to the
payload even if the actual bits required to store the biggest tag value in the
payload was much smaller.

With payload bit-widths < 32bit we would run out of space crashing looking for
new payload to store the value to ...

Instead pass the maximum size of the bits that need storing down.

rdar://26926035
2016-07-08 11:21:30 -07:00
John McCall
06a78fd90b Don't leak EnumImplStrategy objects. 2016-06-30 15:24:03 -07:00
Slava Pestov
60dff01093 Reflection: Simplify associated type metadata emission
Instead of hooking into nominal type and extension emission
and walking all conformances of those declarations, let's
just directly hook into the logic for emitting conformances.

This fixes an issue where we would apparently emit duplicate
conformances, as well as unnecessary conformances that are
defined elsewhere.
2016-05-26 19:33:00 -07:00
John McCall
f944d9133a Teach LoadableTypeInfos how to add themselves to a SwiftAggLowering. NFC. 2016-05-03 11:14:16 -07:00
David Farler
a1ff1e6a7b Eagerly emit reflection metadata as decls are emitted
Rather than collection nominal type and extension decls and emit
reflection metadata records in one go, we can emit them as they
are encountered and instead collection builtin types referenced
by those at the end.
2016-04-29 17:07:55 -07:00
John McCall
857489c2f6 When a generic type has dependent IR and thus requires each
specialization to be separately lowered in IRGen, use the mangling
of the specialized type as the name of the llvm::StructType instead
of the base, unspecialized type.

This tends to produce fewer collisions between IR type names.
LLVM does unique the names on its own, so that's not strictly
necessary, but it's still a good idea because it makes the test
output more reliable and somewhat easier to read (modulo the
impact of bigger type names).  Collisions will still occur if
the type is specialized at an archetype, since in this case we
will fall back on the unspecialized type.
2016-04-29 16:39:16 -07:00
John McCall
6c92c324f6 Rename IRGenModuleDispatcher to just IRGenerator and transfer
ownership of some of the basic structures to it.
2016-04-27 09:42:03 -07:00
Roman Levenstein
d8e28bb690 Handle the [nonatomic] attribute in IRGen and LLVM passes.
Properly lower reference counting SIL instructions with nonatomic attribute as invocations of corresponding non-atomic reference counting runtime functions.
2016-04-06 22:30:23 -07:00
Joe Groff
6ed4eba9c2 IRGen: Add missing forwarding stub in FixedEnumImplStrategy.
Without this, fixed-sized, address-only enums failed to correctly delegate their `getFixedExtraInhabitantMask` implementation to the enum layout strategy, causing a miscompile where switches would test undefined bits of the enum payload. Fixes rdar://problem/24885747.
2016-03-09 17:45:02 -08:00
David Farler
a6a5ece206 IRGen: Emit type references for remote reflection
- Implement emission of type references for nominal type field
  reflection, using a small custom encoder resulting in packed
  structs, not strings. This will let us embed 7-bit encoded
  32-bit relative offsets directly in the structure (not yet
  hooked in).
- Use the AST Mangler for encoding type references
  Archetypes and internal references were complicating this before, so we
  can take the opportunity to reuse this machinery and avoid unique code
  and new ABI.

Next up: Tests for reading the reflection sections and converting the
demangle tree into a tree of type references.

Todo: For concrete types, serialize the types for associated types of
their conformances to bootstrap the typeref substitution process.

rdar://problem/15617914
2016-02-03 13:52:26 -08:00
practicalswift
4b0571bae8 [gardening] Fix documentation typos 2016-01-24 12:52:01 +01:00
Slava Pestov
34a4075116 IRGen: Implement resilient enum case numbering
Recent changes added support for resiliently-sized enums, and
enums resilient to changes in implementation strategy.

This patch adds resilient case numbering, fixing the problem
where adding new payload cases would break existing code by
changing the numbering of no-payload cases.

The problem is that internally, enum cases are numbered with payload
cases coming first, followed by no-payload cases. While each list
is itself in declaration order, with new additions coming at the
end, we need to partition it to give us a fast runtime test for
"is this a payload or no-payload case index."

The resilient numbering strategy used here is that the getEnumTag
and destructiveInjectEnumTag value witness functions now take a
tag index in the range [-ElementsWithPayload..ElementsWithNoPayload-1].

Payload elements are numbered in *reverse* declaration order, so
adding new payload cases yields decreasing tag indices, and adding
new no-payload cases yields increasing tag indices, allowing use
sites to be resilient.

This adds the adjustment between 'fragile' and 'resilient' tag
indices in a somewhat unsatisfying manner, because the calculation
could be pushed down further into EnumImplStrategy, simplifying
both the IRGen code and the generated IR. I'll clean this up later.

In the meantime, clean up some other stuff in GenEnum.cpp, mostly
abstracting code that walks cases.
2016-01-21 12:10:57 -08:00
Joe Groff
638e4b0984 IRGen/Runtime: Use relative addresses in nominal type descriptors.
Decrease the size of nominal type descriptors and make them true-const by relative-addressing the other metadata they need to reference, which should all be included in the same image as the descriptor itself. Relative-referencing string constants exposes a bug in the Apple linker, which crashes when resolving relative relocations to coalesceable symbols (rdar://problem/22674524); work around this for now by revoking the `unnamed_addr`-ness of string constants that we take relative references to. (I haven't tested whether GNU ld or gold also have this problem on Linux; it may be possible to conditionalize the workaround to only apply to Darwin targets for now.)
2016-01-20 14:41:53 -08:00
John McCall
1d3916e6ad Add virtual methods to TypeInfo to do all the buffer operations.
Use them to generate value witnesses when the type has dynamic packing.
Regularize the interface for calling value witnesses.

Not a huge difference yet, although we do re-use local type data
a little more effectively now.
2016-01-14 20:05:44 -08:00
Slava Pestov
33ed1e0ab6 IRGen: Add ResilienceExpansion parameter to TypeInfo::isKnownEmpty(), NFC
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.
2016-01-08 19:56:01 -08:00
Slava Pestov
1eb1a8508e IRGen: StorageType doesn't need to be public, we already have an accessor for it, NFC 2016-01-07 14:33:15 -08:00
Slava Pestov
7faf90a787 IRGen: Replace ResilienceScope enum with AST's ResilienceExpansion, NFC 2016-01-07 08:29:23 -08:00
John McCall
9cd96ce600 Refine the use and behavior of ConditionalDominanceScope.
Instead of categorically forbidding caching within a conditional
scope, permit it but remember how to remove the cache entries.
This means that ad-hoc emission code can now get exactly the
right caching behavior if they use this properly.  In keeping
with that, adjust a bunch of code to properly nest scopes
according to the conditional paths they enter.
2016-01-06 00:24:22 -08:00
John McCall
7dd9f5f037 Improve IRGen's infrastructure for caching local type data.
There are several interesting new features here.

The first is that, when emitting a SILFunction, we're now able to
cache type data according to the full dominance structure of the
original function.  For example, if we ask for type metadata, and
we've already computed it in a dominating position, we're now able
to re-use that value; previously, we were limited to only doing this
if the value was from the entry block or the LLVM basic block
matched exactly.  Since this tracks the SIL dominance relationship,
things in IRGen which add their own control flow must be careful
to suppress caching within blocks that may not dominate the
fallthrough; this mechanism is currently very crude, but could be
made to allow a limited amount of caching within the
conditionally-executed blocks.

This query is done using a proper dominator tree analysis, even at -O0.
I do not expect that we will frequently need to actually build the
tree, and I expect that the code-size benefits of doing a real
analysis will be significant, especially as we move towards making
more metadata lazily computed.

The second feature is that this adds support for "abstract"
cache entries, which indicate that we know how to derive the metadata
but haven't actually done so.  This code isn't yet tested, but
it's going to be the basis of making a lot of things much lazier.
2016-01-05 17:55:51 -08:00
practicalswift
50baf2e53b Use consistent formatting in top of file headers. 2016-01-04 02:17:48 +01:00
Zach Panzarino
e3a4147ac9 Update copyright date 2015-12-31 23:28:40 +00:00
practicalswift
fa0b339a21 Fix typos. 2015-12-26 17:51:59 +01:00
Slava Pestov
54b22f4455 Re-apply "IRGen: Make case numbering consistent for enums with empty payloads"
Now with a small fix.
2015-12-22 00:17:00 -08:00
Slava Pestov
6c2d8839ec Speculatively revert "IRGen: Make case numbering consistent for enums with empty payloads"
I suspect its breaking the build. I must've screwed up my testing.

This reverts commit 86e6b81336.
2015-12-21 14:50:16 -08:00
Slava Pestov
86e6b81336 IRGen: Make case numbering consistent for enums with empty payloads
If an enum case has a payload but the unsubstituted payload type is
zero-sized, we would convert the case into a no-payload case.
This was valid when the only invariant that had to be preserved
is that an enum's layout is the same between all substitutions
of a generic type.

However this is now wrong if the payload type is resiliently-sized,
because other resilience domains may not have knowledge that it is
zero-sized.

The new utility methods will also be used in class layout.
2015-12-21 13:50:24 -08:00
Slava Pestov
d972f6329a IRGen: Tighten up enum fixed-layout optimizations a bit
If an enum is public and @_fixed_layout, we can only use fixed-size
optimizations if the payload types are fixed-size in all resilience
domains.

However, if an enum is resilient or internal to a module, other
resilience domains cannot have knowledge of its layout, so we can
still use fixed-size optimizations if the payload types are known
to be fixed-size in the current resilience domain only.
2015-12-20 16:57:23 -08:00
Slava Pestov
304f4f051f IRGen: Fix for fixed-layout enum with resilient payload
If an enum is fixed-layout in our resilience domain but not
universally fixed-layout, other resilience domains will use
runtime functions to project and inject payloads.

These expect to find the payload size in the metadata, so
emit it if the enum is not universally fixed-layout.

Note that we do know the payload size, so it is constant
for us; there's no runtime call required to initialize
the metadata.
2015-12-19 00:47:47 -08:00
Mark Lacey
1970f137ad Reapply "IRGen: Fix select_enum for single-payload, multi-empty-case enums."
This reapplies 8643d14 with a test update to change the data type to
Int32 so that it will pass on 32- and 64-bit targets with the same IR
generated.
2015-12-17 08:40:51 -08:00
Mark Lacey
997f6d4103 Revert "Reapply "IRGen: Fix select_enum for single-payload, multi-empty-case enums.""
This reverts commit 299a5681ea because it
looks like the test is broken for the iphonesimulator-i386 target.
2015-12-16 21:32:40 -08:00
Mark Lacey
299a5681ea Reapply "IRGen: Fix select_enum for single-payload, multi-empty-case enums."
This reapplies 8643d14. It was speculatively reverted in e3256c8 due
to the concern that it might have been the cause of a build break.
2015-12-16 17:08:51 -08:00
Ted Kremenek
e3256c8626 Revert "IRGen: Fix select_enum for single-payload, multi-empty-case enums."
Speculatively revert commit 8643d146a0 because
it appears to be the likely culprit breaking tests on iOS.
2015-12-15 21:15:06 -08:00
Joe Groff
8643d146a0 IRGen: Fix select_enum for single-payload, multi-empty-case enums.
If the payload has insufficient extra inhabitants and there's more than one empty case that requires spilling extra tag bits, we need to check the payload part of the value to discriminate them.
2015-12-15 18:59:27 -08:00
Joe Groff
fd457fb343 Revert "IRGen/Runtime: Use relative addresses in nominal type descriptors."
This reverts commit fbb832665a. It causes LLVM to complain with
"Cannot represent a subtraction with a weak symbol" when targeting Linux.
2015-12-11 15:41:11 -08:00
Joe Groff
fbb832665a IRGen/Runtime: Use relative addresses in nominal type descriptors.
Decrease the size of nominal type descriptors and make them true-const by relative-addressing the other metadata they need to reference, which should all be included in the same image as the descriptor itself. Relative-referencing string constants exposes a bug in the Apple linker, which crashes when resolving relative relocations to coalesceable symbols (rdar://problem/22674524); work around this for now by revoking the `unnamed_addr`-ness of string constants that we take relative references to. (I haven't tested whether GNU ld or gold also have this problem on Linux; it may be possible to conditionalize the workaround to only apply to Darwin targets for now.)
2015-12-11 15:21:12 -08:00
Slava Pestov
2adabe500b IRGen: Fix incorrect conditional in multi-payload destructiveInjectEnumTag() witness
We were checking if the tag was <= numPayloadCases, not <. Fix this
and swap the order of the basic blocks so that the no-tag case is
the fall through for consistency with getEnumTag().
2015-12-11 08:58:51 -08:00
Slava Pestov
d47cded505 IRGen: Implement ResilientEnumImplStrategy::getSchema()
Turns out this is also used for address-only types.
2015-12-10 22:25:30 -08:00
Slava Pestov
11b8bcfa70 IRGen: Actually construct resilient enums using the new destructiveInjectEnumTag() value witness
This completes the ResilientEnumImplStrategy implementation in IRGen.
2015-12-10 21:04:04 -08:00
Slava Pestov
65a5a03f26 IRGen: Add a new destructiveInjectEnumTag value witness function
This value witness function takes an address of an enum value where the
payload has already been initialized, together with a case index, and
forms the enum value.

The formal behavior can be thought of as satisfying an identity in
relation to the existing two enum value witnesses. For any enum
value, the following is to leave the value unchanged:

  tag = getEnumTag(value)
  destructiveProjectEnumData(value)
  destructiveInjectEnumData(value, tag)

This is the last missing piece for the inject_enum_addr SIL instruction
to handle resilient enums, allowing the implementation of an enum to be
decoupled from its uses. Also, it should be useful for dynamically
constructing enum cases with write reflection, once we get around to
doing such a thing.

The body of the value witness is emitted by a new emitStoreTag() method
on EnumImplStrategy. This is similar to the existing storeTag(), except
the case index is a value instead of a contant.

This is implemented as follows for the different enum strategies:

1) For enums consisting of a single case, this is trivial.

2) For enums where all cases are empty, stores the case index into the
   payload area.

3) For enums with a single payload case, emits a call to a runtime
   function. Note that for non-generic single payload enums, this could
   be open-coded more efficiently, but the function still has the
   correct behavior since it supports extra inhabitants and so on.
   A follow-up patch will make this more efficient.

4) For multi-payload enums, there are two cases:

   a) If one of the payloads is generic or resilient, the enum is
      dynamically-sized, and a call to a runtime function is emitted.

   b) If the entire enum is fixed-size, the value witness checks if
      the case is empty or not.

      If the case has a payload, the case index is swizzled into
      spare bits of the payload, if any, with remaining bits going
      into the extra tag area.

      If the case is empty, the case index is swizzled into the
      spare bits of the payload, the remaining bits of the payload,
      and the extra tag area.

The implementations of emitStoreTag() duplicate existing logic in the
enum strategies, in particular case 4)b) is rather complicated.

Code cleanups are welcome here!
2015-12-08 15:43:55 -08:00
John McCall
4d1b6e2eb6 Reform the runtime interface for unowned reference-counting.
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.
2015-12-04 13:18:14 -08:00
Slava Pestov
ca7254c53d IRGen: Preliminary support for resilient enums
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.
2015-11-30 13:32:55 -08:00
Slava Pestov
c06f3353c9 IRGen: Remove unused IGM parameter from some methods on EnumImplStrategy, NFC
We already stash the IRGenModule in an instance variable.
2015-11-30 13:32:55 -08:00
Slava Pestov
f98cd04853 IRGen: Don't use spare bits in address-only payloads
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.
2015-11-18 23:34:07 -08:00
Slava Pestov
1f726fe87f IRGen: Address-only enums should not use spare bits for layout
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.
2015-11-18 18:20:54 -08:00
Slava Pestov
6c2d5b1b6c IRGen: GenEnum.cpp cleanups, NFC
- Better comment at top of file
- Factor out common projectDataForStore() and
  destructivelyProjectDataForLoad() implementations
- Formatting cleanups
2015-11-18 18:20:54 -08:00
Slava Pestov
5fa9a7dc6d IRGen: Multi-payload enums only use spare bits if payloads are universally fixed-size
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.
2015-11-16 16:34:56 -08:00
Slava Pestov
7237098fe1 IRGen: Clean up class archetype spare bits hack
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.
2015-11-15 15:20:39 -08:00
Slava Pestov
1adf7534d7 IRGen: Collapse down ResilienceScope enum
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.
2015-11-13 17:56:17 -08:00
Slava Pestov
aa40f206cb IRGen: optionals of blocks now use block reference counting entry points
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>.
2015-11-05 01:33:15 -08:00
Slava Pestov
07df0fbc52 Re-apply "IRGen: Fix stupid oversight in emission of fixed multi-payload enum vw_getEnumTag()"
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
2015-08-20 21:19:27 +00:00
Ted Kremenek
0188a69963 Revert "IRGen: Fix stupid oversight in emission of fixed multi-payload enum vw_getEnumTag()"
This appears to be breaking the ARM64 iOS build.

Swift SVN r31335
2015-08-19 07:29:09 +00:00