Commit Graph

24 Commits

Author SHA1 Message Date
John McCall
12b8a92e9d In generic functions, derive local type data for associated types
from the witness tables for their associations rather than passing
them separately.

This drastically reduces the number of physical arguments required
to invoke a generic function with a complex protocol hierarchy.  It's
also an important step towards allowing recursive protocol
constraints.  However, it may cause some performance problems in
generic code that we'll have to figure out ways to remediate.

There are still a few places in IRGen that rely on recursive eager
expansion of associated types and protocol witnesses.  For example,
passing generic arguments requires us to map from a dependent type
back to an index into the all-dependent-types list in order to
find the right Substitution; that's something we'll need to fix
more generally.  Specific to IRGen, there are still a few abstractions
like NecessaryBindings that use recursive expansion and are therefore
probably extremely expensive under this patch; I intend to fix those
up in follow-ups to the greatest extent possible.

There are also still a few things that could be made lazier about
type fulfillment; for example, we eagerly project the dynamic type
metadata of class parameters rather than waiting for the first place
we actually need to do so.  We should be able to be lazier about
that, at least when the parameter is @guaranteed.

Technical notes follow.  Most of the basic infrastructure I set up
for this over the last few months stood up, although there were
some unanticipated complexities:

The first is that the all-dependent-types list still does not
reliably contain all the dependent types in the minimized signature,
even with my last patch, because the primary type parameters aren't
necessarily representatives.  It is, unfortunately, important to
give the witness marker to the primary type parameter because
otherwise substitution won't be able to replace that parameter at all.
There are better representations for all of that, but it's not
something I wanted to condition this patch on; therefore, we have to
do a significantly more expensive check in order to figure out a
dependent type's index in the all-dependent-types list.

The second is that the ability to add requirements to associated
types in protocol refinements means that we have to find the *right*
associatedtype declaration in order to find the associated witness
table.  There seems to be relatively poor AST support for this
operation; maybe I just missed it.

The third complexity (so far) is that the association between an
archetype and its parent isn't particularly more important than
any other association it has.  We need to be able to recover
witness tables linked with *all* of the associations that lead
to an archetype.  This is, again, not particularly well-supported
by the AST, and we may run into problems here when we eliminate
recursive associated type expansion in signatures.

Finally, it's a known fault that this potentially leaves debug
info in a bit of a mess, since we won't have any informaton for
a type parameter unless we actually needed it somewhere.
2016-02-22 01:02:31 -08: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
Zach Panzarino
e3a4147ac9 Update copyright date 2015-12-31 23:28:40 +00:00
practicalswift
22e10737e2 Fix typos 2015-12-26 01:19:40 +01:00
practicalswift
6e3b700b44 Fix typos. 2015-12-23 00:31:13 +01: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
Slava Pestov
9ee10e7d39 IRGen: destructiveProjectEnumData() value witness doesn't need a return value
The rest of the runtime assumes the payload starts at the beginning
of the enum, so simplify some code by removing the return value here.
2015-11-30 13:32:55 -08:00
Joe Groff
ec61fa4c5a IRGen/Runtime: Use only the 'layout' subset of the vwtable to perform value type layout.
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
2015-07-16 15:38:17 +00:00
Ted Kremenek
a3d88266b2 Revert "IRGen/Runtime: Use only the 'layout' subset of the vwtable to perform value type layout."
This reverts commit r30243.

This appears to be breaking the Linux build.

Swift SVN r30253
2015-07-16 06:28:24 +00:00
Joe Groff
2641d566ac IRGen/Runtime: Use only the 'layout' subset of the vwtable to perform value type layout.
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
2015-07-16 01:28:42 +00:00
Slava Pestov
cdd5a4121c IRGen: Generate value witnesses to get enum tag and project payload
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
2015-07-15 06:03:18 +00:00
Joe Groff
feebd56bf4 IRGen: Reorder the extra inhabitant value witnesses so that the count and flags go first.
This nicely gathers all the layout information together in one contiguous bundle we can potentially emit independently for use in generic type layout. A step on the way to rdar://problem/19898165.

Swift SVN r30128
2015-07-12 01:06:15 +00:00
Joe Groff
7d1e60e253 IRGen/Runtime: Agree on which flag bit means "isNotBitwiseTakable" again.
Somehow this got out of sync, and IRGen's idea of which flag it was collided with "hasExtraInhabitants", causing hilarity to ensue whenever weak or protocol types were packed in optionals. Fixes rdar://problem/17814752.

Swift SVN r21803
2014-09-09 05:07:17 +00:00
John McCall
584795e505 Replace the typeOf value witness with an
initializeBufferWithTakeOfBuffer value witness.

Attempt to use initializeBufferWithTakeOfBuffer in
some appropriate places.

There are some changes enabled by this which are
coming in a follow-up patch.

Swift SVN r20741
2014-07-30 08:24:12 +00:00
Joe Groff
71678b4bdf IRGen/Runtime: Expose the 'isBitwiseTakable' bit in the value witness flags.
Set a bit for types that are non-bitwise-takable, and calculate it as part of runtime struct and enum layout. Include 'bitwise takable' as part of the runtime 'is inline' calculation to be consistent with the compile-time policy change in r17008.

Swift SVN r17036
2014-04-29 15:23:14 +00:00
Joe Groff
f29a156e83 IRGen/Runtime: Add value witness slots for array witnesses.
Add value witnesses for destroyArray, initializeArrayWithCopy, and initializeArrayWithTake{FrontToBack,BackToFront}, and fill out the runtime value witness table implementations. Stub out the IRGen ones for now.

Swift SVN r16772
2014-04-24 22:25:26 +00:00
Joe Groff
e109124186 Replace 'union' keyword with 'enum'.
This only touches the compiler and tests. Doc updates to follow.

Swift SVN r8478
2013-09-20 01:33:14 +00:00
Joe Groff
a94489473c IRGen: Add ValueWitness enumerators for union layout and access.
These value witness table entries will be conditionally available for types that support specialized union representation through extra inhabitants and/or spare bits and for union value witnesses:

- storeExtraInhabitant, to store an extra inhabitant representation;
- getExtraInhabitantIndex, to recognize an extra inhabitant representation;
- getUnionTag, to get a union's discriminator; and
- inplaceProjectUnionData, to extract the value in place from a union.

This just sets up the enumerators and related IR types and mangling; nothing emits these witnesses yet.

Swift SVN r7234
2013-08-14 21:01:21 +00:00
John McCall
757c0ae304 Track whether a type is POD and whether it uses inline or allocated
storage in a flags word in the value witness table.  Pack the
alignment into only 16 bits of this word.  Optimize tuple value
witnesses based on whether they're POD and inline.

Swift SVN r5138
2013-05-10 06:16:33 +00:00
John McCall
d8cdb0160f Switch IR-generation to generally traffic in alignment
masks rather than raw alignments.

Swift SVN r5136
2013-05-10 06:16:28 +00:00
Joe Groff
08b6f87524 Add 'typeof' to value witness tables.
To be able to get the dynamic type of a generic value, the 'typeof' operation needs to be part of the value witness for the type. Add 'typeof' to the value witness table layout, and in the runtime, provide standard typeof witnesses for static, Swift class, and ObjC class values.

Swift SVN r5013
2013-05-01 18:49:25 +00:00
John McCall
ce7ddef710 Change value witnesses to take the metatype as 'self'.
The motivations here are that (1) the parametric types
that actually need the 'self' argument don't necessarily
all want to do what tuples do and put the VWT relative
to the metatype at some definable offset and (2)
recovering type parameters from the metatype is much
better defined than also hopping some relationship back.
Plus this allows VWTs to be shared across instances of
generic types.  Also, I'm going to need to add a VW
that takes a metatype, and consistency seems right here.

If keeping two values live is actually punishing, I
might have to reconsider this.  But the VWT is at least
always recoverable from the metatype, so....

I ended up abstracting the thing that GenHeap was doing
in order to save archetypes for arrays, because I
needed it to save metatypes instead of VWTs and because
it really needed abstractin'.

Swift SVN r3096
2012-10-31 08:09:33 +00:00
John McCall
8499117b59 The value witnesses for size/alignment/stride can just be size_t's.
This requires us to potentially copy the value witness tables for
generic struct types as part of computing layout, but that's not
the end of the world (although it will rely on a future patch
to split value witnesses out from protocol witness tables).

Oh, and add a value witness for stride, changing Builtin.strideof
to use that.

Swift SVN r2829
2012-09-06 08:23:14 +00:00
John McCall
85bdae402e Restructure code to permit protocols to be converted independently
of a ProtocolType.

Swift SVN r2242
2012-06-25 20:45:00 +00:00