conversions and extend lifetimes over the call.
Apply this logic to string-to-pointer conversions as well as
array-to-pointer conversions.
Fix the AST verifier to not blow up on optional pointer conversions,
and make sure we SILGen them correctly. There's still an AST bug
here, but I'll fix that in a follow-up patch.
The reason that this is being done is that:
1. SILGenFunction is passed around all throughout SILGen, including in between
APIs some of which call the SILGenFunction variable SGF and others that call it
gen.
2. Thus when one is debugging code in SILGen, one wastes time figuring out what
the variable name of SILGenFunction is in the current frame.
I did not do this by hand. I did this by:
1. Grepping for "SILGenFunction &gen".
2. By hand inspecting that the match was truly a SILGenFunction &gen site.
3. If so, use libclang tooling to rename the variable to SGF.
So I did not update any use sites.
This is in preparation for removing the +0 self hack.
This commit in more detail does the following:
1. It adds Formal Evaluation Scopes to certain places where the scopes were
missing. Specifically:
a. The SILGenLValue cases are places where we are invoking accessors. In each
one of these cases, we had a formal evaluation scope in the accessor
itself, but we did not have a scope that closed over the base access and
the accessor access. The base access is a formal evaluation in the sense
that just like with inout bases, we must create a new reference to the
base and re-destroy the base in a chain of accesses. This is to ensure
that we do not extend the lifetime of the base inappropriately.
b. The SILGenPoly case is a place where we have never properly placed a
Formal Evaluation Scope and have completely been relying on the +0 self
hack to make sure that archetype callees are properly destroyed
immediately after a +0 call.
2. It changes all of the places in SILGen that emit self to using formal access
cleanups instead of normal cleanups.
rdar://29791263
new API called ManagedValue::unmanagedBorrow() for places where we were really trying to model
an exclusive borrow.
ManagedValue::unmanagedBorrow() is just the old implementation.
rdar://29791263
I am using this for implementing tight scopes around specific call sites. The
way that it works is that the class performs the copy and asserts if one has not
called the cleanup method before end of scope has occured.
rdar://29791263
Everything here should be NFC after the ownership model eliminator except for 1
change where translation of unowned parameters is made more
correct. Specifically:
1. In manageParam, we make it so that if we allow PlusZero, we begin an actual
begin_borrow, end_borrow sequence. We can do this unconditionally since if the
passed in SILValue is already borrowed, we just return early.
2. In TranslateArguments::translateSingle(), we used to handle owned, unowned,
and guaranteed parameters all the same way. This is of course incorrect. Now we
do the following:
a. If our final translated value is guaranteed, but we want an unowned or
owned parameter, then we perform a copyUnmanaged().
b. If our final translated value is unowned and our argument must be a
guaranteed value, then we first transition the unowned value to an owned value
using SILGen::emitManagedRetain() and then transition from owned to guaranteed
using a emitBeginBorrow().
c. If our final translated value is owned and our argument must be a
guaranteed value, then we perform an emitBeginBorrow().
3. In forwardFunctionArguments(), if our argument requires a guaranteed
argument, we begin a begin borrow sequence.
rdar://29791263
This lets you do isa<AllocRefInst> to determine if the underlying ManagedValue
contains within it an AllocRefInst without needing to call getValue(). I would
like to restrict the number of places where getValue() needs to be called as
much as possible.
I realized over the weekend the follie of storing a borrowed cleanup on
ManagedValues themselves. The reasons for this are:
1. We assume all over SILGen that ManagedValue::hasCleanup() => Owned. I would
have to fix all of those parts of the compiler.
2. The reason for having a cleanup handle on ManagedValue is to be able to
forward owned arguments, so there is really no purpose since we never want to be
able to forward these arguments.
This is the first step towards eliminating:
* ManagedValue::forUnmanaged(SILValue)
* ManagedValue::ManagedValue(SILValue, CleanupHandle).
The reason why these two methods must be eliminated is that:
1. Currently non-trivial values are "borrowed" using
ManagedValue::forUnmanaged. With Semantic SIL, we are now able to represent
borrows via begin_borrow and end_borrow. This will make the semantics that
SILGen is trying to describe more accurate.
2. ManagedValue::ManagedValue can be used to add arbitrary cleanups. We want
methods that add cleanups, but that at the same time allow the caller to specify
what it expects the ownership of the given SILValue to be. This would then cause
an assertion to trip giving greater clarity.
rdar://29791263
In SILGen, we often times want to transform a ManagedValue, while maintaining
the underlying cleanup. The ManagedValue::transform API attempts to formalize
this pattern through the usage of std::move to create a movable rvalue, but
returning a different ManagedValue as a full value. This ensure that the
original ManagedValue is destroyed at end of statement, will allowing the
underlying cleanup to be forwarded.
From an ownership perspective, I think the majority of these cases should
actually recreate the underlying cleanup since in most cases they involve
forwarding. For today though I am using this to just formalize this pattern at
the relevant call sites.
rdar://29791263
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
declare whether it's owned by the emission code that's
working with it.
This is convenient when working extensively with values
that are being propagated into multiple, often-disjoint
paths, like switches.
Swift SVN r19333
- purge @inout from comments in the compiler except for places talking about
the SIL argument convention.
- change diagnostics to not refer to @inout
- Change the astprinter to print InoutType without the @, so it doesn't show
up in diagnostics or in closure argument types in code completion.
- Implement type parsing support for the new inout syntax (before we just
handled patterns).
- Switch the last couple of uses in the stdlib (in types) to inout.
- Various testcase updates (more to come).
Swift SVN r13564
- Remove my previous local hack.
- Add a new flag to SGFContext indicating that clients are ok with +0 rvalues.
- Teach emitRValueForPropertyLoad and emitRValueForDecl how to work with +0 rvalues.
This allows us to avoid retaining bases in arbitrarily nested struct rvalue
member_ref_expr's. For example, this:
class SomeClass {}
struct AnotherStruct {
var x : Int
var c : SomeClass
}
struct StructMemberTest {
var c1 : SomeClass, c2 : SomeClass
var s : AnotherStruct
func testRecursiveStruct() -> Int {
return s.x
}
}
used to compile to:
sil @_TFV1t16StructMemberTest19testRecursiveStructfS0_FT_Si : $@cc(method) @thin (@owned StructMemberTest) -> Int64 {
bb0(%0 : $StructMemberTest):
debug_value %0 : $StructMemberTest // let self // id: %1
%2 = struct_extract %0 : $StructMemberTest, #s // user: %3
%3 = copy_value %2 : $AnotherStruct // users: %5, %4
%4 = struct_extract %3 : $AnotherStruct, #x // user: %7
destroy_value %3 : $AnotherStruct // id: %5
destroy_value %0 : $StructMemberTest // id: %6
return %4 : $Int64 // id: %7
}
and now it compiles to:
sil @_TFV1t16StructMemberTest19testRecursiveStructfS0_FT_Si : $@cc(method) @thin (@owned StructMemberTest) -> Int64 {
bb0(%0 : $StructMemberTest):
debug_value %0 : $StructMemberTest // let self // id: %1
%2 = struct_extract %0 : $StructMemberTest, #s // user: %3
%3 = struct_extract %2 : $AnotherStruct, #x // user: %5
destroy_value %0 : $StructMemberTest // id: %4
return %3 : $Int64 // id: %5
}
There is more that can come from this, but it is a start. This cuts out 50 retain/release pairs from the stdlib.
Swift SVN r12857
emission routines use the SGFContext passed in. To help with this and
to help the handshake, add a new "isInContext()" representation to
ManagedValue. This makes the code producing and consuming these more
explicit. NFC.
Swift SVN r12783
can often produce an lvalue, for everything else it produces an RValue.
Split it up a bit so that all of the lvalue cases are handled by
emitLValueForDecl (which it calls). This allows clients that only
expect an lvalue back to have a simpler path, and allows one that
wants to probe to see if something is an lvalue or not to be simpler.
Swift SVN r12715