Instead of creating and destroying a SILProfiler
per TopLevelCodeDecl, setup a single profiler
for the top-level entry point function, and visit
all the TopLevelCodeDecls when mapping regions.
So far, function effects only included escape effects.
This change adds side-effects (but they are not computed, yet).
It also involves refactoring of the existing escape effects.
Also the SIL effect syntax changed a bit. Details are in docs/SIL.rst
It makes no sense to operate on the block's instruction list without
also including SILBasicBlock.h anyway. Similarly, it doesn't make
sense to query the entry block without including SILFunction.h.
Now we can call these simple getters in critical-path loops assuming
they are as cheap as a load. I was avoiding calling these in critical
path code, which resulted in less readability and consistency across
the code base.
* [SILOptimizer] Add prespecialization for arbitray reference types
* Fix benchmark Package.swift
* Move SimpleArray to utils
* Fix multiple indirect result case
* Remove leftover code from previous attempt
* Fix test after rebase
* Move code to compute type replacements to SpecializedFunction
* Fix ownership when OSSA is enabled
* Fixes after rebase
* Changes after rebasing
* Add feature flag for layout pre-specialization
* Fix pre_specialize-macos.swift
* Add compiler flag to benchmark build
* Fix benchmark SwiftPM flags
So far, argument effects were printed in square brackets before the function name, e.g.
```
sil [escapes !%0.**, !%1, %1.c*.v** => %0.v**] @foo : $@convention(thin) (@guaranteed T) -> @out S {
bb0(%0 : $*S, %1 : @guaranteed $T):
...
```
As we are adding more argument effects, this becomes unreadable.
To make it more readable, print the effects after the opening curly brace, and print a separate line for each argument. E.g.
```
sil [ossa] @foo : $@convention(thin) (@guaranteed T) -> @out S {
[%0: noescape **]
[%1: noescape, escape c*.v** => %0.v**]
bb0(%0 : $*S, %1 : @guaranteed $T):
...
```
Include the parent `ModuleDecl` when serializing a `SILFunction` so that it is available on deserialized functions even though the full `DeclContext` is not present. With the parent module always available we can reliably compute whether the `SILFunction` comes from a module that was imported `@_weakLinked`.
Serialize the `DeclContext` member of `SILFunction` so that it can be used to look up the module that a function belongs to in order to compute weak import status.
Resolves rdar://98521248
The effect of declaring an import `@_weakLinked` is to treat every declaration from the module as if it were declared with `@_weakLinked`. This is useful in environments where entire modules may not be present at runtime. Although it is already possible to instruct the linker to weakly link an entire dylib, a Swift attribute provides a way to declare intent in source code and also opens the door to diagnostics and other compiler behaviors that depend on knowing that all the module's symbols will be weakly linked.
rdar://96098097
Snapshots are copies of a function at a given point in time.
Currently it's only used for running passes repeatedly for performance profiling.
In future it can be used for caching when doing lazy evaluation in the pipeline.
non-throwing functions.
Activating swift-functions-errors tests
Inserting macros and additional parameters in C and C++ functions following the pattern to lowering to LLVM IR.
If such declarations have availability conditions they have to be
kept alive until IRGen to emit opaque type descriptor that is going
be used at runtime to determine the underlying type.
This is important for "optimized" mode only because in non-optimized
mode "shared" symbol survives SILGen.
It's used to implement `InstructionSet` and `ValueSet`: sets of SILValues and SILInstructions.
Just like `BasicBlockSet` for basic blocks, the set is implemented by setting bits directly in SILNode.
This is super efficient because insertion and deletion to/from the set are basic bit operations.
The cost is an additional word in SILNode. But this is basically negligible: it just adds ~0.7% of memory used for SILInstructions.
In my experiments, I didn't see any relevant changes in memory consumption or compile time.
The main point of this change is to make sure that a shared function always has a body: both, in the optimizer pipeline and in the swiftmodule file.
This is important because the compiler always needs to emit code for a shared function. Shared functions cannot be referenced from outside the module.
In several corner cases we missed to maintain this invariant which resulted in unresolved-symbol linker errors.
As side-effect of this change we can drop the shared_external SIL linkage and the IsSerializable flag, which simplifies the serialization and linkage concept.
Store a list of argument effects in a function, which specify if and how arguments escape.
Such effects can be specified in the Swift source code (for details see docs/ReferenceGuides/UnderscoredAttributes.md) or derived in an optimization pass.
For details see the documentation in SwiftCompilerSources/Sources/SIL/Effects.swift.
Returns true if this SILFunction must be a defer.
NOTE: This may return false for defer statements that have been
deserialized without a DeclContext. This means that this is guaranteed to
be correct for SILFunctions in Raw SIL that were not deserialized as
canonical. Thus one can use it for diagnostics.
- If any of the `-g<kind>` flag is given -- except `-gnone`, debug
info will be printed into every generated SIL files.
- The `-gsil` is deprecated in favor of `-sil-based-debuginfo`. The
SILDebugInfoGenerator Pass now generates intermediate SIL file with
name "<output file>.sil_dbg_<n>.sil". Other functionalities of that
Pass remain the same.
This is the initial version of a buildable SIL definition in libswift.
It defines an initial set of SIL classes, like Function, BasicBlock, Instruction, Argument, and a few instruction classes.
The interface between C++ and SIL is a bridging layer, implemented in C.
It contains all the required bridging data structures used to access various SIL data structures.
This showed up when trying to convert swift-package-manager to build
using static linking on Windows. We would not correctly identify the
module as being static due to there being no DeclContext for emission.
When an instruction is "deleted" from the SIL, it is put into the SILModule::scheduledForDeletion list.
The instructions in this list are eventually deleted for real in SILModule::flushDeletedInsts(), which is called by the pass manager after each pass run.
In other words: instruction deletion is deferred to the end of a pass.
This avoids dangling instruction pointers within the run of a pass and in analysis caches.
Note that the analysis invalidation mechanism ensures that analysis caches are invalidated before flushDeletedInsts().
In theory we could map opened archetypes per module because opened archetypes _should_ be unique across the module.
But currently in some rare cases SILGen re-uses the same opened archetype in multiple functions.
The fix is to add the SILFunction to the map's key.
That also requires that we update the map whenever instructions are moved from one function to another.
This fixes a compiler crash.
rdar://76916931
And rename MemoryDataflow -> BitDataflow.
MemoryLifetime contained MemoryLocations, MemoryDataflow and the MemoryLifetimeVerifier.
Three independent things, for which it makes sense to have them in three separated files.
NFC.
* add a BasicBlockSetVector class
* add a second argument to BasicBlockFlag::set, for the set value.
* rename BasicBlockSet::remove -> BasicBlockSet::erase.
* add a MaxBitfieldID statistics value in SILFunction.cpp
Previously, the name of the entry point function was always main. Here,
a new frontend flag is added to enable an arbitrary name to be
specified.
rdar://58275758
* Instead of passing the vector type as template argument, use a SmallVector and just pass the inline size
* Increase the inline size to 32. Found by experiment, this fits 90% of all functions.
* add an API for getting data for newly created blocks.
It can be used by transforms to store temporary data per basic block.
It is very efficient: only a single memory allocation is needed and no maps are used to lookup data.
```
@_specialize(exported: true, spi: SPIGroupName, where T == Int)
public func myFunc() { }
```
The specialized entry point is only visible for modules that import
using `_spi(SPIGroupName) import ModuleDefiningMyFunc `.
rdar://64993425
This attribute allows to define a pre-specialized entry point of a
generic function in a library.
The following definition provides a pre-specialized entry point for
`genericFunc(_:)` for the parameter type `Int` that clients of the
library can call.
```
@_specialize(exported: true, where T == Int)
public func genericFunc<T>(_ t: T) { ... }
```
Pre-specializations of internal `@inlinable` functions are allowed.
```
@usableFromInline
internal struct GenericThing<T> {
@_specialize(exported: true, where T == Int)
@inlinable
internal func genericMethod(_ t: T) {
}
}
```
There is syntax to pre-specialize a method from a different module.
```
import ModuleDefiningGenericFunc
@_specialize(exported: true, target: genericFunc(_:), where T == Double)
func prespecialize_genericFunc(_ t: T) { fatalError("dont call") }
```
Specially marked extensions allow for pre-specialization of internal
methods accross module boundries (respecting `@inlinable` and
`@usableFromInline`).
```
import ModuleDefiningGenericThing
public struct Something {}
@_specializeExtension
extension GenericThing {
@_specialize(exported: true, target: genericMethod(_:), where T == Something)
func prespecialize_genericMethod(_ t: T) { fatalError("dont call") }
}
```
rdar://64993425
The leak happened in this scenario:
1. A function becomes dead and gets deleted (which means: it gets added to the zombie-list)
2. A function with the same name is created again. This can happen with specializations.
In such a case we just removed the zombie function from the zombie-list without deleting it.
But we cannot delete zombie functions, because they might still be referenced by metadata, like debug-info.
Therefore the right fix is to resurrect the zombie function if a new function is created with the same name.
rdar://problem/66931238