Instead of using an op_constu/consts in the DIExpr, the integer literal
salvage now uses a debug basic block using a typed integer_literal.
This also has the effect of supporting integer literals bigger than
64 bits (such as an Int128 being salvaged) correctly.
Assisted-by: Claude
Instructions emitted as part of the transform block of a debug_value
are now immediately deleted as soon as the debug record is created.
They are salvaged by LLVM's salvageDebugInfo, and as such, their
effects are encoded into the DIExpression of the debug record.
Assisted-by: Claude
Instead of using a single DirectValue/IndirectValue enum with duplicate values
for coro context, indirect values are now represented with an extra op_deref
throughout.
This makes the code simpler: Coro context is now a boolean throughout, and
the intent behind indirection is clearer. It also cleanly supports multiple
layers of indirection: if two consecutive paths set the indirection kind to
IndirectValue, it would only insert one DW_OP_deref instead of two.
This fixes the move_function_dbginfo.swift test file with the deref behaviour
(rdar://176552243). All changed test cases have been tested manually in LLDB
to make sure it is the correct behaviour.
Assisted-by: Claude
The salvage for this instruction was wrong as it didn't multiply the
index by the element stride.
As this salvage is rare, only was correct for byte sized elements, and
will be rewritten in the future, remove it rather than fix it.
All SIL tests now use op_deref correctly on debug_values on address
types, such as alloc_stack. All tests are now conforming to the new
model of always using op_deref for addresses.
Assisted-by: Claude
The VarInfo for an alloc_stack will always have an op_deref, so that they can
get copied along when the VarInfo is moved to a debug_value. This op_deref is
not printed by the SILPrinter.
This commit also updates uses of AllocStackInst's getVarInfo to strip this
op_deref at places where it is not needed, and uses of createDebugValueAddr
where the extra op_deref is no longer needed.
The only change at the IR level is for undef values that now have a DW_OP_deref
for move-only values.
This fixes most of the inconsitencies with op_deref at the SIL level. All
debug_values with addresses should always have an op_deref.
Assisted-by: Claude Opus 4.6 (Updated tests)
This deprecates the use of DIExpr on alloc_stack. When varinfo is present
on an alloc_stack, it represents the whole variable. Otherwise, debug_value
should be used.
SIL-based debug info does not support debug variables. It is limited to
line tables at the IRGen level. Keeping alloc_stack variables but not
debug_values is inconsistent.
When a shadow copy is emitted for an address-only value with
usesMoveableValueDebugInfo, the shadow alloca stores a pointer to the
original storage, adding a level of indirection. Since moveable values
use dbg_value instead of dbg_declare, this indirection is not implicit
and must be accounted for by setting IndirectValue. Introduce
emitShadowCopyIfNeededOrNull to distinguish whether a shadow copy was
actually created, and add the extra DW_OP_deref accordingly.
We cannot use spare bits or other overlapping storage layout tricks with fundamentally
address-only enums, and we can take advantage of this to do borrowing switches or other
in-place projections without copying the value. However, for resilient enums, the
implementation may use spare bit packing, but the type must be handled address-only
outside of its defining module, and we didn't have a way to express that with
borrowing switch. Optimization passes have also been running into problems with the
complexity that we were using `unchecked_take_enum_data_addr` sometimes as a pure
operation. This patch splits the instruction into three:
- `unchecked_inplace_enum_data_addr` represents a nondestructive in-place enum
projection. It is only allowed for enums whose projection operation is
nondestructive.
- `unchecked_take_enum_data_addr` represents a destructive enum projection,
invalidating the enum and leaving the payload to be further consumed.
This matches the current instruction's semantics.
- `unchecked_borrow_enum_data_addr` represents a borrowing enum projection.
The instruction takes a second operand for "scratch" space, which the
enum representation may be copied into in order to avoid invalidating the
enum value, so the result is dependent on the lifetime of both the
original enum and the scratch buffer. This allows for borrowing switches
over resilient enums.
`unchecked_borrow_enum_data_addr` is implemented by taking advantage of the
"address-only enums can't do spare bit optimization" property at runtime.
We inspect the operand type's bitwise-borrowability from its metadata. If
the type is bitwise-borrowable, then we are allowed to bitwise-copy the
enum to the scratch space and apply the projection to the scratch space,
preserving the original value. If the type is not bitwise-borrowable, then
we cannot use spare bit optimization in its layout, so we apply the
projection in-place.
Fixes rdar://174952822.
As a workaround for issues with uniquing, bound generics are emitted as a nested structure:
- A sized outer structure with no name or identifier
- A sizeless inner structure with the mangled name as the name and no identifier.
The actual mechanism of connection for the inner and outer structures is
that the outer structure has a single unnamed member whose type is the
inner structure.
However, LLVM CodeView emission treats unnamed members as anonymous
structs and tries to inline their members into the parent. But since the
inner struct has no members, the effect is that it gets dropped.
This change names the inner struct with the mangled type name. This will
have the effect of preserving the inner struct in CodeView output, and
allow us to use a variation of the DWARF logic at
https://github.com/swiftlang/llvm-project/blob/cd1235e59b87c84144802ab85592ee75a615f231/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserSwift.cpp#L166
to recognize and handle this pattern.
More details and discussion at https://github.com/swiftlang/swift/issues/87093
Marker protocols are a compile time concept only, and emit no metadata.
RemoteInspection does not know how to handle existentials with these
types.
This patch emits debug info for marker protocols, so LLDB can handle
them properly before querying RemoteInspection for type information.
rdar://172847891
Default to use new swift-driver to run lit tests as legacy swift driver
is deprecated for a long time. The lit tests for legacy drivers are also
disable when running new swift-driver.
Tests that relies on legacy swift driver (for example, tests merge
module) can be enabled on conditions `legacy_swift_driver`. Fix and
split up some existing tests that relies on legacy driver.
Commit 0ef2094279 salvages more debug
information in Mem2Reg in several cases. It propagates the information from
the alloc_stack to the replaced load instructions.
However, there are cases where the loads from an alloca are not actually
representing loads from the respective local variable. One such case is
when there is mandatory inlining happening at the start of the pipeline.
For example, consider the example below where an identity function is inlined.
The resulting SIL will contain an alloca from the outer `result` and a load
that is the leftover after the closure (which is just a load of the passed
argument). The load that is created has its debug scope (correctly) in the
closure scope, but the loaded alloc_stack is actually the outer local variable.
The intermediate `result` that is passed to the closure is getting eliminated
by the inliner.
```
let result = try await ... // becomes empty tuple.
return withExtendedLifetime((...)) {
result
}
```
This patch forces that the scope of the debug_value describing result is
actually in the outer function and describes the right `result` local.
Fixes rdar://171023691
`CompletedDebugTypeInfo::getFromTypeInfo` currently uses the storage type as
the preferred source of size information.
For address-only types (and any other type that has no fixed size at compile
time), the storage type is always changed to a pointer.
This currently causes that some non-fixed-size types (e.g., generics)
are assigned the size of a pointer as their actual size in the generated
debug information.
For example:
```
protocol P {
associatedtype S
}
func foo<B: P>(_ b: B) {
let x: (aaa: Int, bbb: B.S?) = (aaa: 0, bbb: nil)
_ = x
let y: (Fx: Int, Fy: Int) = (Fx: 0, Fy: 0)
_ = y
}
```
results in the following DWARF output where the first struct
is given size 8 (= the size of a pointer).
```
0x000000d4: DW_TAG_structure_type
DW_AT_name ("$sSi3aaa_1S4main1PPQzSg3bbbtD")
DW_AT_linkage_name ("$sSi3aaa_1S4main1PPQzSg3bbbtD")
DW_AT_byte_size (0x08)
DW_AT_APPLE_runtime_class (DW_LANG_Swift)
0x000000f3: DW_TAG_structure_type
DW_AT_name ("$sSi2Fx_Si2FytD")
DW_AT_linkage_name ("$sSi2Fx_Si2FytD")
DW_AT_byte_size (0x10)
DW_AT_APPLE_runtime_class (DW_LANG_Swift)
```
This change modifies `CompletedDebugTypeInfo::getFromTypeInfo` to ignore the
storage size for types that do not have fixed size. Generics now have no
specified size or 0 in DWARF. FixedArray<A, B> without substituted type/size
is now also emitted using the dedicated FixedArray code.
Wrap indirect enum case payload types in DW_TAG_reference_type to indicate
that the case stores a pointer to a heap-allocated box rather than the
payload directly.
rdar://170687015
Just like in async functions, coroutines will go through the CoroSplit
flow. As such, variables in O0 need to go through the same treatment
they undergo for async functions: an `asm` directive is emitted so to
create a use of the variable after each split point.
Exit code should not inherit the location of the previous basic block;
instead, it should contain line zero to denote that this is not
associated with any user code.
Without this patch, stepping over code code like:
```
1. yielding mutate {
2. yield &member_int
3. blah
4. blah
}
```
Would go from line 3, to line 4, to line 2.
rdar://149106144
When the main IRGenSIL loop decides to use the previous instruction's
location, it does so by emitting a compiler generated location. This is
creating an issue where the return address of a borrowing accessor is
landing on such a cleanup location, making the parent frame have no line
associated with it.
Why not use the last instruction's location instead? No tests fail with
this change, and it seems to keep the literal meaning of the "use the
last location" boolean variable that already exists in code.