@@ -4799,6 +4799,71 @@ eliminated. However, a memory location ``%a`` must not be accessed
47994799after ``destroy_addr %a `` (which has not yet been eliminated)
48004800regardless of its type.
48014801
4802+ tuple_addr_constructor
4803+ ``````````````````````
4804+
4805+ ::
4806+
4807+ sil-instruction ::= 'tuple_addr_constructor' sil-tuple-addr-constructor-init sil-operand 'with' sil-tuple-addr-constructor-elements
4808+ sil-tuple-addr-constructor-init ::= init|assign
4809+ sil-tuple-addr-constructor-elements ::= '(' (sil-operand (',' sil-operand)*)? ')'
4810+
4811+ // %destAddr has the type $*(Type1, Type2, Type3). Note how we convert all of the types
4812+ // to their address form.
4813+ %1 = tuple_addr_constructor [init] %destAddr : $*(Type1, Type2, Type3) with (%a : $Type1, %b : $*Type2, %c : $Type3)
4814+
4815+ Creates a new tuple in memory from an exploded list of object and address
4816+ values. The SSA values form the leaf elements of the exploded tuple. So for a
4817+ simple tuple that only has top level tuple elements, then the instruction lowers
4818+ as follows::
4819+
4820+ %1 = tuple_addr_constructor [init] %destAddr : $*(Type1, Type2, Type3) with (%a : $Type1, %b : $*Type2, %c : $Type3)
4821+
4822+ -->
4823+
4824+ %0 = tuple_element_addr %destAddr : $*(Type1, Type2, Type3), 0
4825+ store %a to [init] %0 : $*Type1
4826+ %1 = tuple_element_addr %destAddr : $*(Type1, Type2, Type3), 1
4827+ copy_addr %b to [init] %1 : $*Type2
4828+ %2 = tuple_element_addr %destAddr : $*(Type1, Type2, Type3), 2
4829+ store %2 to [init] %2 : $*Type3
4830+
4831+ A ``tuple_addr_constructor `` is lowered similarly with each store/copy_addr
4832+ being changed to their dest assign form.
4833+
4834+ In contrast, if we have a more complicated form of tuple with sub-tuples, then
4835+ we read one element from the list as we process the tuple recursively from left
4836+ to right. So for instance we would lower as follows a more complicated tuple::
4837+
4838+ %1 = tuple_addr_constructor [init] %destAddr : $*((), (Type1, ((), Type2)), Type3) with (%a : $Type1, %b : $*Type2, %c : $Type3)
4839+
4840+ ->
4841+
4842+ %0 = tuple_element_addr %destAddr : $*((), (Type1, ((), Type2)), Type3), 1
4843+ %1 = tuple_element_addr %0 : $*(Type1, ((), Type2)), 0
4844+ store %a to [init] %1 : $*Type1
4845+ %2 = tuple_element_addr %0 : $*(Type1, ((), Type2)), 1
4846+ %3 = tuple_element_addr %2 : $*((), Type2), 1
4847+ copy_addr %b to [init] %3 : $*Type2
4848+ %4 = tuple_element_addr %destAddr : $*((), (Type1, ((), Type2)), Type3), 2
4849+ store %c to [init] %4 : $*Type3
4850+
4851+ This instruction exists to enable for SILGen to init and assign RValues into
4852+ tuples with a single instruction. Since an RValue is a potentially exploded
4853+ tuple, we are forced to use our representation here. If SILGen instead just uses
4854+ separate address projections and stores when it sees such an aggregate,
4855+ diagnostic SIL passes can not tell the difference semantically in between
4856+ initializing a tuple in parts or at once::
4857+
4858+ var arg = (Type1(), Type2())
4859+
4860+ // This looks the same at the SIL level...
4861+ arg = (a, b)
4862+
4863+ // to assigning in pieces even though we have formed a new tuple.
4864+ arg.0 = a
4865+ arg.1 = a
4866+
48024867index_addr
48034868``````````
48044869::
0 commit comments