Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
988a3dc
[SIL] Introduce new SILDeclRef
janbaig Jul 30, 2025
0dbbc8e
[SIL] SILDeclRef Mangling Added
janbaig Aug 1, 2025
b2fad4b
[TypeLowering] Implement the interface type for the `SILDeclRef`
janbaig Aug 8, 2025
2b648ea
[SIL] Mark `Self` operand as optional for `AssignOrInitInst`
janbaig Aug 8, 2025
c84cc34
[SIL] Emit `CanSILFunctionType` for the new `SILDeclRef`
janbaig Aug 8, 2025
544aa3b
[SILGen] SILGen body emission for the new `SILDeclRef` works for nomi…
janbaig Aug 8, 2025
2b8e635
[SILGen] Use DI-tracked backing storage for indirect results
janbaig Aug 8, 2025
51dca5a
[SILGen] Emit `assign_or_init` for ambiguous assignments to property-…
janbaig Aug 8, 2025
ff894c4
[Format] Apply clang-format to recent changes
janbaig Aug 9, 2025
3d11234
[SIL] Refactor to allow `Self` operand to hold local projections
janbaig Aug 9, 2025
b939bdc
[SIL] Initial Implemention of thunk support for local contexts
janbaig Aug 9, 2025
b793db7
[SILGen] Inline `InitializationPtr` setup for init accessor @out buffer
janbaig Aug 12, 2025
836e20a
[SILGen] Refactor `InitializationPtr` usage
janbaig Aug 17, 2025
8ca5c83
[Test] Extract closure test to support init accessor thunk without op…
janbaig Aug 18, 2025
54cc1be
[Test] Refactor property wrapper tests to work with new init accesso…
janbaig Aug 19, 2025
2499116
[Test] Refactor function manglings to reflect file name change
janbaig Aug 20, 2025
30d6780
[TBD] Add init accessor thunk to TBD gen
janbaig Aug 22, 2025
c2850c3
[SIL] Remove `AssignByWrapper` definition and registration
janbaig Aug 23, 2025
8469740
[SIL] Remove `AssignByWrapper` cloning and builder support
janbaig Aug 23, 2025
4c61096
[SIL] Remove `AssignByWrapper` handling from analysis and utils
janbaig Aug 23, 2025
6f1ee54
[SIL] Remove `AssignByWrapper` suport from SIL parsing and serialization
janbaig Aug 23, 2025
52895fe
[SIL] Remove `AssignByWrapper` references from SIL passes
janbaig Aug 23, 2025
ba1fd9f
Minor Comment Cleanup
janbaig Aug 23, 2025
95cf42b
[Docs] Add `assign_or_init` documentation and remove `assign_by_wrapper`
janbaig Aug 23, 2025
d3c40c0
[Docs] Document mangling for the init accessor thunk
janbaig Aug 23, 2025
288c6d9
Update `SWIFTMODULE_VERSION_MINOR`
janbaig Aug 23, 2025
798c0f5
Merge branch 'main' into temp-branch
janbaig Aug 23, 2025
63888e3
Update `SWIFTMODULE_VERSION_MINOR` comment
janbaig Aug 26, 2025
66b38a6
Refactor `lowerAssignOrInitInstruction`
janbaig Aug 26, 2025
afe83fe
Simple refactors to `getSILFunctionTypeForInitAccessor`
janbaig Aug 26, 2025
f4d9c7b
Add `getDeclContextOrNull` to `AssignOrInitInst`
janbaig Aug 26, 2025
be6e6e5
Use callback to avoid repeated allocation when collecting initialized…
janbaig Aug 26, 2025
78fc5cd
Add local context test for demangling
janbaig Aug 26, 2025
4a3938b
Fix: avoid `getInnermostDeclContext()`
janbaig Aug 26, 2025
3a60402
Rename `opaque_values_closures2` test file
janbaig Aug 26, 2025
a1f0b8b
Refactor `declContext` extraction
janbaig Aug 26, 2025
4effb83
Refactor SILOptimizer test to use `assign_or_init`
janbaig Aug 28, 2025
d71cde9
Update mangling due to file name change
janbaig Aug 28, 2025
ac8d630
Remove newline
janbaig Aug 29, 2025
f21eb53
Merge branch 'main' into temp-branch
janbaig Sep 3, 2025
48cedb5
Fix `RawSILInstLowering` test
janbaig Sep 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ extension AddressUseVisitor {
case is SwitchEnumAddrInst, is CheckedCastAddrBranchInst,
is SelectEnumAddrInst, is InjectEnumAddrInst,
is StoreInst, is StoreUnownedInst, is StoreWeakInst,
is AssignInst, is AssignByWrapperInst, is AssignOrInitInst,
is AssignInst, is AssignOrInitInst,
is TupleAddrConstructorInst, is InitBlockStorageHeaderInst,
is RetainValueAddrInst, is ReleaseValueAddrInst,
is DestroyAddrInst, is DeallocStackInst,
Expand Down
2 changes: 0 additions & 2 deletions SwiftCompilerSources/Sources/SIL/Instruction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -347,8 +347,6 @@ final public class AssignInst : Instruction, StoringInstruction {
}
}

final public class AssignByWrapperInst : Instruction, StoringInstruction {}

final public class AssignOrInitInst : Instruction, StoringInstruction {}

/// Instruction that copy or move from a source to destination address.
Expand Down
1 change: 0 additions & 1 deletion SwiftCompilerSources/Sources/SIL/Registration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ private func registerSILClasses() {
register(StoreUnownedInst.self)
register(StoreBorrowInst.self)
register(AssignInst.self)
register(AssignByWrapperInst.self)
register(AssignOrInitInst.self)
register(CopyAddrInst.self)
register(ExplicitCopyAddrInst.self)
Expand Down
1 change: 1 addition & 0 deletions docs/ABI/Mangling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,7 @@ Entities
entity-spec ::= entity 'fa' // runtime discoverable attribute generator
entity-spec ::= 'fi' // non-local variable initializer
entity-spec ::= 'fP' // property wrapper backing initializer
entity-spec ::= 'fF' // property wrapped field init accessor
entity-spec ::= 'fW' // property wrapper init from projected value
entity-spec ::= 'fD' // deallocating destructor; untyped
entity-spec ::= 'fZ' // isolated deallocating destructor; untyped
Expand Down
80 changes: 43 additions & 37 deletions docs/SIL/Instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -1064,43 +1064,49 @@ a sequence that also correctly destroys the current value.
This instruction is only valid in Raw SIL and is rewritten as
appropriate by the definitive initialization pass.

### assign_by_wrapper

```
sil-instruction ::= 'assign_by_wrapper' sil-operand 'to' mode? sil-operand ',' 'init' sil-operand ',' 'set' sil-operand

mode ::= '[init]' | '[assign]' | '[assign_wrapped_value]'

assign_by_wrapper %0 : $S to %1 : $*T, init %2 : $F, set %3 : $G
// $S can be a value or address type
// $T must be the type of a property wrapper.
// $F must be a function type, taking $S as a single argument (or multiple arguments in case of a tuple) and returning $T
// $G must be a function type, taking $S as a single argument (or multiple arguments in case of a tuple) and without a return value
```

Similar to the [assign](#assign) instruction, but the assignment is done
via a delegate.

Initially the instruction is created with no mode. Once the mode is
decided (by the definitive initialization pass), the instruction is
lowered as follows:

If the mode is `initialization`, the function `%2` is called with `%0`
as argument. The result is stored to `%1`. In case of an address type,
`%1` is simply passed as a first out-argument to `%2`.

The `assign` mode works similar to `initialization`, except that the
destination is "assigned" rather than "initialized". This means that
the existing value in the destination is destroyed before the new value
is stored.

If the mode is `assign_wrapped_value`, the function `%3` is called with
`%0` as argument. As `%3` is a setter (e.g. for the property in the
containing nominal type), the destination address `%1` is not used in
this case.

This instruction is only valid in Raw SIL and is rewritten as
appropriate by the definitive initialization pass.
### assign_or_init

```
sil-instruction ::= 'assign_or_init' mode? attached-property ',' self-or-local ',' sil-operand ',' 'value' ',' sil-operand ',' 'init' sil-operand ',' 'set' sil-operand

mode ::= '[init]' | '[assign]'
attached-property ::= '#' sil-decl-ref
self-or-local ::= 'self' | 'local'

// Nominal Context:
assign_or_init #MyStruct.x, self %A, value %V, init %I, set %S
// Local Context (only emitted with compiler synthesized thunks currently):
assign_or_init #x, local %L, value %V, init %I, set %S
```

Assigns or initializes a computed property with an attached init accessor.
This instruction is emitted during SILGen without an explicit mode.
The definitive initialization (DI) pass resolves the mode and rewrites
the instruction accordingly:

- `[init]`: In this mode, the init accessor `%I` is called with `%V`
as an argument.
- `[assign]`: In this mode, the setter function `%S` is called with `%V`
as an argument.

This instruction is only valid in Raw SIL and is rewritten as appropriate by
the DI pass.

Operand Roles:
- `attached-property`: The property being written to. For nominal contexts, this
refers to a property with an attached init accessor (e.g. `#MyStruct.x`). For local
contexts, it refers to a local variable name (e.g. `#x`).
- `self-or-local`:
- `self %A`: Refers to the instance of the type that owns the property with the
attached init accessor.
- `local %L`: Indicates the assignment is to a local variable (`%L`) rather than
a property of a nominal type. While init accessors are not currently available to be
used in local contexts in user-authored code, the compiler can synthesize an `assign_or_init`
in local contexts using an init accessor thunk in special cases.
- `value %V`: The input value passed to either the `init` or `set` function, depending on
the selected DI mode.
- `init %I`: A partially applied function implementing the property's init accessor.
- `set %S`: A partially applied function implementing the property's setter.

### mark_uninitialized

Expand Down
3 changes: 3 additions & 0 deletions include/swift/AST/ASTMangler.h
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,8 @@ class ASTMangler : public Mangler {
std::string mangleInitializerEntity(const VarDecl *var, SymbolKind SKind);
std::string mangleBackingInitializerEntity(const VarDecl *var,
SymbolKind SKind = SymbolKind::Default);
std::string manglePropertyWrappedFieldInitAccessorEntity(
const VarDecl *var, SymbolKind SKind = SymbolKind::Default);
std::string mangleInitFromProjectedValueEntity(const VarDecl *var,
SymbolKind SKind = SymbolKind::Default);

Expand Down Expand Up @@ -722,6 +724,7 @@ class ASTMangler : public Mangler {

void appendInitializerEntity(const VarDecl *var);
void appendBackingInitializerEntity(const VarDecl *var);
void appendPropertyWrappedFieldInitAccessorEntity(const VarDecl *var);
void appendInitFromProjectedValueEntity(const VarDecl *var);

CanType getDeclTypeForMangling(const ValueDecl *decl,
Expand Down
1 change: 1 addition & 0 deletions include/swift/Demangling/DemangleNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ NODE(PrefixOperator)
NODE(PrivateDeclName)
NODE(PropertyDescriptor)
CONTEXT_NODE(PropertyWrapperBackingInitializer)
CONTEXT_NODE(PropertyWrappedFieldInitAccessor)
CONTEXT_NODE(PropertyWrapperInitFromProjectedValue)
CONTEXT_NODE(Protocol)
CONTEXT_NODE(ProtocolSymbolicReference)
Expand Down
6 changes: 3 additions & 3 deletions include/swift/SIL/AddressWalker.h
Original file line number Diff line number Diff line change
Expand Up @@ -214,8 +214,7 @@ TransitiveAddressWalker<Impl>::walk(SILValue projectedAddress) {
isa<AssignInst>(user) || isa<LoadUnownedInst>(user) ||
isa<StoreUnownedInst>(user) || isa<EndApplyInst>(user) ||
isa<LoadWeakInst>(user) || isa<StoreWeakInst>(user) ||
isa<AssignByWrapperInst>(user) || isa<AssignOrInitInst>(user) ||
isa<BeginUnpairedAccessInst>(user) ||
isa<AssignOrInitInst>(user) || isa<BeginUnpairedAccessInst>(user) ||
isa<EndUnpairedAccessInst>(user) || isa<WitnessMethodInst>(user) ||
isa<SelectEnumAddrInst>(user) || isa<InjectEnumAddrInst>(user) ||
isa<IsUniqueInst>(user) || isa<ValueMetatypeInst>(user) ||
Expand All @@ -229,7 +228,8 @@ TransitiveAddressWalker<Impl>::walk(SILValue projectedAddress) {
isa<PackElementSetInst>(user) || isa<PackElementGetInst>(user) ||
isa<DeinitExistentialAddrInst>(user) || isa<LoadBorrowInst>(user) ||
isa<TupleAddrConstructorInst>(user) || isa<DeallocPackInst>(user) ||
isa<MergeIsolationRegionInst>(user) || isa<EndCOWMutationAddrInst>(user)) {
isa<MergeIsolationRegionInst>(user) ||
isa<EndCOWMutationAddrInst>(user)) {
callVisitUse(op);
continue;
}
Expand Down
4 changes: 0 additions & 4 deletions include/swift/SIL/InstructionUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,10 +158,6 @@ bool isInstrumentation(SILInstruction *Instruction);
/// argument of the partial apply if it is.
SILValue isPartialApplyOfReabstractionThunk(PartialApplyInst *PAI);

/// Returns true if \p PAI is only used by an assign_by_wrapper instruction as
/// init or set function.
bool onlyUsedByAssignByWrapper(PartialApplyInst *PAI);

/// Returns true if \p PAI is only used by an \c assign_or_init
/// instruction as init or set function.
bool onlyUsedByAssignOrInit(PartialApplyInst *PAI);
Expand Down
24 changes: 6 additions & 18 deletions include/swift/SIL/SILBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -972,25 +972,13 @@ class SILBuilder {
Qualifier));
}

AssignByWrapperInst *createAssignByWrapper(SILLocation Loc, SILValue Src,
SILValue Dest,
SILValue Initializer,
SILValue Setter,
AssignByWrapperInst::Mode mode) {
return insert(new (getModule()) AssignByWrapperInst(
getSILDebugLocation(Loc), Src, Dest, Initializer, Setter, mode));
}

AssignOrInitInst *createAssignOrInit(SILLocation Loc,
VarDecl *Property,
SILValue Self,
SILValue Src,
SILValue Initializer,
SILValue Setter,
AssignOrInitInst *createAssignOrInit(SILLocation Loc, VarDecl *Property,
SILValue SelfOrLocal, SILValue Src,
SILValue Initializer, SILValue Setter,
AssignOrInitInst::Mode Mode) {
return insert(new (getModule())
AssignOrInitInst(getSILDebugLocation(Loc), Property, Self,
Src, Initializer, Setter, Mode));
return insert(new (getModule()) AssignOrInitInst(
getSILDebugLocation(Loc), Property, SelfOrLocal, Src, Initializer,
Setter, Mode));
}

StoreBorrowInst *createStoreBorrow(SILLocation Loc, SILValue Src,
Expand Down
21 changes: 3 additions & 18 deletions include/swift/SIL/SILCloner.h
Original file line number Diff line number Diff line change
Expand Up @@ -1525,27 +1525,14 @@ void SILCloner<ImplClass>::visitAssignInst(AssignInst *Inst) {
Inst->getOwnershipQualifier()));
}

template <typename ImplClass>
void SILCloner<ImplClass>::visitAssignByWrapperInst(AssignByWrapperInst *Inst) {
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
recordClonedInstruction(
Inst, getBuilder().createAssignByWrapper(
getOpLocation(Inst->getLoc()),
getOpValue(Inst->getSrc()), getOpValue(Inst->getDest()),
getOpValue(Inst->getInitializer()),
getOpValue(Inst->getSetter()), Inst->getMode()));
}

template <typename ImplClass>
void SILCloner<ImplClass>::visitAssignOrInitInst(AssignOrInitInst *Inst) {
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
recordClonedInstruction(
Inst, getBuilder().createAssignOrInit(
getOpLocation(Inst->getLoc()),
Inst->getProperty(),
getOpValue(Inst->getSelf()),
getOpValue(Inst->getSrc()),
getOpValue(Inst->getInitializer()),
getOpLocation(Inst->getLoc()), Inst->getProperty(),
getOpValue(Inst->getSelfOrLocalOperand()),
getOpValue(Inst->getSrc()), getOpValue(Inst->getInitializer()),
getOpValue(Inst->getSetter()), Inst->getMode()));
}

Expand Down Expand Up @@ -3538,9 +3525,7 @@ visitSwitchEnumAddrInst(SwitchEnumAddrInst *Inst) {
getOpValue(Inst->getOperand()),
DefaultBB, CaseBBs));
}



template<typename ImplClass>
void
SILCloner<ImplClass>::visitSelectEnumInst(SelectEnumInst *Inst) {
Expand Down
4 changes: 4 additions & 0 deletions include/swift/SIL/SILDeclRef.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,10 @@ struct SILDeclRef {

/// The asynchronous main entry-point function.
AsyncEntryPoint,

/// An init accessor that calls a propery wrapped field's
/// backing storage initializer
PropertyWrappedFieldInitAccessor
};

/// Represents the variants of a back deployable function.
Expand Down
64 changes: 14 additions & 50 deletions include/swift/SIL/SILInstruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -5230,52 +5230,7 @@ class AssignInst
}
};

/// AssignByWrapperInst - Represents an abstract assignment via a wrapper,
/// which may either be an initialization or a store sequence. This is only
/// valid in Raw SIL.
class AssignByWrapperInst
: public AssignInstBase<SILInstructionKind::AssignByWrapperInst, 4> {
friend SILBuilder;
USE_SHARED_UINT8;

public:
enum Mode {
/// The mode is not decided yet (by DefiniteInitialization).
Unknown,

/// The initializer is called with Src as argument. The result is stored to
/// Dest.
Initialization,

// Like ``Initialization``, except that the destination is "assigned" rather
// than "initialized". This means that the existing value in the destination
// is destroyed before the new value is stored.
Assign,

/// The setter is called with Src as argument. The Dest is not used in this
/// case.
AssignWrappedValue
};

private:
AssignByWrapperInst(SILDebugLocation DebugLoc,
SILValue Src, SILValue Dest, SILValue Initializer,
SILValue Setter, Mode mode);

public:
SILValue getInitializer() { return Operands[2].get(); }
SILValue getSetter() { return Operands[3].get(); }

Mode getMode() const {
return Mode(sharedUInt8().AssignByWrapperInst.mode);
}

void setMode(Mode mode) {
sharedUInt8().AssignByWrapperInst.mode = uint8_t(mode);
}
};

/// AssignOrInitInst - Represents an abstract assignment via a init accessor
/// AssignOrInitInst - Represents an abstract assignment via an init accessor
/// or a setter, which may either be an initialization or a store sequence.
/// This is only valid in Raw SIL.
///
Expand Down Expand Up @@ -5312,16 +5267,23 @@ class AssignOrInitInst
};

private:
AssignOrInitInst(SILDebugLocation DebugLoc, VarDecl *P, SILValue Self,
AssignOrInitInst(SILDebugLocation DebugLoc, VarDecl *P, SILValue SelfOrLocal,
SILValue Src, SILValue Initializer, SILValue Setter,
Mode mode);

public:
VarDecl *getProperty() const { return Property; }
SILValue getSelf() const { return Operands[0].get(); }
SILValue getSrc() const { return Operands[1].get(); }
SILValue getInitializer() const { return Operands[2].get(); }
SILValue getSetter() { return Operands[3].get(); }
SILValue getSetter() { return Operands[3].get(); }

// Init accessors currently don't support local contexts.
// The `PropertyWrappedFieldInitAccessor` thunk must work for both local
// and nominal contexts. For locals, we work around this by storing the
// projected local address directly in the original `Self` operand.
// Callers of this method conditionally handle its result based on
// the current DeclContext
SILValue getSelfOrLocalOperand() const { return Operands[0].get(); }

Mode getMode() const {
return Mode(sharedUInt8().AssignOrInitInst.mode);
Expand All @@ -5343,14 +5305,16 @@ class AssignOrInitInst

unsigned getNumInitializedProperties() const;

ArrayRef<VarDecl *> getInitializedProperties() const;
void forEachInitializedProperty(
llvm::function_ref<void(VarDecl *)> callback) const;
ArrayRef<VarDecl *> getAccessedProperties() const;

ArrayRef<Operand> getAllOperands() const { return Operands.asArray(); }
MutableArrayRef<Operand> getAllOperands() { return Operands.asArray(); }

StringRef getPropertyName() const;
AccessorDecl *getReferencedInitAccessor() const;
DeclContext *getDeclContextOrNull() const;
};

/// Indicates that a memory location is uninitialized at this point and needs to
Expand Down
2 changes: 0 additions & 2 deletions include/swift/SIL/SILNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,6 @@ class alignas(8) SILNode :
enum { NumStoreOwnershipQualifierBits = 2 };
enum { NumLoadOwnershipQualifierBits = 2 };
enum { NumAssignOwnershipQualifierBits = 2 };
enum { NumAssignByWrapperModeBits = 2 };
enum { NumSILAccessKindBits = 2 };
enum { NumSILAccessEnforcementBits = 3 };
enum { NumAllocRefTailTypesBits = 4 };
Expand Down Expand Up @@ -196,7 +195,6 @@ class alignas(8) SILNode :
SHARED_FIELD(StoreInst, uint8_t ownershipQualifier);
SHARED_FIELD(LoadInst, uint8_t ownershipQualifier);
SHARED_FIELD(AssignInst, uint8_t ownershipQualifier);
SHARED_FIELD(AssignByWrapperInst, uint8_t mode);
SHARED_FIELD(AssignOrInitInst, uint8_t mode);
SHARED_FIELD(StringLiteralInst, uint8_t encoding);
SHARED_FIELD(SwitchValueInst, bool hasDefault);
Expand Down
2 changes: 0 additions & 2 deletions include/swift/SIL/SILNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -837,8 +837,6 @@ NON_VALUE_INST(StoreInst, store,
SILInstruction, MayHaveSideEffects, MayRelease)
NON_VALUE_INST(AssignInst, assign,
SILInstruction, MayWrite, DoesNotRelease)
NON_VALUE_INST(AssignByWrapperInst, assign_by_wrapper,
SILInstruction, MayWrite, DoesNotRelease)
NON_VALUE_INST(AssignOrInitInst, assign_or_init,
SILInstruction, MayWrite, DoesNotRelease)
NON_VALUE_INST(MarkFunctionEscapeInst, mark_function_escape,
Expand Down
Loading