It does not take ownership of its non-trivial arguments, is a trivial
function type and therefore must not be destroyed. The compiler must
make sure to extend the lifetime of non-trivial arguments beyond the
last use of the closure.
%objc = copy_value %0 : $AnObject
%closure = partial_apply [stack] [callee_guaranteed] %16(%obj) : $@convention(thin) (@guaranteed AnObject) -> ()
%closure2 = mark_dependence %closure : $@noescape @callee_guaranteed () -> () on %obj : $AnObject
%user = function_ref @useClosure : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
apply %user(%closure2) : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
dealloc_stack %closure : $() ->()
destroy_value %obj : $AnObject // noescape closure does not take ownership
SR-904
rdar://35590578
Specifically we add a groups of APIs for destructure operations. The destructure
helpers are a family of functions built around
emitDestructureValueOperation. These in ossa produce destructures and pass the
results off to the caller in some manner that hides the internal destructure
instruction. In non-ossa, the appropriate projections are created and passed off
to the caller.
We've been running doxygen with the autobrief option for a couple of
years now. This makes the \brief markers into our comments
redundant. Since they are a visual distraction and we don't want to
encourage more \brief markers in new code either, this patch removes
them all.
Patch produced by
for i in $(git grep -l '\\brief'); do perl -pi -e 's/\\brief //g' $i & done
Previously we would always calculate these instructions ownership dynamically
when asked and rely on the ownership verifier to catch if we made any
mistakes. Instead with this commit we move to a more static model where the
ownership that these instructions can take are frozen on construction. This is a
more static model that simplifies the ownership model.
I also eliminated a few asserts that are enforced in other places that caused
problems when parsing since we may not have a Function while Parsing (it was
generally asserts if a type was trivial).
In this commit I added a more convenient API for doing this sort of operation.
Specifically: SILBuilder::emitScopedBorrowOperation. This performs either a
load_borrow or begin_borrow, then calls a user provided closure, and finally
inserts the end_borrow after the scope has closed.
rdar://43398898
The major important thing here is that by using copy_unowned_value we can
guarantee that the non-ownership SIL ARC optimizer will treat the release
associated with the strong_retain_unowned as on a distinc rc-identity from its
argument. As an example of this problem consider the following SILGen like
output:
----
%1 = copy_value %0 : $Builtin.NativeObject
%2 = ref_to_unowned %1
%3 = copy_unowned_value %2
destroy_value %1
...
destroy_value %3
----
In this case, we are converting a strong reference to an unowned value and then
lifetime extending the value past the original value. After eliminating
ownership this lowers to:
----
strong_retain %0 : $Builtin.NativeObject
%1 = ref_to_unowned %0
strong_retain_unowned %1
strong_release %0
...
strong_release %0
----
From an RC identity perspective, we have now blurred the lines in between %3 and
%1 in the previous example. This can then result in the following miscompile:
----
%1 = ref_to_unowned %0
strong_retain_unowned %1
...
strong_release %0
----
In this case, it is possible that we created a lifetime gap that will then cause
strong_retain_unowned to assert. By not lowering copy_unowned_value throughout
the SIL pipeline, we instead get this after lowering:
----
strong_retain %0 : $Builtin.NativeObject
%1 = ref_to_unowned %0
%2 = copy_unowned_value %1
strong_release %0
...
strong_release %2
----
And we do not miscompile since we preserved the high level rc identity
pairing.
There shouldn't be any performance impact since we do not really optimize
strong_retain_unowned at the SIL level. I went through all of the places that
strong_retain_unowned was referenced and added appropriate handling for
copy_unowned_value.
rdar://41328987
**NOTE** I am going to remove strong_retain_unowned in a forthcoming commit. I
just want something more minimal for cherry-picking purposes.
In an upcoming bug fix, I want to pass SILBuilderContext to a
utility. I could continue reusing SILBuilder, even though the utility
must set its own insertion point and debug location. However, this is
terrible practice that I don't want to perpetuate.
The lifetime of a SILBuilder should correspond to a single insertion
point and debug location. That's the only sane way to preserve debug
information in SIL passes.
There are various pieces of contextual state that we've been adding to
the SILBuilder. Those have made it impossible to use SILBuilder
correctly. I'm pulling the context out, so clients can begin using
better practices. In the future, we can make SILBuilderContext
polymorphic, so passes can extend it easily with arbitrary
callbacks. We can also make it self-contained so we don't need to pass
around pointers to an InsertedInst list anymore.
Assign the location of a switch statement's subject expression to all of
its case statements.
This improves the debugger's stepping behavior in switch statements.
Stepping into a switch now goes directly to the first matching case
(possibly one with a `where` clause that may or may not match). It's
still possible to set breakpoints within `where` clauses.
rdar://35628672
* Reduce array abstraction on apple platforms dealing with literals
Part of the ongoing quest to reduce swift array literal abstraction
penalties: make the SIL optimizer able to eliminate bridging overhead
when dealing with array literals.
Introduce a new classify_bridge_object SIL instruction to handle the
logic of extracting platform specific bits from a Builtin.BridgeObject
value that indicate whether it contains a ObjC tagged pointer object,
or a normal ObjC object. This allows the SIL optimizer to eliminate
these, which allows constant folding a ton of code. On the example
added to test/SILOptimizer/static_arrays.swift, this results in 4x
less SIL code, and also leads to a lot more commonality between linux
and apple platform codegen when passing an array literal.
This also introduces a couple of SIL combines for patterns that occur
in the array literal passing case.
- Add a DominanceInfo::dominates helper functions that takes two instructions,
as analogues to the properlyDominates ones.
- Further generalize some SILBuilder code to be more defensive in the face
of incorrect or partially constructed SIL instructions.
These are cleanups, NFC.
introduce a common superclass, SILNode.
This is in preparation for allowing instructions to have multiple
results. It is also a somewhat more elegant representation for
instructions that have zero results. Instructions that are known
to have exactly one result inherit from a class, SingleValueInstruction,
that subclasses both ValueBase and SILInstruction. Some care must be
taken when working with SILNode pointers and testing for equality;
please see the comment on SILNode for more information.
A number of SIL passes needed to be updated in order to handle this
new distinction between SIL values and SIL instructions.
Note that the SIL parser is now stricter about not trying to assign
a result value from an instruction (like 'return' or 'strong_retain')
that does not produce any.
The problem is that within SimplifyCFG we call this for an instruction within unreachable code. And within an unreachable block it can happen that defs do not dominate uses (because there is no dominance defined).
The fix is to prevent the infinite loop in addOpenedArchetypeOperands by marking visited instructions.
Fixes rdar://problem/34602036
Static initializers are now represented by a list of literal and aggregate instructions in a SILGlobalVariable.
For details see SIL.rst.
This representation is cleaner than what we did so far (point to the initializer function and do some pattern matching).
One implication of that change is that now (a subset of) instructions not necessarily have a parent function.
Regarding the generated code it's a NFC.
Also the swift module format didn't change because so far we don't serializer global variables.
It makes it easier to track down this type of bug since the assert occurs in
SILBuilder right where the invalid ValueMetatype is created.
rdar://problem/31880847
removeFromParent should only be used when one is moving a SILInstruction from
one block to another or in preparation for deleting an instruction. In this
case, we are removing these two SILInstructions from their parent block and
leaking the instruction. The right thing to do is to use eraseFromParent.
<rdar://problem/31276565>
A lot of files transitively include Expr.h, because it was
included from SILInstruction.h, SILLocation.h and SILDeclRef.h.
However in reality most of these files don't do anything
with Exprs, especially not anything in IRGen or the SILOptimizer.
Now we're down to 171 files in the frontend which depend on
Expr.h, which is still a lot but much better than before.
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>.
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.
This simplifies the SILType substitution APIs and brings them in line with Doug and Slava's refactorings to improve AST-level type substitution. NFC intended.
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()