Mandatory pass will clean it up and replace it by a copy_block and
is_escaping/cond_fail/release combination on the %closure in follow-up
patches.
The instruction marks the dependence of a block on a closure that is
used as an 'withoutActuallyEscaping' sentinel.
rdar://39682865
To mark when a user of it is known to escape the value. This happens
with materializeForSet arguments which are captured and used in the
write-back. This means we need to keep the context alive until after
the write-back.
Follow-up patches to fully replace the PostponedCleanup hack in SILGen
by a mandatory SIL transformation pass to guarantee the proper lifetime
will use this flag to be more conservative when extending the lifetime.
The problem:
%pa = partial_apply %f(%some_context)
%cvt = convert_escape_to_noescape [not_guaranteed] [escaped] %pa
%ptr = %materialize_for_set(..., %cvt)
... write_back
... // <-- %pa needs to be alive until after write_back
By design, things with shared linkage are allowed to have definitions in different TUs, and we're supposed to pick one when linking or merging modules.
Add serialization layouts for rare instructions that take extra attributes. We
can continue adding bits to these layout without affecting the layout of the
vast majority of instructions.
A public subscript might have generic indexes that aren't unconditionally Hashable, or might use indexes that are retroactively made Hashable, so the property descriptor on the implementer's side can't always resiliently provide this information to the final instantiated KeyPath.
If a property or subscript is referenceable from other modules, we need to give it a descriptor so that we can reliably build an equivalent key path in or out of that module.
There are some cases that we should handle but don't yet:
- Global and static properties ought to be key-path-able someday, so we should make descriptors for them, but this might need a new key path component kind.
- Subscripts with indexes that aren't Hashable in the current module ought to get descriptors too, in case we ever support non-hashable key path components, and also because a generic subscript might be substituted with Hashable types by an external user, or an external module might post-hoc extend a type to be Hashable, so we really need to change things so that the client supplies the hashing and equality implementations for the indexes instead of the descriptor.
Will be used to verify that withoutActuallyEscaping's block does not
escape the closure.
``%escaping = is_escaping_closure %closure`` tests the reference count. If the
closure is not uniquely referenced it prints out and error message and
returns true. Otherwise, it returns false. The returned result can be
used with a ``cond_fail %escaping`` instruction to abort the program.
rdar://35525730
The obsolete llvm::HashString() was equivalent to
llvm::djbHash(seed=0) and was removed from llvm. This patch replaces
all occurences of llvm::HashString() with llvm::djbHash(seed=0), no
functional change.
The default seed of llvm::djbHash() is supposed to yield a higher
quality result that using seed=0, but changing it looks like it
affects the ordering of SIL serialization.
This is mostly intended to be used for testing at this point; in the
long run, we want to be using availability information to decide
whether to weak-link something or not. You'll notice a bunch of FIXMEs
in the test case that we may not need now, but will probably need to
handle in the future.
Groundwork for doing backward-deployment execution tests.
We can't make the same assumptions about .sib files.
Ideally, we should serialize the module's stage and set WasDeserializedCanonical
based on that state. However, we probably still want the IsSIB flag for
assertions.
We need to be able to detect function definitions that have been
deserialized. There's no need to rerun diagnostics on those functions,
and in some cases it's actually incorrect to do so. With exclusivity,
we could even miscompile in theory (debug assert) because the fully
optimized SIL does adhere to rules requires by the
diagnostic. Hopefully that specific issue can be fixed soon, but the
point is that we need control over the order that passes are run
because we play these games all the time. Not to mention the wasted
compilation time.
It would probably be sufficient to check isAvailableExternally. However, using
an explicit flag is, well, more explicit. It also generalizes to serializing IR
at any stage.
Note: I would strongly prefer not to rely on this flag for correctness. In
principle, serialized SIL should be compatible with all SIL stages prior to the
serialization point. However, it is necessary to fix bugs in the short term, and
useful for bootstrapping SIL changes in general. Also, it formalizes some
assumptions about the way the pass pipeline is expected to work making it easier
to reason about and avoid pass ordering bugs. In particular, we should not be
relying on a second round of the mandatory pass pipeline to catch important
performance opportunities.
@noescape function types will eventually be trivial. A
convert_escape_to_noescape instruction does not take ownership of its
operand. It is a projection to the trivial value carried by the closure
-- both context and implementation function viewed as a trivial value.
A safe SIL program must ensure that the object that the project value is based
on is live beyond the last use of the trivial value. This will be
achieve by means of making the lifetimes dependent.
For example:
%e = partial_apply [callee_guaranteed] %f(%z) : $@convention(thin) (Builtin.Int64) -> ()
%n = convert_escape_to_noescape %e : $@callee_guaranteed () -> () to $@noescape @callee_guaranteed () -> ()
%n2 = mark_dependence %n : $@noescape @callee_guaranteed () -> () on %e : $@callee_guaranteed () -> ()
%f2 = function_ref @use : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
apply %f2(%n2) : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
release_value %e : $@callee_guaranteed () -> ()
Note: This is not yet actually used.
Part of:
SR-5441
rdar://36116691
- Clear the 'serialized' flag on witness tables and vtables
after serialization, not just functions. This fixes SIL
verifier failures if post-serialization SIL is printed
out and parsed back in.
- Clear the 'serialized' flag when deserializing functions,
witness tables and vtables in a module that has already
been serialized. This fixes SIL verifier failures if
we deserialize more declarations after serializing SIL.
We were seeing SIL verifier failures on bots that run the
tests with the stdlib built with non-standard flags.
Unfortunately I don't have a reduced test case that would
fail in PR testing without these fixes.
Fixes <rdar://problem/36682929>.
Consider a module with two files, one of which references a
function in the other file. If the function had PublicNonABI
linkage, the forward reference has HiddenExternal linkage.
If we saw the forward reference first in the merge modules
process, we would not update the linkage of the function
when we later deserialized its body.
This would result in it being dropped from the final merged
SIL module. Previously this did not cause any problems
because all inlineable functions had public linkage, but now
that default argument generators no longer have public entry
points, this could cause linker errors.
For the majority of artificial helper functions the filename is
actively misleading since it usually represents the file of the caller
that triggered the helper to be generated. Instead, this patch creates
a virtual filname `<compiler-generated>` to make it very obvious that
the function has not correspondence to any source code.
<rdar://problem/33809560>
This is going to be used for "always emit into client" functions,
such as default argument generators and stored property
initializers.
- In dead function elimination, these functions behave identically to
public functions, serving as "anchors" for the mark-and-sweep
analysis.
- There is no external variant of this linkage, because external
declarations can use HiddenExternal linkage -- the definition should
always be emitted by another translation unit in the same Swift
module.
- When deserialized, they receive shared linkage, because we want the
linker to coalesce multiple copies of the same deserialized
definition if it was deserialized from multiple translation units
in the same Swift module.
- When IRGen emits a definition with this linkage, it receives the
same LLVM-level linkage as a hidden definition, ensuring it does not
have a public entry point.