@@ -4799,6 +4799,71 @@ eliminated. However, a memory location ``%a`` must not be accessed
4799
4799
after ``destroy_addr %a `` (which has not yet been eliminated)
4800
4800
regardless of its type.
4801
4801
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
+
4802
4867
index_addr
4803
4868
``````````
4804
4869
::
0 commit comments