This is an LValue component whose value is the class
reference inside of a class existential.
Unlike OpenOpaqueExistentialComponent, this is a logical
component, with a "writeback" consisting of wrapping the
new class reference in a class existential having the
same conformances as the original.
This is slightly awkward, but adding "by-address" operations
on class existentials, and projecting the payload out is
a big change and might not make sense for other reasons.
When lowering a LoadExpr, SILGen constructs an LValue
and loads from it to produce an RValue.
If a LoadExpr contains another LoadExpr, the innermost
LoadExpr builds its own LValue, which is then loaded
to an RValue, and turned back into an LValue by creating
a single ValueComponent.
When evaluating an OpenExistentialExpr inside an LValue,
we record the base expression and evaluate it as an LValue
later when we encounter the corresponding OpaqueValueExpr.
The problem is when this is combined with a nested
LoadExpr, we might be inside of a different LValue than
the original LValue that contained the OpenExistentialExpr.
This would trigger an assertion, because the mapping from
OpaqueValueExprs to their base expressions was per-LValue;
instead, it needs to be per-SILGenFunction.
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.
This enables me to refactor some code in SILGenConstructor. Specifically this
code passes in a false for uninitialized and then creates the mark uninitialized
for itself.
NFC by default.
I had a much more comprehensive version of this patch that I had to
back out in order to just get something in to unblock progress.
There's a lot of technical debt in SILGen around l-values.
Enabling this will almost certainly not get past the SIL passes.
The reason I am doing this is that I am going to in the next couple of commits
change enum element dispatch to with or without semantic SIL use proper
ownership.
In this commit, I just did the copy and eliminated any parts of the code that
were predicated on having an address.
(This re-applies #7736 with an update to the
tsan-inout.swift execution test to handle configurations where
TSan's ignore_interceptors_accesses is enabled by default.)
Add SILGen instrumentation to treat inout accesses as Thread Sanitizer writes.
The goal is to catch races on inout accesses even when there is a not an
llvm-level read/write to a particular address. Ultimately
this will enable TSan to, for example, report racy writes to distinct
stored properties of a common struct as a data race.
This instrumentation is off by default. It can be enabled with the
'enable-experimental-tsan-inout-instrumentation' frontend flag.
The high-level approach is to add a SIL-level builtin that represents a call
to a TSan routine in compiler-rt. Then, when emitting an address for an LValue
as part of an inout expression, we call this builtin for each path component
that represents an LValue. I've added an 'isRValue()' method to PathComponent
that tracks whether a component represents an RValue or an LValue. Right the
only PathComponent that sometimes returns 'true' is ValueComponent().
For now, we're instrumenting only InoutExprs, but in the future it probably
makes sense to instrument all LValue accesses. In this patch I've
added a 'TSanKind' parameter to SILGenFunction::emitAddressOfLValue() and
its helpers to limit instrumentation to inout accesses. I envision that this
parameter will eventually go away.
Add SILGen instrumentation to treat inout accesses as Thread Sanitizer writes.
The goal is to catch races on inout accesses even when there is a not an
llvm-level read/write to a particular address. Ultimately
this will enable TSan to, for example, report racy writes to distinct
stored properties of a common struct as a data race.
This instrumentation is off by default. It can be enabled with the
'enable-experimental-tsan-inout-instrumentation' frontend flag.
The high-level approach is to add a SIL-level builtin that represents a call
to a TSan routine in compiler-rt. Then, when emitting an address for an LValue
as part of an inout expression, we call this builtin for each path component
that represents an LValue. I've added an 'isRValue()' method to PathComponent
that tracks whether a component represents an RValue or an LValue. Right the
only PathComponent that sometimes returns 'true' is ValueComponent().
For now, we're instrumenting only InoutExprs, but in the future it probably
makes sense to instrument all LValue accesses. In this patch I've
added a 'TSanKind' parameter to SILGenFunction::emitAddressOfLValue() and
its helpers to limit instrumentation to inout accesses. I envision that this
parameter will eventually go away.
This structure contains all of the type information that we use to build a
ResultPlanPtr. In a subsequent commit, I am going to move ResultPlanPtr creation
out of emitApply and place it before the creation of arguments. This is to
enable indirect result initializations to belong to the scope outside of any
argument based scopes.
Without this the lifetimes of the indirect result initializations and arguments
can not be separated without using hacks. There is no reason why we can't emit
the indirect result temporaries before we emit any arguments since they will
remain dormant until after the final apply/any future committed argument scopes
being popped.
rdar://30955427
Change emitApplyOfLibraryIntrinsic() to take a SubstitutionMap,
and use the correct abstractions to build the map.
This gets rid of the last remaining uses of gatherAllSubstitutions()
in SIL.
Previously, we would put a destroy_value directly on the value that we tried to
cast. Since checked_cast_br is consuming, this would cause the destroy_value on
the failure path to be flagged as a double consume.
This commit causes SILGen to emit the value consumed by checked_cast_br as an
@owned argument to the failure BB, allowing semantic arc rules to be respected.
As an additional benefit, I also upgraded the ownership_model_eliminator test to
use semantic sil verification.
One issue that did come up though is that I was unable to use the new code in
all locations in the compiler. Specifically, there is one location in
SILGenPattern that uses argument unforwarding. I am going to need to undo
argument unforwarding in SILGenPattern in order to completely eliminate the old
code path.
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
Eventually I want to move all of these emit* APIs to SILGenBuilder and make them
private details of SILGenBuilder. But that is a refactoring for another time.
rdar://29791263
Previously, we were emitting these cleanups at the end of the lexical scope
instead of at the end of the formal evaluation scope. This change ensures that
we always emit the cleanup immediately at the end of the formal evaluation
scope.
Previously in most cases we got away with this due to the +0 self
hack. Basically we would emit a get for a self parameter and then immediately
use that self parameter as a guaranteed parameter. Then the hack would insert
the destroy value forwarding the lexical scope level cleanup at the same time.
rdar://29791263
As per John, WritebackScope was always an unfortunate name. Generally these
scopes are meant for formal evaluations of inout parameters. The cases that I am
interested in generalizing them to be used for are borrows of the base of a
class that will then be used as an lvalue.
This also eliminates the out of line vector of lvalue writebacks.
rdar://29791263
SubstitutionList is going to be a more compact representation of
a SubstitutionMap, suitable for inline allocation inside another
object.
For now, it's just a typedef for ArrayRef<Substitution>.
There was only one place where we lowered AST types with a non-zero
uncurry level, in SILGenApply.cpp. Add a new overload of the
getSILFunctionType() method that takes an uncurry level. All the
other methods no longer have to thread it through.
Separate formal lowered types from SIL types.
The SIL type of an argument will depend on the SIL module's conventions.
The module conventions are determined by the SIL stage and LangOpts.
Almost NFC, but specialized manglings are broken incidentally as a result of
fixes to the way passes handle book-keeping of aruments. The mangler is fixed in
the subsequent commit.
Otherwise, NFC is intended, but quite possible do to rewriting the logic in many
places.
For this we need to store the linkage of the “original” method implementation in the vtable.
Otherwise DeadFunctionElimination thinks that the method implementation is not public but private (which is the linkage of the thunk).
The big part of this change is to extend SILVTable to store the linkage (+ serialization, printing, etc.).
fixes rdar://problem/29841635
Suppose we have a protocol requirement returning Self:
protocol Clonable {
func clone() -> Self
}
If we have a value 'x' of existential type 'Clonable',
the partial application 'x.clone' has formal type
'() -> Clonable'. However the actual type of the
method substitutes in an "opened" existential type
for 'Self'.
In order to implement the partial application we must
wrap the method in a thunk which 'erases' the opened
existential, so the thunk has type
<T : Clonable> (() -> T) -> () -> Clonable
The thunk is called with a substitution replacing 'T'
with the opened existential type.
Fixes <rdar://problem/21391055>.
Otherwise we might miss emitting a local type that's inside
unreachable code. Normally such a type cannot be found via
name lookup either, but IRGen will walk the list of local types
and try to emit a class with no SIL vtable, which will crash.
Fixes <https://bugs.swift.org/browse/SR-1924>.
Before this commit all code relating to handling arguments in SILBasicBlock had
somewhere in the name BB. This is redundant given that the class's name is
already SILBasicBlock. This commit drops those names.
Some examples:
getBBArg() => getArgument()
BBArgList => ArgumentList
bbarg_begin() => args_begin()