This patch replace all in-memory objects of DebugValueAddrInst with
DebugValueInst + op_deref, and duplicates logics that handles
DebugValueAddrInst with the latter. All related check in the tests
have been updated as well.
Note that this patch neither remove the DebugValueAddrInst class nor
remove `debug_value_addr` syntax in the test inputs.
ARC operations don't have an effect on immortal objects, like the empty array singleton or statically allocated arrays.
Therefore we can freely remove and retain/release instructions on such objects, even if there is no paired balanced ARC operation.
This optimization can only be done with a minimum deployment target of Swift 5.1, because in that version we added immortal ref count bits.
The optimization is implemented in libswift. Additionally, the remaining logic of simplifying strong_retain and strong_release is also ported to libswift.
rdar://81482156
Track in-use iterators and update them both when instructions are
deleted and when they are added.
Safe iteration in the presence of arbitrary changes now looks like
this:
for (SILInstruction *inst : deleter.updatingRange(&bb)) {
modify(inst);
}
Fix innumerable latent bugs with iterator invalidation and callback invocation.
Removes dead code earlier and chips away at all the redundant copies the compiler generates.
We cannot replace a load from a global let-variable with a function_ref, if the referenced function would violate the resilience rules.
That means if a non-public function_ref would be inlined into a function which is serialized.
We must make sure the new load is inserted where the old load was instead of
inserting it at the unchecked_take_enum_data_addr, since the
unchecked_take_enum_data_addr may be in a different block from old load /and/
old load may not post-dominate that point. This was just a thinko.
Even if the enum type is not trivial (because it has not trivial payloads for some cases), a release of such an enum can be removed if the enum is constructed with a trivial case.
Instead make `findJointPostDominatingSet` a stand-alone function.
There is no need to keep the temporary SmallVector alive across multiple calls of findJointPostDominatingSet for the purpose of re-using malloc'ed memory. The worklist usually contains way less elements than its small size.
This involves folding a metatype into the alloc_ref_dynamic and we always
replace the alloc_ref_dynamic with an alloc_ref so this is always safe from an
ownership perspective.
The key thing is that all of these while they do modify the branches of the CFG
do not invalidate block level CFG analyses like dominance and dead end
blocks.
I implemented specifically the promotion from switch_enum_addr -> switch_enum
for loadable types.
NOTE: I did not add support for the inject_enum_addr based conversion to br since that
optimization deletes an edge from the CFG, potentially invalidating CFG
properties. Since OSSA needs to use DeadEndBlocks, we want to avoid changing
reachability in any way with our SILCombine transforms.
All of the non-SILCombiner specific helpers have already been updated for OSSA,
so this was not too bad.
NOTE: I also added two small combines that delete copy_value, destroy_value with
.none arguments. The reason why I added this is that this is a pretty small
addition and many of the tests of this code rely on SILCombine being able to
eliminate such operations on thin_to_thick_function.
NOTE: I also disabled TypePropagation in OSSA, we are going to redo that code
when we bring up opaque values.
From an ownership perspective, this is just eliminating a non-lifetime ending
use. The new instructions we create are not connecting to the underlying object
anymore.
This reverts commit 0a0f8cffc1.
Currently the memory lifetime verifier (I believe due to the switch_enum) is not
caring that we are not emitting destroy_addr for an enum address along paths
where we know the underlying enum case is trivial.
This transform eliminated that switch_enum_addr causing the memory lifetime
verifier to then trigger.
Disabling to unblock the bots!
NOTE: The stdlib count/capacity propagation code is tested in an end<->end
fashion in a separate Swift test. Once I flip the switch, that test will run.
The code is pretty simple, so I feel relatively confident with it.
The one opt we perform here is that we promote fix_lifetime on loadable
alloc_stack addresses to fix_lifetimes on objects by loading the underlying
value and putting the fix lifetime upon it.
This caused a problem when propagating the concrete type of an existential: if the concrete type is itself an opened existential, it was not added to the OpenedArchetypeTracker.
https://bugs.swift.org/browse/SR-13444
rdar://problem/68077098
Optimize the unconditional_checked_cast_addr in this pattern:
%box = alloc_existential_box $Error, $ConcreteError
%a = project_existential_box $ConcreteError in %b : $Error
store %value to %a : $*ConcreteError
%err = alloc_stack $Error
store %box to %err : $*Error
%dest = alloc_stack $ConcreteError
unconditional_checked_cast_addr Error in %err : $*Error to ConcreteError in %dest : $*ConcreteError
to:
...
retain_value %value : $ConcreteError
destroy_addr %err : $*Error
store %value to %dest $*ConcreteError
This lets the alloc_existential_box become dead and it can be removed in following optimizations.
The same optimization is also done for conditional_checked_cast_addr.
There is also an implication for debugging:
Each "throw" in the code calls the runtime function swift_willThrow. The function is used by the debugger to set a breakpoint and also add hooks.
This optimization can completely eliminate a "throw", including the runtime call.
So, with optimized code, the user might not see the program to break at a throw, whereas in the source code it is actually throwing.
On the other hand, eliminating the existential box is a significant performance win and we don't guarantee any debugging behavior for optimized code anyway. So I think this is a reasonable trade-off.
I added an option "-Xllvm -keep-will-throw-call" to keep the runtime call which can be used if someone want's to reliably break on "throw" in optimized builds.
rdar://problem/66055678
Propagate a value from a static "let" global variable.
This optimization is also done by GlobalOpt, but not with de-serialized globals, which can occur with cross-module optimization.
Replaces an alloc_stack of an enum by an alloc_stack of the payload if only one enum case (with payload) is stored to that location.
For example:
%loc = alloc_stack $Optional<T>
%payload = init_enum_data_addr %loc
store %value to %payload
...
%take_addr = unchecked_take_enum_data_addr %loc
%l = load %take_addr
is transformed to
%loc = alloc_stack $T
store %value to %loc
...
%l = load %loc
https://bugs.swift.org/browse/SR-12710
MSVC does not realize that the switch is exhaustive and requires that
the path is explicitly marked as unreachable. This silences the C4715
warning ("not all control paths return a value").
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.