This became necessary after recent function type changes that keep
substituted generic function types abstract even after substitution to
correctly handle automatic opaque result type substitution.
Instead of performing the opaque result type substitution as part of
substituting the generic args the underlying type will now be reified as
part of looking at the parameter/return types which happens as part of
the function convention apis.
rdar://62560867
The cast optimizer was too eager to fold casts where the source and
target lowered types were the same, even though the formal types
might be different. Move the classifyFeasibility() check to deal
with this case.
Also in dead code elimination we have to mark all operands of a
cast branch instruction as live, not just the first operand,
otherwise we miss the special 'type dependent' self metadata
operand and replace it with 'undef'.
SIL type lowering erases DynamicSelfType, so we generate
incorrect code when casting to DynamicSelfType. Fixing this
requires a fair amount of plumbing, but most of the
changes are mechanical.
Note that the textual SIL syntax for casts has changed
slightly; the target type is now a formal type without a '$',
not a SIL type.
Also, the unconditional_checked_cast_value and
checked_cast_value_br instructions now take the _source_
formal type as well, just like the *_addr forms they are
intended to replace.
ProtocolConformanceRef already has an invalid state. Drop all of the
uses of Optional<ProtocolConformanceRef> and just use
ProtocolConformanceRef::forInvalid() to represent it. Mechanically
translate all of the callers and callsites to use this new
representation.
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.
This mostly requires changing various entry points to pass around a
TypeConverter instead of a SILModule. I've left behind entry points
that take a SILModule for a few methods like SILType::subst() to
avoid creating even more churn.
This was not a real leak, because it only happened in an error condition where the block ends in an trap instructon anyway.
But it must be fixed to make the MemoryLifetimeVerifier happy.
Specifically:
1. I removed an extra defensive copy that we put in place some time ago that
isn't really warranted. We know that we have an @owned value, so can safely just
pass the value as a @guaranteed parameter. This also eliminates an ownership
error that would occur due to my not having updated this code for ownership in
tree.
2. I also ensured that if we are performing a loadable address bridging cast ->
value bridging cast that we store the loadable value back into memory after we
perform the cast. Otherwise, it appears to leak to the ownership verifier.
I also centralized the non-ownership tests for this into one place
(const_fold_objc_bridge.sil => constant_propagation_objc.sil).
Specifically, in this part of the cast optimizer we are trying to optimize casts
that can be done in two parts. As an example consider: NSObject ->
Array<Any>. In this case, we first cast from NSObject -> NSArray and then try to
conditionally bridge to Array<Any> from NSArray.
The problem is we did not destroy the NSObject correctly if the first cast
failed. I couldn't figure out how to create an actual swift test case that
produces this problem since we are pretty conservative about triggering this
code path. But in SIL it is pretty easy and in ossa, we trigger the ownership
verifier.
This is another victory for the ownership verifier!
rdar://51753580
The specific problem here is that we are setting the insertion point of a
SILBuilder and not unsetting it. I fixed the problem by creating a separate
builder so the original builder stays put.
I originally came across this in my work on moving ownership stripping after the
diagnostic passes. This patch fixes it without my other changes to ease
cherry-picking to 5.1.
I also added more test coverage by expanding the test case to also handle
copy_on_success and take_always.
rdar://51093557
This is a large patch; I couldn't split it up further while still
keeping things working. There are four things being changed at
once here:
- Places that call SILType::isAddressOnly()/isLoadable() now call
the SILFunction overload and not the SILModule one.
- SILFunction's overloads of getTypeLowering() and getLoweredType()
now pass the function's resilience expansion down, instead of
hardcoding ResilienceExpansion::Minimal.
- Various other places with '// FIXME: Expansion' now use a better
resilience expansion.
- A few tests were updated to reflect SILGen's improved code
generation, and some new tests are added to cover more code paths
that previously were uncovered and only manifested themselves as
standard library build failures while I was working on this change.
The ownership kind is Any for trivial types, or Owned otherwise, but
whether a type is trivial or not will soon depend on the resilience
expansion.
This means that a SILModule now uniques two SILUndefs per type instead
of one, and serialization uses two distinct sentinel IDs for this
purpose as well.
For now, the resilience expansion is not actually used here, so this
change is NFC, other than changing the module format.
This could probably be an error, but I am leaving it to preserve previous
behavior. The reason I am hoisting this is that I am hoisting it before we
potentially split a basic block. When we evaluate if we can early exit, we
should never do work before we know that we will emit /something/.
This code today only handles the following two instructions:
1. checked_cast_addr_br
2. unconditional_checked_cast_addr
We were asserting that the source/dest of these values were addresses... but
they are obviously are!