The overhead of uniquing the locations in a Densemap isn't worth any of
the potential memory savings: While this adds an extra pointer and
unsigned to each SILInstruction, any extra memory is completely lost in
the noise (measured on a release -emit-ir build of the x86_64 stdlib).
This is not too surpising as the ratio between SILInstructions and unique
SILLocations is not very high and the DenseMap also needs space.
<rdar://problem/22706994>
remove the mixed concept that was SILFileLocation.
Also add support for a third type of underlying storage that will be used
for deserialized debug lcoations from textual SIL.
NFC
<rdar://problem/22706994>
Similarly to how we've always handled parameter types, we
now recursively expand tuples in result types and separately
determine a result convention for each result.
The most important code-generation change here is that
indirect results are now returned separately from each
other and from any direct results. It is generally far
better, when receiving an indirect result, to receive it
as an independent result; the caller is much more likely
to be able to directly receive the result in the address
they want to initialize, rather than having to receive it
in temporary memory and then copy parts of it into the
target.
The most important conceptual change here that clients and
producers of SIL must be aware of is the new distinction
between a SILFunctionType's *parameters* and its *argument
list*. The former is just the formal parameters, derived
purely from the parameter types of the original function;
indirect results are no longer in this list. The latter
includes the indirect result arguments; as always, all
the indirect results strictly precede the parameters.
Apply instructions and entry block arguments follow the
argument list, not the parameter list.
A relatively minor change is that there can now be multiple
direct results, each with its own result convention.
This is a minor change because I've chosen to leave
return instructions as taking a single operand and
apply instructions as producing a single result; when
the type describes multiple results, they are implicitly
bound up in a tuple. It might make sense to split these
up and allow e.g. return instructions to take a list
of operands; however, it's not clear what to do on the
caller side, and this would be a major change that can
be separated out from this already over-large patch.
Unsurprisingly, the most invasive changes here are in
SILGen; this requires substantial reworking of both call
emission and reabstraction. It also proved important
to switch several SILGen operations over to work with
RValue instead of ManagedValue, since otherwise they
would be forced to spuriously "implode" buffers.
If a value is returned as @owned, we can move the epilogue retain
to the caller and convert the return value to @unowned. This gives
ARC optimizer more freedom to optimize the retain out on the caller's
side.
It appears that epilgue retains are harder to find than epilogue
releases. Most of the time they are not in the return block.
(1) Sometimes, they are in predecessors
(2) Sometimes they come from a call which returns an @owned return value.
This should be improved if we fix (1) and go bottom up.
(3) We do not handle exploded retain_value.
Currently, this catches a small number of opportunities.
We probably need to improve epilogue retain matcher if we are to handle
more cases.
This is part of rdar://24022375.
We also need some refactoring in the pass. e.g. break functions into smaller
functions. I will do with subsequent commit.
When a dependent type is mapped into context, the result will either be
an archetype or a concrete type. The latter occurs if a same-type
constraint exists between the dependent type and the concrete type.
The logic to decide if a type should be passed directly or indirectly
was not handling this case if an interface type was passed down -- we
would just check if there was a class constraint present.
This resulted in mismatching conventions between an interface type and
its corresponding contextual type, which would trigger assertions.
Note that same-type constraints between generic parameters and concrete
types are still not supported for other reasons; the subject of the
constraint must still be an associated type of a generic parameter.
Fixes <rdar://problem/24687460>.
When we have all the epilogue releases. Make sure they cover all the non-trivial
parts of the base. Otherwise, treat as if we've found no releases for the base.
Currently. this is a NFC other than epilogue dumper. I will wire it up with
function signature with next commit.
This is part of rdar://22380547
Dead function elimination deletes functions making them zombies. A zombie is a
function whose name only exists because debug info might still refer to it.
However, later passes of specialization might create a new function by the same
name again. We now have a zombie function (which is just an alias to a deleted
method stub) and a function definition.
No test case since I could not reduce this to a small test case.
rdar://24659988
Note: this is not the same as one path does not have value. A path can have no
value when we can not find a projection path between Base and Derived.
If we've found paths for both projections, and they turn'ed out to be both empty.
Its safe to say that they are accessing the same fields in the object.
I failed to create a test case as the changed code is currently not reached with
the current way we use it.
But it will be used as i use projection to do more analysis on epilogue release
matcher.
So instead of only being able to match %1 and release %1 in (1). we
can also match %1 with (release %2, and release%3, i.e. exploded release_value)
in (2).
(1)
foo(%1)
strong_release %1
(2)
foo(%1)
%2 = struct_extract %1, field_a
%3 = struct_extract %1, field_b
strong_release %2
strong_release %3
This will allow function signature to better move the release instructions to
the callers.
Currently, this is a NFC other than testing using the epilogue match dumper.
There's a group of methods in `DeclContext` with names that start with *is*,
such as `isClassOrClassExtensionContext()`. These names suggests a boolean
return value, while the methods actually return a type declaration. This
patch replaces the *is* prefix with *getAs* to better reflect their interface.
The logic that detects type circularity in TypeLowering has been replaced in
Sema. By exiting as soon as an address-only type is detected, we can avoid
walking the rest and gain some speedup.
Previously, we exploded argument to the most-derived fields, i.e. the field that
can no longer be exploded further. And in the spliced (newly created) function,
we form aggregates if necessary.
Changing this to explode only to the deepest level accessed, this enables us to
create the projection tree nodes for fields of which its level is accessed, instead of
all fields on all levels.
Note: this also changes the definition of a leaf node. Leaf node now means the node
which does not have children based on current explosion (it however could have children
if exploded further).
I am refining the old projection tree first before (mostly copying) it to create the
new projection tree.
SIL already has a pretty good infrastructure for tail-allocated operands, although
it's not enforced in any way. SwitchEnumInstBase would also benefit from this if
we were willing to make it a template, or if we had a way to override the 'final'
requirement on llvm::TrailingObjects.
For long names this is easier to read and in most cases the omitted information can be seen in the actual SIL code.
With the option -Xllvm -sil-full-demangle the old behavior can be restored.
Headers in include/ are meant to be used across libraries, headers in lib/
are only used within that library.
Thanks @jrose-apple for pointing this out.
Certain type circularities weren't being checked until this point. Such as
```
struct X<T> { let a: X<X> }
struct Y<T> { let a: (Int, Y<Y>) }
enum Z<T> { case A(Optional<Z<Z>>) }
```
We introduce a more comprehensive approach to detect these in type checker.
After name lookup, exam each value field in declared structs and enums for
self-reference types that creates inifinite sizes.
This will be used to help IRGen record protocol requirements
with resilient default implementations in protocol metadata.
To enable testing before all the Sema support is in place, this
patch adds SIL parser, printer and verifier support for default
witness tables.
For now, SILGen emits empty default witness tables for protocol
declarations in resilient modules, and IRGen ignores them when
emitting protocol metadata.
inlined-at chain.
The previous implementation was only correct for cases where the inliner
inlined bottom-up in the call graph, which happened to cover the majority
of all cases.
rdar://problem/24462475
function signature opt.
Instead of replacing %1 with UNDEF in debugvalueinst %1, we form an aggregate,
taking the alive part of %1 and fill the dead part with undef.
rdar://23727705