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 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)
For consistency within SIL, we want to keep the information that the value
associated with an alloc_stack needs to be dereferenced to have access to
the variables value.
This should simplify passes that might conditionally remove an op_deref:
for address types, there should always be an op_deref.
IRGen then internally strips the op_deref so that when a dbg_declare is
created, it will not have an additional op_deref.
This commit changes SIL but should not affect the LLVM IR of a program.
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.
The `@export(interface)` and `@export(implementation)` attributes
SE-0497 are queried directly on AST nodes in several places within the
SIL pipeline. However, they don't persist when SIL functions are
serialized, meaning that clients of the original module might make
different assumptions about the availability of a given function's
definition.
Represent these attributes in a SIL function (as an optional
CodeGenerationModel), (de-)serialize them into the module, and add a
textual representation as SIL function attributes `[export_interface]`
and `[export_implementation]`.
when accessing private resilient accessors. The compiler may have elided
dispatch thunks for resilient methods. To make them available in the expression
evaluator there is a special case to directly calls the virtualmethod. However,
this causes a crash in IRGen if the method doesn't have a vtable entry. This
patch adds a check for that condition.
rdar://172871023
performed, and simplify and improve the handling of allocation throughout
IRGen.
The improvements are that we used to use dynamic allocas in a few
places that clearly could and should use static allocas.
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
These comments were verbose and too personal, making it hard to
understand the point being made.
Some comments were duplicated.
Some comments could be merged by placing them where they are relevant.
When lowering an instruction, the intended logic seems to be:
1. If `I` does not contains a cleanup location, use that.
2. If `I` has a cleanup location, but there are other "normal" locations
afterwards, use the previous instruction location to avoid jumps in the line
table (unless there was no location).
3. Otherwise (`I` has a cleanup location and it's all cleanup locations
afterwards), use the location of the last instruction in the BB.
This is currently expressed in a very convoluted way. This patch
simplifies it.
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.
There is a lot of stateful code in the middle of the main IRGenSIL loop
that makes it really hard to understand what is going on. This commit is
a very modest attempt at reducing the cognitive burden in this area by:
1. Moving it out to a helper function
2. Removing one of the stateful booleans, as it can be re-computed from
the previous instruction.
The hope is that, with this patch, we can reason a bit better about the
"CleanupLocation" situation, though even in the new state it is hard to
spot redundant code.
Since after address lowering, `Borrow` can remain loadable with a known-
layout address-only referent, we need instructions that handle three
forms:
- borrow and referent are both loadable values
- borrow is a value, but referent is address-only
- borrow and referent are both address-only
The exclusivity enforcement command-line flags currently impact the
generation of SIL within the current module. However, it does not
impact any SIL that was deserialized from another module, which means
that `-enforce-exclusivity=unchecked` doesn't actually remove all of
the dynamic exclusivity checks.
When dynamic exclusivity is disabled, lower SIL
begin_access/end_access instructions to nothing to ensure that we
won't do any dynamic exclusivity checks.
Use this to better model the reality of dynamic exclusivity checking
in Embedded Swift, which effectively turned off all dynamic
exclusivity checking by having empty stub implementations of
swift_(begin|end)Access. Instead, have Embedded Swift default to
`-enforce-exclusivity=unchecked`, so that it never emits calls to
swift_(begin|end)Access. Remove the stub implementations of
swift_(begin|end)Access from the Embedded Swift runtime, since we will
no longer generate calls to them by default.
Moving forward, this will allow us to conditionally enable the new
implementation of dynamic exclusivity checking by specifying
`-enforce-exclusivity=checked` for Embedded Swift builds. We'll stage
that in over time to avoid breaking existing Embedded Swift clients.
The swift compiler memsets new allocas to zero. It does this so that
LLDB is able to display a friendly 'variable is uninitialized' message
rather than garbage. Unfortunately this use of a variable before its
lifetime.start disagrees with the memtag-stack tagging pass.
This patch attaches a piece of metadata to these memsets, so that the
memtag-stack tagging pass can recognize them and work around them
appropriately.
Paired with: https://github.com/swiftlang/llvm-project/pull/11846.
rdar://162206592
This sanitizer adds MTE (memory tagging extension) checks to stack
variable accesses. Enablement simply requires setting an attribute on
function definitions, and the instrumentation is added by LLVM.
The corresponding swift-driver change is at:
https://github.com/swiftlang/swift-driver/pull/2016.
rdar://161721201
functions.
These were introduced in an early draft implementation of async let, but
never used by a released compiler. They are not used as symbols by any
app binaries. There's no reason to keep carrying them.
While I'm at it, dramatically improve the documentation of the remaining
async let API functions.
This instruction can be used to disable ownership verification on it's result and
will be allowed only in raw SIL.
Sometimes SILGen can produce invalid ownership SSA, that cannot be resolved until
mandatory passes run. We have a few ways to piecewise disable verification.
With unchecked_ownership instruction we can provide a uniform way to disable ownership
verification for a value.
To enable ABIs which store extra info in the frame, add two new slots to
the coroutine allocator function table. For example, a frame could have
a header containing a context pointer at a negative offset from the
address returned from `swift_coro_alloc_frame`. The frame deallocation
function would then know to deallocate more space correspondingly.
Specifically, when TBI is available we use the bottom two bits of the top nibble
(bits 60,61). On platforms without TBI, we use the bottom two tagged pointer
bits (bits 0, 1).
rdar://156525771
This instruction converts Builtin.ImplicitActor to Optional<any Actor>. In the
process of doing so, it masks out the bits we may have stolen from the witness
table pointer of Builtin.ImplicitActor. The bits that we mask out are the bottom
two bits of the top nibble of the TBI space on platforms that support TBI (that
is bit 60,61 on arm64). On platforms that do not support TBI, we just use the
bottom two tagged pointer bits (0,1).
By using an instruction, we avoid having to represent the bitmasking that we are
performing at the SIL level and can instead just make the emission of the
bitmasking an IRGen detail. It also allows us to move detection if we are
compiling for AArch64 to be an IRGen flag instead of a LangOpts flag.
The instruction is a guaranteed forwarding instruction since we want to treat
its result as a borrowed projection from the Builtin.ImplicitActor.
This is currently not wired up to anything. I am going to wire it up in
subsequent commits.
The reason why we are introducing this new Builtin type is to represent that we
are going to start stealing bits from the protocol witness table pointer of the
Optional<any Actor> that this type is bitwise compatible with. The type will
ensure that this value is only used in places where we know that it will be
properly masked out giving us certainty that this value will not be used in any
manner without it first being bit cleared and transformed back to Optional<any
Actor>.