The intent for `@inline(always)` is to act as an optimization control.
The user can rely on inlining to happen or the compiler will emit an error
message.
Because function values can be dynamic (closures, protocol/class lookup)
this guarantee can only be upheld for direct function references.
In cases where the optimizer can resolve dynamic function values the
attribute shall be respected.
rdar://148608854
This attribute forces programmers to acknowledge every
copy that is required to happen in the body of the
function. Only those copies that make sense according
to Swift's ownership rules should be "required".
The way this is implemented as of now is to flag each
non-explicit copy in a function, coming from SILGen, as
an error through PerformanceDiagnostics.
* move some Cloner utilities from ContextCommon.swift directly into Cloner.swift
* add an `cloneRecursively` overload which doesn't require the `customGetCloned` closure argument
* some small cleanups
functions to compute them directly without a TypeLowering object, and
change a lot of getTypeLowering call sites to just use that.
There is one subtle change here that I think is okay: SILBuilder used to
use different TypeExpansionContexts when inserting into a global:
- getTypeLowering() always used a minimal context when inserting into
a global
- getTypeExpansionContext() always returned a maximal context for the
module scope
The latter seems more correct, as AFAIK global initializers are never
inlinable. If they are, we probably need to configure the builder with
an actual context properly rather than making global assumptions.
This is incremental progress towards computing this for most types
without a TypeLowering, and hopefully eventually removing TL entirely.
add `Test`, which is the SIL-equivalent of `FunctionTest`.
It's invocation closure gets a `TestContext` instead of a `FunctionContext`.
^ The commit message #2 will be skipped:
^ - test
This allows to move many SIL APIs and utilities, which require a context, to the SIL module.
The SIL-part of SwiftPassInvocation is extracted into a base class SILContext which now lives in SIL.
Also: simplify the begin/end-pass functions of the SwiftPassInvocation.
Convert a bunch of places where we're dumping to stderr and calling
`abort` over to using `ABORT` such that the message gets printed to
the pretty stack trace. This ensures it gets picked up by
CrashReporter.
If the method is a default witness methods (`selfType` != nil) it has generic self type.
In this case the generic self parameter is at depth 0 and the actual generic parameters of the substitution map are at depth + 1, e.g:
```
@convention(witness_method: P) <τ_0_0><τ_1_0 where τ_0_0 : GenClass<τ_1_0>.T>
^ ^
self params of substitution map at depth + 1
```
* factor out common methods of AST Type/CanonicalType into a `TypeProperties` protocol.
* add more APIs to AST Type/CanoncialType.
* move `MetatypeRepresentation` from SIL.Type to AST.Type and implement it with a swift enum.
* let `Builder.createMetatype` get a CanonicalType as instance type, because the instance type must not be a lowered type.
And move the implementation of `SIL.Type.canBeClass` to the AST Type. The SIL Type just calls the AST Type implementation.
Also rename `SIL.Type.canonicalASTType` -> `SIL.Type.astType`.
As the optimizer uses more and more AST stuff, it's now time to create an "AST" module.
Initially it defines following AST datastructures:
* declarations: `Decl` + derived classes
* `Conformance`
* `SubstitutionMap`
* `Type` and `CanonicalType`
Some of those were already defined in the SIL module and are now moved to the AST module.
This change also cleans up a few things:
* proper definition of `NominalTypeDecl`-related APIs in `SIL.Type`
* rename `ProtocolConformance` to `Conformance`
* use `AST.Type`/`AST.CanonicalType` instead of `BridgedASTType` in SIL and the Optimizer
* add missing APIs
* bridge the entries as values and not as pointers
* add lookup functions in `Context`
* make WitnessTable.Entry.Kind enum cases lower case
Make SILLInkage available in SIL as `SIL.Linkage`.
Also, rename the misleading Function and GlobalVariable ABI `isAvailableExternally` to `isDefinedExternally`
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)
Avoid heap-allocating an immortal FunctionTest with `new` because it
results in LSAN reporting a leak.
In fact, the "leaked" value wasn't leaked: a reference to it was stored
in a global map when the type's constructor ran. It was only a leak in
the sense that it was never freed, not that there was a dangling
allocation which couldn't be freed.
Work around this by storing the global instances themselves in a second
static structure. Store pointers to the instances into the global map
as before.
rdar://118134637
Introduce two modes of bridging:
* inline mode: this is basically how it worked so far. Using full C++ interop which allows bridging functions to be inlined.
* pure mode: bridging functions are not inlined but compiled in a cpp file. This allows to reduce the C++ interop requirements to a minimum. No std/llvm/swift headers are imported.
This change requires a major refactoring of bridging sources. The implementation of bridging functions go to two separate files: SILBridgingImpl.h and OptimizerBridgingImpl.h.
Depending on the mode, those files are either included in the corresponding header files (inline mode), or included in the c++ file (pure mode).
The mode can be selected with the BRIDGING_MODE cmake variable. By default it is set to the inline mode (= existing behavior). The pure mode is only selected in certain configurations to work around C++ interop issues:
* In debug builds, to workaround a problem with LLDB's `po` command (rdar://115770255).
* On windows to workaround a build problem.
At the cost of adding an unsafe bitcast implementation detail,
simplified the code involved to register a new FunctionTest when adding
one.
Also simplifies how Swift native `FunctionTest`s are registered with the
C++ registry.
Now, the to-be-executed thin closure for native Swift `FunctionTest`s is
stored under within the swift::test::FunctionTest instance corresponding
to it. Because its type isn't representable in C++, `void *` is used
instead. When the FunctionTest is invoked, a thunk is called which
takes the actual test function and bridged versions of the arguments.
That thunk unwraps the arguments, casts the stored function to the
appropriate type, and invokes it.
Thanks to Andrew Trick for the idea.
All SILArgument types are "block arguments". There are three kinds:
1. Function arguments
2. Phis
3. Terminator results
In every situation where the source of the block argument matters, we
need to distinguish between these three. Accidentally failing to
handle one of the cases is an perpetual source of compiler
bugs. Attempting to handle both phis and terminator results uniformly
is *always* a bug, especially once OSSA has phi flags. Even when all
cases are handled correctly, the code that deals with data flow across
blocks is incomprehensible without giving each case a type. This
continues to be a massive waste of time literally every time I review
code that involves cross-block control flow.
Unfortunately, we don't have these C++ types yet (nothing big is
blocking that, it just wasn't done). That's manageable because we can
use wrapper types on the Swift side for now. Wrapper types don't
create any more complexity than protocols, but they do sacrifice some
usability in switch cases.
There is no reason for a BlockArgument type. First, a function
argument is a block argument just as much as any other. BlockArgument
provides no useful information beyond Argument. And it is nearly
always a mistake to care about whether a value is a function argument
and not care whether it is a phi or terminator result.
Before this change, if a global variable is required to be statically initialized (e.g. due to @_section attribute), we don't allow its type to be a struct, only a scalar type works. This change improves on that by teaching MandatoryPerformanceOptimizations pass to inline struct initializer calls into initializer of globals, as long as they are simple enough so that we can be sure that we don't trigger recursive/infinite inlining.