@@ -2107,6 +2107,94 @@ make the use of such types more convenient; it does not shift the
2107
2107
ultimate responsibility for assuring the safety of unsafe
2108
2108
language/library features away from the user.
2109
2109
2110
+ Copy-on-Write Representation
2111
+ ----------------------------
2112
+
2113
+ Copy-on-Write (COW) data structures are implemented by a reference to an object
2114
+ which is copied on mutation in case it's not uniquely referenced.
2115
+
2116
+ A COW mutation sequence in SIL typically looks like::
2117
+
2118
+ (%uniq, %buffer) = begin_cow_mutation %immutable_buffer : $BufferClass
2119
+ cond_br %uniq, bb_uniq, bb_not_unique
2120
+ bb_uniq:
2121
+ br bb_mutate(%buffer : $BufferClass)
2122
+ bb_not_unique:
2123
+ %copied_buffer = apply %copy_buffer_function(%buffer) : ...
2124
+ br bb_mutate(%copied_buffer : $BufferClass)
2125
+ bb_mutate(%mutable_buffer : $BufferClass):
2126
+ %field = ref_element_addr %mutable_buffer : $BufferClass, #BufferClass.Field
2127
+ store %value to %field : $ValueType
2128
+ %new_immutable_buffer = end_cow_mutation %buffer : $BufferClass
2129
+
2130
+ Loading from a COW data structure looks like::
2131
+
2132
+ %field1 = ref_element_addr [immutable] %immutable_buffer : $BufferClass, #BufferClass.Field
2133
+ %value1 = load %field1 : $*FieldType
2134
+ ...
2135
+ %field2 = ref_element_addr [immutable] %immutable_buffer : $BufferClass, #BufferClass.Field
2136
+ %value2 = load %field2 : $*FieldType
2137
+
2138
+ The ``immutable `` attribute means that loading values from ``ref_element_addr ``
2139
+ and ``ref_tail_addr `` instructions, which have the *same * operand, are
2140
+ equivalent.
2141
+ In other words, it's guaranteed that a buffer's properties are not mutated
2142
+ between two ``ref_element/tail_addr [immutable] `` as long as they have the
2143
+ same buffer reference as operand.
2144
+ This is even true if e.g. the buffer 'escapes' to an unknown function.
2145
+
2146
+
2147
+ In the example above, ``%value2 `` is equal to ``%value1 `` because the operand
2148
+ of both ``ref_element_addr `` instructions is the same ``%immutable_buffer ``.
2149
+ Conceptually, the content of a COW buffer object can be seen as part of
2150
+ the same *static * (immutable) SSA value as the buffer reference.
2151
+
2152
+ The lifetime of a COW value is strictly separated into *mutable * and
2153
+ *immutable * regions by ``begin_cow_mutation `` and
2154
+ ``end_cow_mutation `` instructions::
2155
+
2156
+ %b1 = alloc_ref $BufferClass
2157
+ // The buffer %b1 is mutable
2158
+ %b2 = end_cow_mutation %b1 : $BufferClass
2159
+ // The buffer %b2 is immutable
2160
+ (%u1, %b3) = begin_cow_mutation %b1 : $BufferClass
2161
+ // The buffer %b3 is mutable
2162
+ %b4 = end_cow_mutation %b3 : $BufferClass
2163
+ // The buffer %b4 is immutable
2164
+ ...
2165
+
2166
+ Both, ``begin_cow_mutation `` and ``end_cow_mutation ``, consume their operand
2167
+ and return the new buffer as an *owned * value.
2168
+ The ``begin_cow_mutation `` will compile down to a uniqueness check and
2169
+ ``end_cow_mutation `` will compile to a no-op.
2170
+
2171
+ Although the physical pointer value of the returned buffer reference is the
2172
+ same as the operand, it's important to generate a *new * buffer reference in
2173
+ SIL. It prevents the optimizer from moving buffer accesses from a *mutable * into
2174
+ a *immutable * region and vice versa.
2175
+
2176
+ Because the buffer *content * is conceptually part of the
2177
+ buffer *reference * SSA value, there must be a new buffer reference every time
2178
+ the buffer content is mutated.
2179
+
2180
+ To illustrate this, let's look at an example, where a COW value is mutated in
2181
+ a loop. As with a scalar SSA value, also mutating a COW buffer will enforce a
2182
+ phi-argument in the loop header block (for simplicity the code for copying a
2183
+ non-unique buffer is not shown)::
2184
+
2185
+ header_block(%b_phi : $BufferClass):
2186
+ (%u, %b_mutate) = begin_cow_mutation %b_phi : $BufferClass
2187
+ // Store something to %b_mutate
2188
+ %b_immutable = end_cow_mutation %b_mutate : $BufferClass
2189
+ cond_br %loop_cond, exit_block, backedge_block
2190
+ backedge_block:
2191
+ br header_block(b_immutable : $BufferClass)
2192
+ exit_block:
2193
+
2194
+ Two adjacent ``begin_cow_mutation `` and ``end_cow_mutation `` instructions
2195
+ don't need to be in the same function.
2196
+
2197
+
2110
2198
Instruction Set
2111
2199
---------------
2112
2200
0 commit comments