`SWIFT_IMPORT_UNSAFE` is an escape hatch that can be used to make the Swift compiler ignore its usual safety heuristics for C++ types.
`SILDebugLocation` is better described as a self-contained Swift type.
Similar to 35263ef9.
Previously if one wanted to get an ASTNode, one needed to use the
getAsASTNode<T>() type. If one just wants to get out the type and use it in a
generic way using ASTNode there wasn't any way to do this... so I did it. We
actually have to do the marshalling here since ASTNodeTy and ASTNode have
different layouts despite them both being PointerUnions. So one can't just cast
in between them =---(.
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.
Calls to getters are implicit because the compiler inserts them on a property
access, but the location is useful in backtraces so it should be preserved.
rdar://109123395
This patch replaces the stateful generation of SILScope information in
SILGenFunction with data derived from the ASTScope hierarchy, which should be
100% in sync with the scopes needed for local variables. The goal is to
eliminate the surprising effects that the stack of cleanup operations can have
on the current state of SILBuilder leading to a fully deterministic (in the
sense of: predictible by a human) association of SILDebugScopes with
SILInstructions. The patch also eliminates the need to many workarounds. There
are still some accomodations for several Sema transformation passes such as
ResultBuilders, which don't correctly update the source locations when moving
around nodes. If these were implemented as macros, this problem would disappear.
This necessary rewrite of the macro scope handling included in this patch also
adds proper support nested macro expansions.
This fixes
rdar://88274783
and either fixes or at least partially addresses the following:
rdar://89252827
rdar://105186946
rdar://105757810
rdar://105997826
rdar://105102288
This change aims at reducing the need for SIL passes to check into the AST
storage of SILLocations. The end goal is to eventually merge this with the
autogenerated flag, but at the moment the emergent semantics of both properties
are not identical.
The pointsToEnd flag is only meaningful when combined with an AST node, and
moving it into the AST pointer frees up a bit in the flags bitfield for later
use.
We already have entry points for creating an ExtendedASTNodeLoc with an empty
location for diagnostics and a location for debugging. This does the inverse so
one can emit diagnostics that point at a terminator sourceloc without needing to
add a ReturnInst to the instruction which is illegal and would cause the
SILVerifier to assert.
When emitting debug info that references into a macro expansion, dump
the macro expansion buffer into a file on disk (in the temporary
directory) so that one can see the macro expansion buffers in the
source files themselves.
The test here validates that the generated LLVM IR looks correct, but
I'm having a problem getting LLDB to actually locate the source code
correctly.
The use of the SWIFT_INLINE_BITFIELD macros in SILNode were a constant source of confusion and bugs.
With this refactoring I tried to simplify the definition of "shared fields" in SILNode, SILValue and SILInstruction classes:
* Move `kind`, `locationKindAndFlags` and the 32-bit fields out of the 64-bitfield into their own member variables. This avoids _a lot_ of manual bit position computations.
* Now we have two separate "shared fields": an 8-bit field (e.g. for boolean flags) and a 32-bit field (e.g. for indices, which can potentially get large). Both fields can be used independently. Also, they are not "bit fields" per se. Instructions can use the field e.g. as a `bool`, `uint32_t`, or - if multiple flags are to be stored - as a packed bit field.
* With these two separate fields, we don't have the need for defining bitfields both in a base class _and_ in a derived value/instruction class. We can get rid of the complex logic which handles such cases. Just keep a check to catch accidental overlaps of fields in base and derived classes.
* Still use preprocessor macros for the implementation, but much simpler ones than before.
* Add documentation.
The function prologue of async funclets inherits its source location
from the hop_to_executor instruction. This makes it easier to produce
logical backtraces, since the PC in logical frames will always point
to the start if the function.
rdar://89776340
NOTE: debug_value [moved] appearing in the source code implies a _move was
used. So this will not effect current stable swift code.
This is just a first version of this that I am using to commit/bring up tests
for IRGen supporting a full dataflow version of this patch.
Big picture is that there is a bunch of work that is done in the LLVM level in
the coroutine splitter to work around communicating live variables in the
various coroutine func-lets. This logic is all done with debug.declare and we
would need to update that logic in the coroutine splitter to handle
debug.addr. Rather than do this, after some conversation, AdrianP and I realized
that we could get the same effect of a debug.declare by just redeclaring the
current live set of debug_value after each possible coroutine funclet start. To
do this in full generality, we need a full dataflow but just to bring this up we
initially perform a dominance propagation algorithm of the following sort:
1. We walk the CFG along successors. By doing this we guarantee that we visit
blocks after their dominators.
2. When we visit a block, we walk the block from start->end. During this walk:
a. We grab a new block state from the centralized block->blockState map. This
state is a [SILDebugVariable : DebugValueInst].
b. If we see a debug_value, we map blockState[debug_value.getDbgVar()] =
debug_value. This ensures that when we get to the bottom of the block, we
have pairs of SILDebugVariable + last debug_value on it.
c. If we see any coroutine funclet boundaries, we clone the current tracked
set of our block state and then walk up the dom tree dumping in each block
any debug_value with a SILDebugVariable that we have not already
dumped. This is maintained by using a visited set of SILDebugVariable for
each funclet boundary.
The end result is that at the beginning of each funclet we will basically
declare the debug info for an addr.
This is insufficient of course for moves that are in conditional control flow,
e.x.:
```
let x = Klass()
if boolValue {
await asyncCall()
let _ = _move(x)
}
```
but this at least lets me begin to write tests for this in lldb using straight
line code and work out the rest of the issues in CodeGen using those tests.
Those instructions should not be "visible" for debugging and for diagnostic messages.
Fixes a wrong "unreachable code" warning.
https://bugs.swift.org/browse/SR-14873
rdar://80237870
- 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.
Store the 1-byte kindAndFlags of SILLocation in the instruction's SILNode bitfield and only store SILLocation::storage in SILInstruction directly.
This reduces the space for the location from 2 to 1 word in SILInstruction.
My goal was to reduce the size of SILLocation. It now contains only of a storage union, which is basically a pointer and a bitfield containing the Kind, StorageKind and flags. By far, most locations are only single pointers to an AST node. For the few cases where more data needs to be stored, this data is allocated separately: with the SILModule's bump pointer allocator.
While working on this, I couldn't resist to do a major refactoring to simplify the code:
* removed unused stuff
* The term "DebugLoc" was used for 3 completely different things:
- for `struct SILLocation::DebugLoc` -> renamed it to `FilePosition`
- for `hasDebugLoc()`/`getDebugSourceLoc()` -> renamed it to `hasASTNodeForDebugging()`/`getSourceLocForDebugging()`
- for `class SILDebugLocation` -> kept it as it is (though, `SILScopedLocation` would be a better name, IMO)
* made SILLocation more "functional", i.e. replaced some setters with corresponding constructors
* replaced the hand-written bitfield `KindData` with C bitfields
* updated and improved comments
This ensures that we do not emit diagnostics onto these functions. I noticed we
were doing this with my work on opt-remarks when I was hitting diagnostics in
these functions in a set of subsequent commits.
The way that I found these is that I went through this file and looked for any
cases where we were never calling emitStmt on a user provided function body.
I also eliminated two places where we were setting a new DebugScope even though
preEmitFunction already does that for us.
The reason to do this is that one can now do:
```
if (auto debugLoc = i.getDebugLocation()) {
// do something with debug loc.
}
```
I also cleaned up the style a little bit by renaming the internal ivars to be
camelCase.
* [SILGenFunction] Don't create redundant nested debug scopes
Instead of emitting:
```
sil_scope 4 { loc "main.swift":6:19 parent 3 }
sil_scope 5 { loc "main.swift":7:3 parent 4 }
sil_scope 6 { loc "main.swift":7:3 parent 5 }
sil_scope 7 { loc "main.swift":7:3 parent 5 }
sil_scope 8 { loc "main.swift":9:5 parent 4 }
```
Emit:
```
sil_scope 4 { loc "main.swift":6:19 parent 3 }
sil_scope 5 { loc "main.swift":7:3 parent 4 }
sil_scope 6 { loc "main.swift":9:5 parent 5 }
```
* [IRGenSIL] Diagnose conflicting shadow copies
If we attempt to store a value with the wrong type into a slot reserved
for a shadow copy, diagnose what went wrong.
* [SILGenPattern] Defer debug description of case variables
Create unique nested debug scopes for a switch, each of its case labels,
and each of its case bodies. This looks like:
```
switch ... { // Enter scope 1.
case ... : // Enter scope 2, nested within scope 1.
<body-1> // Enter scope 3, nested within scope 2.
case ... : // Enter scope 4, nested within scope 1.
<body-2> // Enter scope 5, nested within scope 4.
}
```
Use the new scope structure to defer emitting debug descriptions of case
bindings. Specifically, defer the work until we can nest the scope for a
case body under the scope for a pattern match.
This fixes SR-7973, a problem where it was impossible to inspect a case
binding in lldb when stopped at a case with multiple items.
Previously, we would emit the debug descriptions too early (in the
pattern match), leading to duplicate/conflicting descriptions. The only
reason that the ambiguous description was allowed to compile was because
the debug scopes were nested incorrectly.
rdar://41048339
* Update tests
Commit 2948ec5ca98f8593584f2117bc92fe8d75f6f098 removed the
PointerUnion3 and PointerUnion4 aliases and migrated everything
to the variadic template. Let's do the same here to get the
build running.
While tightening the requirements of the debug info generator in
IRGenSIL I noticed that SILCloner didn't correctly transfer variable
debug info on alloc_box and alloc_stack instructions. In order to make
these mistakes easier to find I added an assertion to SILBuilder and
fixed all issues uncovered by that assertion, too.
The result is a moderate increase in debug info coverage in optimized code.
On stdlib/public/core/OSX/x86_64/Swift.o "variables with location"
increases from 60134 to 60299.
There was one case which was not handled and that's inlining of a compiler intrinsic.
In this case there is a different location type on the function call.
rdar://problem/49651421
Since SIL instructions get used a /lot/, this may result in a
compile-time speedup and/or lowered peak memory usage.
(It's not a lot in practice, though.)
Summary:
CodeView does not recognize zero as an artificial line location
and so a line location of zero causes unexpected behavior when
stepping through user code. If we find a line location of zero
and our scope has not changed, we use the most recent debug
location. That is expected to be the user code that most likely
relates to the current instruction and is similar to the behavior
in LLDB.
Test Plan:
test/DebugInfo/linetable-codeview.swift