To handle borrowing operands that produce a dependence value but do not create a
nested borrow scope. This includes non-reborrow borrowed-from and guaranteed
mark_dependence [nonescaping].
Although I don't plan to bring over new assertions wholesale
into the current qualification branch, it's entirely possible
that various minor changes in main will use the new assertions;
having this basic support in the release branch will simplify that.
(This is why I'm adding the includes as a separate pass from
rewriting the individual assertions)
When rewriting uses of a noncopyable value, the move-only checker failed to take into account
the scope of borrowing uses when establishing the final lifetimes of values. One way this
manifested was when borrowed values get reabstracted from value to in-memory representations,
using a store_borrow instruction, the lifetime of the original borrow would be ended immediately
after the store_borrow begins rather than after the matching end_borrow. Fix this by, first,
changing `store_borrow` to be treated as a borrowing use of its source rather than an
interior-pointer use; this should be more accurate overall since `store_borrow` borrows the
entire source value for a well-scoped duration balanced by `end_borrow` instructions. That done,
change MoveOnlyBorrowToDestructureUtils so that when it sees a borrow use, it ends the borrow
at the end(s) of the use's borrow scope, instead of immediately after the beginning of the use.
This patch migrates the compiler off of the deprecated LLVM APIs where I
can.
- APInt::getAllOnesValue -> APInt::getAllOnes
- APInt::getNullValue -> APInt::getZero
- APInt::isNullValue -> APInt::isZero
- APInt::getMinSignedBits -> APInt::getSignificantBits
- clang::Module::submodule_{begin,end} -> clang::Module::submodules
This is phase-1 of switching from llvm::Optional to std::optional in the
next rebranch. llvm::Optional was removed from upstream LLVM, so we need
to migrate off rather soon. On Darwin, std::optional, and llvm::Optional
have the same layout, so we don't need to be as concerned about ABI
beyond the name mangling. `llvm::Optional` is only returned from one
function in
```
getStandardTypeSubst(StringRef TypeName,
bool allowConcurrencyManglings);
```
It's the return value, so it should not impact the mangling of the
function, and the layout is the same as `std::optional`, so it should be
mostly okay. This function doesn't appear to have users, and the ABI was
already broken 2 years ago for concurrency and no one seemed to notice
so this should be "okay".
I'm doing the migration incrementally so that folks working on main can
cherry-pick back to the release/5.9 branch. Once 5.9 is done and locked
away, then we can go through and finish the replacement. Since `None`
and `Optional` show up in contexts where they are not `llvm::None` and
`llvm::Optional`, I'm preparing the work now by going through and
removing the namespace unwrapping and making the `llvm` namespace
explicit. This should make it fairly mechanical to go through and
replace llvm::Optional with std::optional, and llvm::None with
std::nullopt. It's also a change that can be brought onto the
release/5.9 with minimal impact. This should be an NFC change.
It's equivalent to getBorrowIntroducingUserResult except that it's less
convenient to use. There's only ever one result, so there's no need for
a visitor. Updated all users to call getBorrowIntroducingUserResult
instead.
`getValue` -> `value`
`getValueOr` -> `value_or`
`hasValue` -> `has_value`
`map` -> `transform`
The old API will be deprecated in the rebranch.
To avoid merge conflicts, use the new API already in the main branch.
rdar://102362022
For those who are unaware, a store_borrow is an instruction that is needed so
that we can without adding ARC traffic materialize a guaranteed object value
into memory so we can pass it as an in_guaranteed argument. It has not had its
model completely implemented due to time. I am going to add some information
about it in this commit message for others.
From a model semantic perspective, a store_borrow is meant to allow for a
guaranteed value to be materialized into memory safely for a scoped region of
time and be able to guarantee that:
1. The guaranteed value that was stored is always live.
2. The memory is never written to within that region.
The natural way to model this type of guaranteeing behavior from an object to an
address is via a safe interior pointer formulation and thus with that in mind I
made it so that store_borrow returned an address that was an interior pointer of
the guaranteed value. Sadly, we have not changed the compiler yet to use this
effectively since we in store_borrow code paths generally just use the input
address. That being said, in this PR I begin to move us toward this world by
making store_borrow's src operand an InteriorPointerOperand. This means that we
will require the borrowed value to be alive at all use points of the
store_borrow result. That will not have a large effect today but I am going to
loop back around and extend that.
There is additional work here that I wish to accomplish in the future is that I
would like to define an end_store_borrow instruction to explicitly end the scope
in which there is a condition on the borrow. Then we would require that the
memory we are using to for sure never be written to in that region and maybe
additionally try to give some sort of guarantee around exclusivity (consider if
we made it so that we could only store_borrow into an alloc_stack with certain
conditions). Not sure about the last one yet. But philosophically since we are
using this to just handle reabstraction suggests we can do something more
constrained.
Instead of bailing on ownership functions in SILCombine::run, we will
bail in individual visitors. This way, as SILCombine is updated we can
paritially support ownership across the pass.
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.
Returns `true` if `T.Type` is known to refer to a concrete type. The
implementation allows for the optimizer to specialize this at -O and
eliminate conditional code.
Includes `Swift._isConcrete<T>(T.Type) -> Bool` wrapper function.
NOTE:
1. To test this I changed UnaryOp_match to use this under the hood.
2. These types of m_##ID##Inst matchers now will only accept compound types and
I added a static assert to verify that this mistake doesn't happen. We
previously had matchers that would take an int or the like to match tuple
extract patterns. I converted those to use TupleExtractOperation that also
properly handles destructures.
The SIL generation for this builtin also changes: instead of generating the cond_fail instructions upfront, let the optimizer generate it, if the operand is a static string literal.
In worst case, if the second operand is not a static string literal, the Builtin.condfail is lowered at the end of the optimization pipeline with a default message: "unknown program error".
The SIL generation for this builtin also changes: instead of generating the cond_fail instructions upfront, let the optimizer generate it, if the operand is a static string literal.
In worst case, if the second operand is not a static string literal, the Builtin.condfail is lowered at the end of the optimization pipeline with a default message: "unknown program error".
For example:
%0 = string_literal "abc"
%1 = integer_literal 0x8000000000000000
%2 = builtin "stringObjectOr_Int64" (%0, %1)
%3 = integer_literal 0x4000000000000000
%4 = builtin "and_Int64" (%2, %3)
In this case we know that %4 is 0.
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.
Replace `NameOfType foo = dyn_cast<NameOfType>(bar)` with DRY version `auto foo = dyn_cast<NameOfType>(bar)`.
The DRY auto version is by far the dominant form already used in the repo, so this PR merely brings the exceptional cases (redundant repetition form) in line with the dominant form (auto form).
See the [C++ Core Guidelines](https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#es11-use-auto-to-avoid-redundant-repetition-of-type-names) for a general discussion on why to use `auto` to avoid redundant repetition of type names.
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>.
Strict aliasing only applies to memory operations that use strict
addresses. The optimizer needs to be aware of this flag. Uses of raw
addresses should not have their address substituted with a strict
address.
Also add Builtin.LoadRaw which will be used by raw pointer loads.