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
Summary:
There are a few problems with how Swift currently emits location
information for CodeView.
1. WinDbg does not work well with column information so all column
locations must be set to zero.
2. Some instructions, e.g., ``a + b``, will emit ``@llvm.trap()``
and ``unreachable``. Those instructions should have artificial
locations, i.e., they should have a line location of zero.
3. Some instructions, e.g., ``a / b``, will emit ``unreachable``
sandwiched between other code for that instruction. This makes
WinDbg confused and it cannot decide which set of instructions
to break on. Those instructions should have the same line location
as the others.
4. There are several prologue instructions with artificial line
locations that create breaks in the linetables. Those instructions
should have valid line locations, usually at the start of the
function.
5. Case bodies have cleanup instructions with artificial line
locations unless it has a ``do`` block. Those locations should
be the last line in the case block.
Test Plan:
test/DebugInfo/basic.swift
test/DebugInfo/columns.swift
test/DebugInfo/linetable-codeview.swift
test/DebugInfo/line-directive-codeview.swift
For the majority of artificial helper functions the filename is
actively misleading since it usually represents the file of the caller
that triggered the helper to be generated. Instead, this patch creates
a virtual filname `<compiler-generated>` to make it very obvious that
the function has not correspondence to any source code.
<rdar://problem/33809560>
This commit changes how inline information is stored in SILDebugScope
from a tree to a linear chain of inlined call sites (similar to what
LLVM is using). This makes creating inlined SILDebugScopes slightly
more expensive, but makes lowering SILDebugScopes into LLVM metadata
much faster because entire inlined-at chains can now be cached. This
means that SIL is no longer preserve the inlining history (i.e., ((a
was inlined into b) was inlined into c) is represented the same as (a
was inlined into (b was inlined into c)), but this information was not
used by anyone.
On my late 2012 i7 iMac, this saves about 4 seconds when compiling the
RelWithDebInfo x86_64 swift standard library — or 40% of IRGen time.
rdar://problem/28311051
A lot of files transitively include Expr.h, because it was
included from SILInstruction.h, SILLocation.h and SILDeclRef.h.
However in reality most of these files don't do anything
with Exprs, especially not anything in IRGen or the SILOptimizer.
Now we're down to 171 files in the frontend which depend on
Expr.h, which is still a lot but much better than before.
In all cases the DeclCtx field was supposed to be initialized from the
SILLocation of the function, so we can save one pointer per
SILFunction.
There is one test case change where a different (more precise)
diagnostic is being generated after this change.
llvm r283043 and possibly other recent changes switch to use StringRef
instead of char* pointers. Update Swift to match. In some cases, this is
a clear improvement. It would be good to assess the impact on memory use,
particularly for the Filename component of source locations.
Note that the change to SILLocation::isNull fixes an apparent bug where
the location was treated as null when the filename was *not* null.
This ireapplies commit 255c52de9f.
Original commit message:
Serialize debug scope and location info in the SIL assembler language.
At the moment it is only possible to test the effects that SIL
optimization passes have on debug information by observing the
effects of a full .swift -> LLVM IR compilation. This change enable us
to write targeted testcases for single SIL optimization passes.
The new syntax is as follows:
sil-scope-ref ::= 'scope' [0-9]+
sil-scope ::= 'sil_scope' [0-9]+ '{'
sil-loc
'parent' scope-parent
('inlined_at' sil-scope-ref )?
'}'
scope-parent ::= sil-function-name ':' sil-type
scope-parent ::= sil-scope-ref
sil-loc ::= 'loc' string-literal ':' [0-9]+ ':' [0-9]+
Each instruction may have a debug location and a SIL scope reference
at the end. Debug locations consist of a filename, a line number, and
a column number. If the debug location is omitted, it defaults to the
location in the SIL source file. SIL scopes describe the position
inside the lexical scope structure that the Swift expression a SIL
instruction was generated from had originally. SIL scopes also hold
inlining information.
<rdar://problem/22706994>
At the moment it is only possible to test the effects that SIL
optimization passes have on debug information by observing the
effects of a full .swift -> LLVM IR compilation. This change enable us
to write targeted testcases for single SIL optimization passes.
The new syntax is as follows:
sil-scope-ref ::= 'scope' [0-9]+
sil-scope ::= 'sil_scope' [0-9]+ '{'
sil-loc
'parent' scope-parent
('inlined_at' sil-scope-ref )?
'}'
scope-parent ::= sil-function-name ':' sil-type
scope-parent ::= sil-scope-ref
sil-loc ::= 'loc' string-literal ':' [0-9]+ ':' [0-9]+
Each instruction may have a debug location and a SIL scope reference
at the end. Debug locations consist of a filename, a line number, and
a column number. If the debug location is omitted, it defaults to the
location in the SIL source file. SIL scopes describe the position
inside the lexical scope structure that the Swift expression a SIL
instruction was generated from had originally. SIL scopes also hold
inlining information.
<rdar://problem/22706994>
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>
There's a buggy SIL verifier check that was previously tautological,
and it turns out that it's violated, apparently harmlessly. Since it
was already doing nothing, I've commented it out temporarily while
I figure out the right way to fix SILGen to get the invariant right.
The drivers for this change are providing a simpler API to SIL pass
authors, having a more efficient of the in-memory representation,
and ruling out an entire class of common bugs that usually result
in hard-to-debug backend crashes.
Summary
-------
SILInstruction
Old New
+---------------+ +------------------+ +-----------------+
|SILInstruction | |SILInstruction | |SILDebugLocation |
+---------------+ +------------------+ +-----------------+
| ... | | ... | | ... |
|SILLocation | |SILDebugLocation *| -> |SILLocation |
|SILDebugScope *| +------------------+ |SILDebugScope * |
+---------------+ +-----------------+
We’re introducing a new class SILDebugLocation which represents the
combination of a SILLocation and a SILDebugScope.
Instead of storing an inline SILLocation and a SILDebugScope pointer,
SILInstruction now only has one SILDebugLocation pointer. The APIs of
SILBuilder and SILDebugLocation guarantees that every SILInstruction
has a nonempty SILDebugScope.
Developer-visible changes include:
SILBuilder
----------
In the old design SILBuilder populated the InsertedInstrs list to
allow setting the debug scopes of all built instructions in bulk
at the very end (as the responsibility of the user). In the new design,
SILBuilder now carries a "current debug scope" state and immediately
sets the debug scope when an instruction is inserted.
This fixes a use-after-free issue with with SIL passes that delete
instructions before destroying the SILBuilder that created them.
Because of this, SILBuilderWithScopes no longer needs to be a template,
which simplifies its call sites.
SILInstruction
--------------
It is neither possible or necessary to manually call setDebugScope()
on a SILInstruction any more. The function still exists as a private
method, but is only used when splicing instructions from one function
to another.
Efficiency
----------
In addition to dropping 20 bytes from each SILInstruction,
SILDebugLocations are now allocated in the SILModule's bump pointer
allocator and are uniqued by SILBuilder. Unfortunately repeat compiles
of the standard library already vary by about 5% so I couldn’t yet
produce reliable numbers for how much this saves overall.
rdar://problem/22017421
Change the SILLocations for enum element dispatches to make the line table
more consistent. emitEnumElementDispatch may be invoked several times so
it should use the location of the first pattern rather than TheSwitch.
Swift SVN r22782
with user code and that the boilerplate is counted towards the prologue.
<rdar://problem/18563763> Setting a breakpoint on "main" in a Swift program doesn't stop at user code
Swift SVN r22611
Eliminate the intermediate top_level_code function. Now that SIL is expressive enough to express a "main" function, there's no reason for it, and this eliminates a bunch of mystery code in IRGen to thunk from main to top_level_code by reaching for hardcoded symbol names. Demystify the special code for setting up C_ARGC and C_ARGV by having SILGen look for a transparent "_didEnterMain" hook in the stdlib and emit a call to it.
Swift SVN r22525
introduced, as these are obvious miscompilations and clearly mystifying to our user base.
This is enough to emit diagnostics like this:
writeback_conflict_diagnostics.swift:58:70: error: inout writeback aliasing conflict detected on computed property 'c_local_struct_property'
swap(&c_local_struct_property.stored_int, &c_local_struct_property.stored_int)
~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~
writeback_conflict_diagnostics.swift:58:33: note: concurrent writeback occurred here
swap(&c_local_struct_property.stored_int, &c_local_struct_property.stored_int)
~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~
which isn't great, but is better than nothing (better wording is totally welcome!).
This doesn't handle subscripts (or many other kinds of logical lvalue) at all yet, so
it doesn't handle the swift WTF case, but this is progress towards that.
Swift SVN r20297