The reason why this is true is that we will be inserting new copy_values for
each available value implying that we can never have such a singular value.
I also added two test cases that show that we have a singular value with the
trivial type and that works.
The key thing to note here is that when we are processing a take, we validate
that at all destroy points we have a fully available value. So we should never
hit this code path which is correct. This assert just makes the assumption
clearer in the small when reading code locally in handlePrimitiveValue.
Previously, we only specified via a boolean value whether or not we were a take
or not. Now we have an enum which is more specific and descriptive. It will also
let me fix an issue that occurs with Borrow/Copy incrementally as separate
patches.
This is a pure refactor so I can make some subsequent transformations easier to
do.
I also did a little bit of debridement when there were opportunities to
flatten control flow by eliminating direct checks for one or the other classes.
symbolic values, which are used to represent constant struct and tuple
instances. Associating those symbolic values with the types of the
aggregate they are representing will allow writing some sanity checks,
and will also make constant folding of the symbolic values easier and
more robust.
of OSLogMessage constant evaluable and remove @_transparent annotation
from the methods. Also, improve diagnostics in the OSLogOptimization
pass as now it rely on seeing the appendInterpolation/Literal calls.
add -enable-ownership-stripping-after-serialization flag to OSLog optimization tests,
and update the folding logic and end-of-use discovery logic to handle ownership
and non-ownership SIL.
https://forums.swift.org/t/improving-the-representation-of-polymorphic-interfaces-in-sil-with-substituted-function-types/29711
This prepares SIL to be able to more accurately preserve the calling convention of
polymorphic generic interfaces by letting the type system represent "substituted function types".
We add a couple of fields to SILFunctionType to support this:
- A substitution map, accessed by `getSubstitutions()`, which maps the generic signature
of the function to its concrete implementation. This will allow, for instance, a protocol
witness for a requirement of type `<Self: P> (Self, ...) -> ...` for a concrete conforming
type `Foo` to express its type as `<Self: P> (Self, ...) -> ... for <Foo>`, preserving the relation
to the protocol interface without relying on the pile of hacks that is the `witness_method`
protocol.
- A bool for whether the generic signature of the function is "implied" by the substitutions.
If true, the generic signature isn't really part of the calling convention of the function.
This will allow closure types to distinguish a closure being passed to a generic function, like
`<T, U> in (*T, *U) -> T for <Int, String>`, from the concrete type `(*Int, *String) -> Int`,
which will make it easier for us to differentiate the representation of those as types, for
instance by giving them different pointer authentication discriminators to harden arm64e
code.
This patch is currently NFC, it just introduces the new APIs and takes a first pass at updating
code to use them. Much more work will need to be done once we start exercising these new
fields.
This does bifurcate some existing APIs:
- SILFunctionType now has two accessors to get its generic signature.
`getSubstGenericSignature` gets the generic signature that is used to apply its
substitution map, if any. `getInvocationGenericSignature` gets the generic signature
used to invoke the function at apply sites. These differ if the generic signature is
implied.
- SILParameterInfo and SILResultInfo values carry the unsubstituted types of the parameters
and results of the function. They now have two APIs to get that type. `getInterfaceType`
returns the unsubstituted type of the generic interface, and
`getArgumentType`/`getReturnValueType` produce the substituted type that is used at
apply sites.
Specifically, we may have a loaded callee value from a stack value. This change
just makes it so that we do not optimize if we do not actually have the box.
rdar://56386236
Since getSpecifier() now kicks off a request instead of always
returning what was previously set, we can't pass a ParamSpecifier
to the ParamDecl constructor anymore. Instead, callers either
call setSpecifier() if the ParamDecl is synthesized, or they
rely on the request, which can compute the specifier in three
specific cases:
- Ordinary parsed parameters get their specifier from the TypeRepr.
- The 'self' parameter's specifier is based on the self access kind.
- Accessor parameters are either the 'newValue' parameter of a
setter, or a cloned subscript parameter.
For closure parameters with inferred types, we still end up
calling setSpecifier() twice, once to set the initial defalut
value and a second time when applying the solution in the
case that we inferred an 'inout' specifier. In practice this
should not be a big problem because expression type checking
walks the AST in a pre-determined order anyway.
Previously, we were using a pointer set to ensure that was checked when a value
was popped off the worklist. In this commit, I change the code so that we
instead use the set to guard insertion into the worklist.
I changed the name of the set to blockAlreadyAddedToWorklist. Hopefully that
will make things a bit clearer.
Beyond creating a nice invariant, I am going to be using this invariant in some
small code improvements to MandatoryCombine that assume we have an initial basic
block.
`cdecl` is a keyword in the non-conforming C++ dialect used on Windows
which expands to `__cdecl`. Simply rename the variable to avoid the
replacement. Although it is possible to `#undef cdecl`, renaming makes
it less confusing for non-Windows developers.
The XXOptUtils.h convention is already established and parallels
the SIL/XXUtils convention.
New:
- InstOptUtils.h
- CFGOptUtils.h
- BasicBlockOptUtils.h
- ValueLifetime.h
Removed:
- Local.h
- Two conflicting CFG.h files
This reorganization is helpful before I introduce more
utilities for block cloning similar to SinkAddressProjections.
Move the control flow utilies out of Local.h, which was an
unreadable, unprincipled mess. Rename it to InstOptUtils.h, and
confine it to small APIs for working with individual instructions.
These are the optimizer's additions to /SIL/InstUtils.h.
Rename CFG.h to CFGOptUtils.h and remove the one in /Analysis. Now
there is only SIL/CFG.h, resolving the naming conflict within the
swift project (this has always been a problem for source tools). Limit
this header to low-level APIs for working with branches and CFG edges.
Add BasicBlockOptUtils.h for block level transforms (it makes me sad
that I can't use BBOptUtils.h, but SIL already has
BasicBlockUtils.h). These are larger APIs for cloning or removing
whole blocks.
discovering the beginning of the string interpolation passed
to os log APIs.
The implementation follows the chain of dependencies starting
from an initializer call to OSLogMessage until the first
instruction of interpolation is discovered. This is more
robust towards changes to the SIL generation of string
interpolation literals.
Often times when one is working with apply sites, one wants to insert
instructions after both terminator apply sites and normal apply sites. This can
get ackward and result in unnecessary if-else code that is all really doing the
same thing, once for terminator instructions and once for normal instructions.
insertAfterApply is a helper method that MandatoryInlining uses for this purpose
and it is so useful that I want to use it somewhere else in closure lifetime
fixup as well. I am moving it onto apply site since that is the true abstraction
that insertAfterApply works with.
This commit only changes how BranchPropagatedUser is constructed and does not
change the internal representation. This is a result of my noticing that
BranchPropagatedUser could also use an operand internally to represent its
state. To simplify how I am making the change, I am splitting the change into
two PRs that should be easy to validate:
1. A commit that maps how the various users of BranchPropagatedUser have been
constructing BPUs to a single routine that takes an Operand. This leaves
BranchPropagatedUser's internal state alone as well as its user the Linear
Lifetime Checker.
2. A second commit that changes the internal bits of the BranchPropagatedUser to
store an Operand instead of a PointerUnion.
This will allow me to use the first commit to validate the second.
This will ensure that if an expert user is using this feature and makes a
mistake as a result of tweaking their code, they get an error. This will ensure
they do not ship and look into why this is happening.
This is not intended to be used by anyone except for expert stdlib users.
evaluator to precisely evaluate Builtin.assert_configuration.
Unify UnknownReason::Trap and UnknownReason::AssertionFailure error
values in the constant evaluator, now that we have 'condfail_message'
SIL instruction, which provides an error message for the traps.
@_semantics("constant_evaluable") annotation to denote constant
evaluable functions.
Add a test suite that uses the sil-opt pass ConstantEvaluableSubsetChecker.cpp
to check the constant evaluability of function in the OSLog
overlay.
This is the first in a series of patches that begin to hide the underlying
linear lifetime implementation underneath the facade of the linear lifetime
checker. I only updated the users that this applies to.
This is just a simple refactoring commit in preparation for hiding more of the
details of the linear lifetime checker. This is NFC, just moving around code.
The idea is that this can be used to work with things like load_borrow,
begin_borrow, SILFunctionArgument, results of begin_apply(in the future) and the like in a
generic way using exhaustive switches to make sure this code stays up to date.
I refactored code in SemanticARCOpts and some utilities in OwnershipUtils.cpp to
use these new APIs. The code looks a lot nicer and should be quite easy to
expand to handle new borrow introducers (e.x.: end_apply).