This is used when materializing an LValue to share state between
the read and write phases of the access, replacing the 'temporary'
and 'extraInfo' parameters that were previously being passed around.
It adds two new fields, origSelfType and genericSig, which will be
used in an upcoming patch to actually apply the callback with the
current generic signature.
This will finally allow us to make use of materializeForSet
implementations in protocol extensions, which is a prerequisite
for enabling resilient default implementations of property and
subscript requirements.
Similarly to how we've always handled parameter types, we
now recursively expand tuples in result types and separately
determine a result convention for each result.
The most important code-generation change here is that
indirect results are now returned separately from each
other and from any direct results. It is generally far
better, when receiving an indirect result, to receive it
as an independent result; the caller is much more likely
to be able to directly receive the result in the address
they want to initialize, rather than having to receive it
in temporary memory and then copy parts of it into the
target.
The most important conceptual change here that clients and
producers of SIL must be aware of is the new distinction
between a SILFunctionType's *parameters* and its *argument
list*. The former is just the formal parameters, derived
purely from the parameter types of the original function;
indirect results are no longer in this list. The latter
includes the indirect result arguments; as always, all
the indirect results strictly precede the parameters.
Apply instructions and entry block arguments follow the
argument list, not the parameter list.
A relatively minor change is that there can now be multiple
direct results, each with its own result convention.
This is a minor change because I've chosen to leave
return instructions as taking a single operand and
apply instructions as producing a single result; when
the type describes multiple results, they are implicitly
bound up in a tuple. It might make sense to split these
up and allow e.g. return instructions to take a list
of operands; however, it's not clear what to do on the
caller side, and this would be a major change that can
be separated out from this already over-large patch.
Unsurprisingly, the most invasive changes here are in
SILGen; this requires substantial reworking of both call
emission and reabstraction. It also proved important
to switch several SILGen operations over to work with
RValue instead of ManagedValue, since otherwise they
would be forced to spuriously "implode" buffers.
This improves MaterializeForSetEmitter to support emission
of static materializeForSet thunks, as well as witnesses.
This is now done by passing in a nullptr as the conformance
and requirement parameters, and adding some conditional code.
Along the way, I fixed a few limitations of the old code,
namely weak/unowned and static stored properties weren't
completely plumbed through. There was also a memory leak in
addressed materializeForSet, the valueBuffer was never freed.
Finally, remove the materializeForSet synthesis in Sema since
it is no longer needed, which fixes at least one known crash
case.
peephole reabstraction components by applying them to
the r-value instead of materializing to a temporary
and then assigning to that.
Removes a completely unnecessary use of the getter
from simple assignments to properties or subscripts
at a different abstraction level.
Swift SVN r31197
the type-checker. The strategy for now is to just use this
for protocol witness thunk emission, where it is required
when generating a materializeForSet for storage that is
either implemented in a protocol extension or requires
reabstraction to the requirement's pattern.
Eventually, this should be generalized to the point that
we can use it for all materializeForSet emission, which
I don't think will take much. However, that's not really
the sort of instability we want to embrace for the current
release.
WIP towards rdar://21836671; currently disabled, so NFC.
Swift SVN r31072
This requires some really ugly copies at -O0 in order to
avoid changing whether enclosing cleanups are active during
the emission of those cleanups. (There may also be complex
situations where values are forwarded to the writeback but
the writeback cleanup can't take advantage of that --- not
sure yet.) These should generally be trivial to clean up,
but I'm still thinking about how to avoid emitting them in
the first place.
Swift SVN r30180
the call instead of during the formal evaluation of the argument.
This is the last major chunk of the semantic changes proposed
in the accessors document. It has two purposes, both related
to the fact that it shortens the duration of the formal access.
First, the change isolates later evaluations (as long as they
precede the call) from the formal access, preventing them from
spuriously seeing unspecified behavior. For example::
foo(&array[0], bar(array))
Here the value passed to bar is a proper copy of 'array',
and if bar() decides to stash it aside, any modifications
to 'array[0]' made by foo() will not spontaneously appear
in the copy. (In contrast, if something caused a copy of
'array' during foo()'s execution, that copy would violate
our formal access rules and would therefore be allowed to
have an arbitrary value at index 0.)
Second, when a mutating access uses a pinning addressor, the
change limits the amount of arbitrary code that falls between
the pin and unpin. For example::
array[0] += countNodes(subtree)
Previously, we would begin the access to array[0] before the
call to countNodes(). To eliminate the pin and unpin, the
optimizer would have needed to prove that countNodes didn't
access the same array. With this change, the call is evaluated
first, and the access instead begins immediately before the call
to +=. Since that operator is easily inlined, it becomes
straightforward to eliminate the pin/unpin.
A number of other changes got bundled up with this in ways that
are hard to tease apart. In particular:
- RValueSource is now ArgumentSource and can now store LValues.
- It is now illegal to use emitRValue to emit an l-value.
- Call argument emission is now smart enough to emit tuple
shuffles itself, applying abstraction patterns in reverse
through the shuffle. It also evaluates varargs elements
directly into the array.
- AllowPlusZero has been split in two. AllowImmediatePlusZero
is useful when you are going to immediately consume the value;
this is good enough to avoid copies/retains when reading a 'var'.
AllowGuaranteedPlusZero is useful when you need a stronger
guarantee, e.g. when arbitrary code might intervene between
evaluation and use; it's still good enough to avoid copies
from a 'let'. The upshot is that we're now a lot smarter
about generally avoiding retains on lets, but we've also
gotten properly paranoid about calling non-mutating methods
on vars.
(Note that you can't necessarily avoid a copy when passing
something in a var to an @in_guaranteed parameter! You
first have to prove that nothing can assign to the var during
the call. That should be easy as long as the var hasn't
escaped, but that does need to be proven first, so we can't
do it in SILGen.)
Swift SVN r24709
Change all the existing addressors to the unsafe variant.
Update the addressor mangling to include the variant.
The addressor and mutable-addressor may be any of the
variants, independent of the choice for the other.
SILGen and code synthesis for the new variants is still
untested.
Swift SVN r24387
optional callback; retrofit existing implementations.
There's a lot of unpleasant traffic in raw pointers here
which I'm going to try to clean up.
Swift SVN r24123
conservatively copying them.
Also, fix a number of issues with mutating getters that
I noticed while examining and changing this code. In
particular, stop relying on suppressing writeback scopes
during loads.
Fixes rdar://19002913, a bug where an unnecessary copy of
an array for a getter call left the array in a non-unique
state when a subsequent mutation occurred.
Swift SVN r23642
semantically valid way.
Previously, this decision algorithm was repeated in a
bunch of different places, and it was usually expressed
in terms of whether the decl declared any accessor
functions. There are, however, multiple reasons why a
decl might provide accessor functions that don't require
it to be accessed through them; for example, we
generate trivial accessors for a stored property that
satisfies a protocol requirement, but non-protocol
uses of the property do not need to use them.
As part of this, and in preparation for allowing
get/mutableAddressor combinations, I've gone ahead and
made l-value emission use-sensitive. This happens to
also optimize loads from observing properties backed
by storage.
rdar://18465527
Swift SVN r22298
Addressors now appear to pass a simple smoke-test; in
order to allow some parallel developement, I'll be
committing actual SILGen tests for this later and
separately.
Swift SVN r22243
accessors on non-dynamic storage.
This allows us to take advantage of dynamic knowledge
that a property is implemented as stored in order to
gain direct access to it instead of copying into a
temporary. When a class or protocol-member property
is expensive to copy, and particularly when it's of
copy-on-write type, such direct accesses can massively
improve the performance of a program.
We are currently only able to apply this when the
property is implemented purely as stored. A willSet
observer inherently blocks the optimization, but we
should be able to make it work even for properties
with didSet observers. This could be done by returning
an arbitrary callback from materializeForSet instead
of returning a flag indicating whether to call the
setter.
rdar://17416120
Swift SVN r22122
as a std::vector<std::unique_ptr<PathComponent>>. DiverseList memcpy's
around its buffer on copy and move operations. This seems safe with all
of the current implementations of Cleanup, but is absolutely not with the
LValue PathComponents. These things hold std::vectors, RValue (which has
an std::vector in it), and a bunch of other probably non-trivial things.
While we're in here, disable the copy constructor, since it isn't safe.
This doesn't harm mainline, but was burning me on a patch I'm working on.
When/if someone cares about performance optimizing this code, a better
approach would be to use an ilist + bump pointer allocator.
Swift SVN r21057
behaviorly correct code by CSE'sing subscripts that are identical.
Also, add a dump() method to PathComponent to help visualize / debug LValue structures.
Swift SVN r20661
computed property" errors when SILGen could determine that there was
an inout writeback alias, and have the code instead perform CSE of the
writebacks directly.
This means that we produce more efficient code, that a lot of things
now "just work" the way users would expect, and that the still erroneous
cases now get diagnosed with the "inout arguments are not allowed to
alias each other" error, which people have a hope of understanding.
There is still more to do here in terms of detecting identical cases,
but that was true of the previous diagnostic as well.
Swift SVN r20658
introduced, as these are obvious miscompilations and clearly mystifying to our user base.
This is enough to emit diagnostics like this:
writeback_conflict_diagnostics.swift:58:70: error: inout writeback aliasing conflict detected on computed property 'c_local_struct_property'
swap(&c_local_struct_property.stored_int, &c_local_struct_property.stored_int)
~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~
writeback_conflict_diagnostics.swift:58:33: note: concurrent writeback occurred here
swap(&c_local_struct_property.stored_int, &c_local_struct_property.stored_int)
~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~
which isn't great, but is better than nothing (better wording is totally welcome!).
This doesn't handle subscripts (or many other kinds of logical lvalue) at all yet, so
it doesn't handle the swift WTF case, but this is progress towards that.
Swift SVN r20297
Implement lowering for the LValueToPointer and InOutConversion expressions. For the former, we emit the lvalue, then convert it to a RawPointer; for the latter, we introduce an InOutConversion scope, which suppresses any nested writeback conversion scopes.
This completes the implementation of inout address conversion, except that we don't implement reabstraction of the lvalue prior to taking its address. Simply report them unimplemented for now, since reabstraction should not come up for our immediate use case with C types.
Swift SVN r15595
- Strength reduce the interface to LogicalPathComponent::getMaterialized
to now just return a SILValue for the address. The full "Materialize"
structure hasn't been needed since MaterializeExpr got removed.
- Move 'struct Materialize' out of SILGen.h into SILGenLValues.cpp now
that it is only used for logical property materialization.
- Drop the dead 'loc' argument on DeallocStackCleanup. The location is
already specified when the cleanup is emitted.
Swift SVN r12827
When we produce a physical LValue with an abstraction difference, cap off the LValue with a logical "OrigToSubstComponent", which enacts the abstraction change on load or store, and introduces a writeback for the property when used in an @inout context.
Swift SVN r11498
of having to lower to an RValue.
This is valuable because we can often emit an expression to a
desired abstraction level more efficiently than just emitting
it to minimal abstraction and then generalizing.
Swift SVN r10455
These are the terms sent out in the proposal last week and described in
StoredAndComputedVariables.rst.
variable
anything declared with 'var'
member variable
a variable inside a nominal type (may be an instance variable or not)
property
another term for "member variable"
computed variable
a variable with a custom getter or setter
stored variable
a variable with backing storage; any non-computed variable
These terms pre-exist in SIL and IRGen, so I only attempted to solidify
their definitions. Other than the use of "field" for "tuple element",
none of these should be exposed to users.
field
a tuple element, or
the underlying storage for a stored variable in a struct or class
physical
describes an entity whose value can be accessed directly
logical
describes an entity whose value must be accessed through some accessor
Swift SVN r8698