SIL optimizer: add the LetPropertyLowering pass

It lowers let property accesses of classes.
Lowering consists of two tasks:

* In class initializers, insert `end_init_let_ref` instructions at places where all let-fields are initialized.
  This strictly separates the life-range of the class into a region where let fields are still written during
  initialization and a region where let fields are truly immutable.

* Add the `[immutable]` flag to all `ref_element_addr` instructions (for let-fields) which are in the "immutable"
  region. This includes the region after an inserted `end_init_let_ref` in an class initializer, but also all
  let-field accesses in other functions than the initializer and the destructor.

This pass should run after DefiniteInitialization but before RawSILInstLowering (because it relies on `mark_uninitialized` still present in the class initializer).
Note that it's not mandatory to run this pass. If it doesn't run, SIL is still correct.

Simplified example (after lowering):

  bb0(%0 : @owned C):                           // = self of the class initializer
    %1 = mark_uninitialized %0
    %2 = ref_element_addr %1, #C.l              // a let-field
    store %init_value to %2
    %3 = end_init_let_ref %1                    // inserted by lowering
    %4 = ref_element_addr [immutable] %3, #C.l  // set to immutable by lowering
    %5 = load %4
This commit is contained in:
Erik Eckstein
2023-09-06 19:14:38 +02:00
parent 9ae28a2980
commit 5bc036661c
38 changed files with 906 additions and 127 deletions

View File

@@ -13,6 +13,7 @@ swift_compiler_sources(Optimizer
ComputeSideEffects.swift
DeadStoreElimination.swift
InitializeStaticGlobals.swift
LetPropertyLowering.swift
ObjectOutliner.swift
ObjCBridgingOptimization.swift
MergeCondFails.swift

View File

@@ -0,0 +1,209 @@
//===--- LetPropertyLowering.swift -----------------------------------------==//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
import SIL
/// Lowers let property accesses of classes.
///
/// Lowering consists of two tasks:
///
/// * In class initializers, insert `end_init_let_ref` instructions at places where all let-fields are initialized.
/// This strictly separates the life-range of the class into a region where let fields are still written during
/// initialization and a region where let fields are truly immutable.
///
/// * Add the `[immutable]` flag to all `ref_element_addr` instructions (for let-fields) which are in the "immutable"
/// region. This includes the region after an inserted `end_init_let_ref` in an class initializer, but also all
/// let-field accesses in other functions than the initializer and the destructor.
///
/// This pass should run after DefiniteInitialization but before RawSILInstLowering (because it relies on
/// `mark_uninitialized` still present in the class initializer).
///
/// Note that it's not mandatory to run this pass. If it doesn't run, SIL is still correct.
///
/// Simplified example (after lowering):
///
/// bb0(%0 : @owned C): // = self of the class initializer
/// %1 = mark_uninitialized %0
/// %2 = ref_element_addr %1, #C.l // a let-field
/// store %init_value to %2
/// %3 = end_init_let_ref %1 // inserted by lowering
/// %4 = ref_element_addr [immutable] %3, #C.l // set to immutable by lowering
/// %5 = load %4
///
let letPropertyLowering = FunctionPass(name: "let-property-lowering") {
(function: Function, context: FunctionPassContext) in
assert(context.silStage == .raw, "let-property-lowering must run before RawSILInstLowering")
if context.hadError {
// If DefiniteInitialization (or other passes) already reported an error, we cannot assume valid SIL anymore.
return
}
if function.isDestructor {
// Let-fields are not immutable in the class destructor.
return
}
for inst in function.instructions {
switch inst {
// First task of lowering: insert `end_init_let_ref` instructions in class initializers.
case let markUninitialized as MarkUninitializedInst
where markUninitialized.type.isClass &&
// TODO: support move-only classes
!markUninitialized.type.isMoveOnly &&
// We only have to do that for root classes because derived classes call the super-initializer
// _after_ all fields in the derived class are already initialized.
markUninitialized.kind == .rootSelf:
insertEndInitInstructions(for: markUninitialized, context)
// Second task of lowering: set the `immutable` flags.
case let rea as RefElementAddrInst
where rea.fieldIsLet && !rea.isInUninitializedRegion &&
// TODO: support move-only classes
!rea.instance.type.isMoveOnly:
rea.set(isImmutable: true, context)
default:
break
}
}
}
private func insertEndInitInstructions(for markUninitialized: MarkUninitializedInst, _ context: FunctionPassContext) {
assert(!markUninitialized.type.isAddress, "self of class should not be an address")
// The region which contains all let-field initializations, including any partial
// let-field de-initializations (in case of a fail-able or throwing initializer).
var initRegion = InstructionRange(begin: markUninitialized, context)
defer { initRegion.deinitialize() }
constructLetInitRegion(of: markUninitialized, result: &initRegion, context)
insertEndInitInstructions(for: markUninitialized, atEndOf: initRegion, context)
}
private func insertEndInitInstructions(
for markUninitialized: MarkUninitializedInst,
atEndOf initRegion: InstructionRange,
_ context: FunctionPassContext
) {
var ssaUpdater = SSAUpdater(type: markUninitialized.type, ownership: .owned, context)
ssaUpdater.addAvailableValue(markUninitialized, in: markUninitialized.parentBlock)
for endInst in initRegion.ends {
let builder = Builder(after: endInst, context)
let newValue = builder.createEndInitLetRef(operand: markUninitialized)
ssaUpdater.addAvailableValue(newValue, in: endInst.parentBlock)
}
for exitInst in initRegion.exits {
let builder = Builder(before: exitInst, context)
let newValue = builder.createEndInitLetRef(operand: markUninitialized)
ssaUpdater.addAvailableValue(newValue, in: exitInst.parentBlock)
}
for use in markUninitialized.uses {
if !initRegion.inclusiveRangeContains(use.instruction) &&
!(use.instruction is EndInitLetRefInst)
{
use.set(to: ssaUpdater.getValue(atEndOf: use.instruction.parentBlock), context)
}
}
}
private func constructLetInitRegion(
of markUninitialized: MarkUninitializedInst,
result initRegion: inout InstructionRange,
_ context: FunctionPassContext
) {
// Adding the initial `mark_uninitialized` ensures that a single `end_init_let_ref` is inserted (after the
// `mark_uninitialized`) in case there are no let-field accesses at all.
// Note that we have to insert an `end_init_let_ref` even if there are no let-field initializations, because
// derived classes could have let-field initializations in their initializers (which eventually call the
// root-class initializer).
initRegion.insert(markUninitialized)
var beginBorrows = Stack<BeginBorrowInst>(context)
defer { beginBorrows.deinitialize() }
for inst in markUninitialized.parentFunction.instructions {
switch inst {
case let assign as AssignInst
where assign.destination.isLetFieldAddress(of: markUninitialized):
assert(assign.assignOwnership == .initialize)
initRegion.insert(inst)
case let store as StoreInst
where store.destination.isLetFieldAddress(of: markUninitialized):
assert(store.storeOwnership != .assign)
initRegion.insert(inst)
case let copy as CopyAddrInst
where copy.destination.isLetFieldAddress(of: markUninitialized):
assert(copy.isInitializationOfDest)
initRegion.insert(inst)
case let beginAccess as BeginAccessInst
where beginAccess.accessKind == .Deinit &&
beginAccess.address.isLetFieldAddress(of: markUninitialized):
// Include let-field partial de-initializations in the region.
initRegion.insert(inst)
case let beginBorrow as BeginBorrowInst:
beginBorrows.append(beginBorrow)
default:
break
}
}
// Extend the region to whole borrow scopes to avoid that we insert an `end_init_let_ref` in the
// middle of a borrow scope.
for beginBorrow in beginBorrows where initRegion.contains(beginBorrow) {
initRegion.insert(contentsOf: beginBorrow.endBorrows)
}
}
private extension RefElementAddrInst {
var isInUninitializedRegion: Bool {
var root = self.instance
while true {
switch root {
case let beginBorrow as BeginBorrowInst:
root = beginBorrow.borrowedValue
case let loadBorrow as LoadBorrowInst:
// Initializers of derived classes store `self` into a stack location from where
// it's loaded via a `load_borrow`.
root = loadBorrow.address
case is MarkUninitializedInst:
return true
default:
return false
}
}
}
}
private extension Value {
func isLetFieldAddress(of markUninitialized: MarkUninitializedInst) -> Bool {
if case .class(let rea) = self.accessBase,
rea.fieldIsLet,
rea.instance.referenceRoot == markUninitialized
{
return true
}
return false
}
}

View File

@@ -66,6 +66,7 @@ private func registerSwiftPasses() {
registerPass(stackProtection, { stackProtection.run($0) })
// Function passes
registerPass(letPropertyLowering, { letPropertyLowering.run($0) })
registerPass(mergeCondFailsPass, { mergeCondFailsPass.run($0) })
registerPass(computeEscapeEffects, { computeEscapeEffects.run($0) })
registerPass(computeSideEffects, { computeSideEffects.run($0) })

View File

@@ -355,6 +355,8 @@ IRGEN_PASS(PackMetadataMarkerInserter, "pack-metadata-marker-inserter",
"Insert markers where pack metadata might be de/allocated.")
PASS(PerformanceSILLinker, "performance-linker",
"Deserialize all referenced SIL functions")
SWIFT_FUNCTION_PASS(LetPropertyLowering, "let-property-lowering",
"Lowers accesses to let properties of classes")
PASS(RawSILInstLowering, "raw-sil-inst-lowering",
"Lower all raw SIL instructions to canonical equivalents.")
PASS(TempLValueOpt, "temp-lvalue-opt",

View File

@@ -1644,6 +1644,8 @@ public:
/// Adjoint: adj[x] += adj[y]
void visitMoveValueInst(MoveValueInst *mvi) { visitValueOwnershipInst(mvi); }
void visitEndInitLetRefInst(EndInitLetRefInst *eir) { visitValueOwnershipInst(eir); }
/// Handle `begin_access` instruction.
/// Original: y = begin_access x
/// Adjoint: nothing

View File

@@ -3702,25 +3702,14 @@ static bool checkDefiniteInitialization(SILFunction &Fn) {
BlockStates blockStates(&Fn);
for (auto &BB : Fn) {
for (auto I = BB.begin(), E = BB.end(); I != E;) {
SILInstruction *Inst = &*I;
auto *MUI = dyn_cast<MarkUninitializedInst>(Inst);
if (!MUI) {
++I;
continue;
for (SILInstruction &inst : BB) {
if (auto *MUI = dyn_cast<MarkUninitializedInst>(&inst)) {
processMemoryObject(MUI, blockStates);
Changed = true;
// mark_uninitialized needs to remain in SIL for mandatory passes which
// follow DI, like LetPropertyLowering.
// It will be eventually removed by RawSILInstLowering.
}
// Then process the memory object.
processMemoryObject(MUI, blockStates);
// Move off of the MUI only after we have processed memory objects. The
// lifetime checker may rewrite instructions, so it is important to not
// move onto the next element until after it runs.
++I;
MUI->replaceAllUsesWith(MUI->getOperand());
MUI->eraseFromParent();
Changed = true;
}
}

View File

@@ -546,6 +546,30 @@ static bool diagnoseNonSendableFromDeinit(ModuleDecl *module,
return true;
}
class OperandWorklist {
SmallVector<Operand *, 32> worklist;
SmallPtrSet<Operand *, 16> visited;
public:
Operand *pop() {
if (worklist.empty())
return nullptr;
return worklist.pop_back_val();
}
void pushIfNotVisited(Operand *op) {
if (visited.insert(op).second) {
worklist.push_back(op);
}
}
void pushUsesOfValueIfNotVisited(SILValue value) {
for (Operand *use : value->getUses()) {
pushIfNotVisited(use);
}
}
};
/// Analyzes a function for uses of `self` and records the kinds of isolation
/// required.
/// \param selfParam the parameter of \c getFunction() that should be
@@ -556,13 +580,12 @@ void AnalysisInfo::analyze(const SILArgument *selfParam) {
ModuleDecl *module = getFunction()->getModule().getSwiftModule();
// Use a worklist to track the uses left to be searched.
SmallVector<Operand *, 32> worklist;
OperandWorklist worklist;
// Seed with direct users of `self`
worklist.append(selfParam->use_begin(), selfParam->use_end());
worklist.pushUsesOfValueIfNotVisited(selfParam);
while (!worklist.empty()) {
Operand *operand = worklist.pop_back_val();
while (Operand *operand = worklist.pop()) {
SILInstruction *user = operand->getUser();
// First, check if this is an apply that involves `self`
@@ -651,12 +674,20 @@ void AnalysisInfo::analyze(const SILArgument *selfParam) {
break;
case SILInstructionKind::BeginAccessInst:
case SILInstructionKind::BeginBorrowInst: {
case SILInstructionKind::BeginBorrowInst:
case SILInstructionKind::EndInitLetRefInst: {
auto *svi = cast<SingleValueInstruction>(user);
worklist.append(svi->use_begin(), svi->use_end());
worklist.pushUsesOfValueIfNotVisited(svi);
break;
}
case SILInstructionKind::BranchInst: {
auto *arg = cast<BranchInst>(user)->getArgForOperand(operand);
worklist.pushUsesOfValueIfNotVisited(arg);
break;
}
default:
// don't follow this instruction.
LLVM_DEBUG(llvm::dbgs() << DEBUG_TYPE << " def-use walk skipping: "

View File

@@ -103,6 +103,7 @@ static void addOwnershipModelEliminatorPipeline(SILPassPipelinePlan &P) {
/// order.
static void addDefiniteInitialization(SILPassPipelinePlan &P) {
P.addDefiniteInitialization();
P.addLetPropertyLowering();
P.addRawSILInstLowering();
}

View File

@@ -448,6 +448,14 @@ bool ValueToDeclInferrer::infer(
foundDeclFromUse |= valueUseInferrer.findDecls(use, value);
});
for (Operand *use : value->getUses()) {
if (auto *eir = dyn_cast<EndInitLetRefInst>(use->getUser())) {
rcfi.visitRCUses(eir, [&](Operand *use) {
foundDeclFromUse |= valueUseInferrer.findDecls(use, value);
});
}
}
// At this point, we could not infer any argument. See if we can look up the
// def-use graph and come up with a good location after looking through
// loads and projections.

View File

@@ -1301,6 +1301,8 @@ CastOptimizer::optimizeCheckedCastBranchInst(CheckedCastBranchInst *Inst) {
// checked_cast_br %1, ....
if (auto *FoundIERI = dyn_cast<InitExistentialRefInst>(Op)) {
SILValue op = FoundIERI->getOperand();
if (auto *eir = dyn_cast<EndInitLetRefInst>(op))
op = eir->getOperand();
if (!isa<AllocRefInst>(op))
return nullptr;

View File

@@ -5,6 +5,7 @@
// REQUIRES: concurrency
// REQUIRES: asserts
// REQUIRES: swift_in_compiler
actor A {
var x: String = "Hello"
@@ -44,20 +45,21 @@ actor C {
}
// CHECK-LABEL: sil hidden @$s21default_actor_definit1CC1yACSgSi_tcfc
// CHECK: builtin "initializeDefaultActor"(%1 : $C)
// CHECK: [[X:%.*]] = ref_element_addr %1 : $C, #C.x
// CHECK: [[EI:%.*]] = end_init_let_ref %1
// CHECK: [[X:%.*]] = ref_element_addr [[EI]] : $C, #C.x
// CHECK-NEXT: [[ACCESS:%.*]] = begin_access [init] [static] [[X]] : $*String
// CHECK-NEXT: store {{.*}} to [[ACCESS]] : $*String
// CHECK-NEXT: end_access [[ACCESS]] : $*String
// CHECK: cond_br {{%.*}}, bb1, bb2
// CHECK: bb1:
// CHECK: ref_element_addr %1 : $C, #C.y
// CHECK: ref_element_addr [[EI]] : $C, #C.y
// CHECK: br bb3
// CHECK: bb2:
// CHECK: [[X:%.*]] = ref_element_addr %1 : $C, #C.x
// CHECK: [[X:%.*]] = ref_element_addr [[EI]] : $C, #C.x
// CHECK-NEXT: [[ACCESS:%.*]] = begin_access [deinit] [static] [[X]] : $*String
// CHECK-NEXT: destroy_addr [[ACCESS]] : $*String
// CHECK-NEXT: end_access [[ACCESS]] : $*String
// CHECK: builtin "destroyDefaultActor"(%1 : $C)
// CHECK: builtin "destroyDefaultActor"([[EI]] : $C)
// CHECK: br bb3
// CHECK-LABEL: end sil function '$s21default_actor_definit1CC1yACSgSi_tcfc'

View File

@@ -3,6 +3,7 @@
// RUN: %target-swift-frontend -module-name default_deinit -primary-file %s -emit-sil -verify -disable-availability-checking -I %t | %FileCheck %s --enable-var-scope --dump-input=fail
// REQUIRES: concurrency
// REQUIRES: distributed
// REQUIRES: swift_in_compiler
/// The convention in this test is that the Swift declaration comes before its FileCheck lines.
@@ -55,9 +56,10 @@ distributed actor MyDistActor {
// CHECK: return [[SELF]]
// CHECK: [[ERROR_BB]]([[ERRVAL:%[0-9]+]] : $any Error):
// CHECK-NEXT: [[MU:%.*]] = end_init_let_ref [[SELF]]
// CHECK-NEXT: = metatype $@thick MyDistActor.Type
// CHECK-NEXT: = builtin "destroyDefaultActor"([[SELF]] : $MyDistActor) : $()
// CHECK-NEXT: dealloc_partial_ref [[SELF]]
// CHECK-NEXT: = builtin "destroyDefaultActor"([[MU]] : $MyDistActor) : $()
// CHECK-NEXT: dealloc_partial_ref [[MU]]
// CHECK: throw [[ERRVAL]] : $any Error
// CHECK: } // end sil function '$s14default_deinit11MyDistActorCACyKcfc'

View File

@@ -3,6 +3,7 @@
// RUN: %target-swift-frontend -module-name default_deinit -primary-file %s -emit-sil -verify -disable-availability-checking -I %t | %FileCheck %s --enable-var-scope --dump-input=fail
// REQUIRES: concurrency
// REQUIRES: distributed
// REQUIRES: swift_in_compiler
/// The convention in this test is that the Swift declaration comes before its FileCheck lines.
@@ -89,8 +90,9 @@ distributed actor MyDistActor {
// CHECK: [[SYSTEM_ACC:%[0-9]+]] = begin_access [deinit] [static] [[REF_SYS_D2]] : $*FakeActorSystem
// CHECK: destroy_addr [[SYSTEM_ACC]] : $*FakeActorSystem
// CHECK: end_access [[SYSTEM_ACC]] : $*FakeActorSystem
// CHECK: builtin "destroyDefaultActor"([[SELF]] : $MyDistActor) : $()
// CHECK: dealloc_partial_ref [[SELF]]
// CHECK: [[EI:%.*]] = end_init_let_ref [[SELF]]
// CHECK: builtin "destroyDefaultActor"([[EI]] : $MyDistActor) : $()
// CHECK: dealloc_partial_ref [[EI]]
// CHECK: throw

View File

@@ -3,6 +3,7 @@
// RUN: %target-swift-frontend -module-name default_deinit -primary-file %s -emit-sil -verify -disable-availability-checking -I %t | %FileCheck %s --enable-var-scope --dump-input=fail
// REQUIRES: concurrency
// REQUIRES: distributed
// REQUIRES: swift_in_compiler
/// The convention in this test is that the Swift declaration comes before its FileCheck lines.
@@ -93,8 +94,9 @@ distributed actor MyDistActor {
// CHECK: [[SYSTEM_ACC:%[0-9]+]] = begin_access [deinit] [static] [[REF_SYS_D2]] : $*FakeRoundtripActorSystem
// CHECK: destroy_addr [[SYSTEM_ACC]] : $*FakeRoundtripActorSystem
// CHECK: end_access [[SYSTEM_ACC]] : $*FakeRoundtripActorSystem
// CHECK: builtin "destroyDefaultActor"([[SELF]] : $MyDistActor) : $()
// CHECK: dealloc_partial_ref [[SELF]]
// CHECK: [[EI:%.*]] = end_init_let_ref [[SELF]]
// CHECK: builtin "destroyDefaultActor"([[EI]] : $MyDistActor) : $()
// CHECK: dealloc_partial_ref [[EI]]
// CHECK: throw

View File

@@ -3,6 +3,7 @@
// RUN: %target-swift-frontend -module-name default_deinit -primary-file %s -emit-sil -verify -disable-availability-checking -I %t | %FileCheck %s --enable-var-scope --dump-input=fail
// REQUIRES: concurrency
// REQUIRES: distributed
// REQUIRES: swift_in_compiler
/// The convention in this test is that the Swift declaration comes before its FileCheck lines.
@@ -21,10 +22,10 @@ distributed actor MyDistActor {
// CHECK: [[SYS_RESOLVE_RESULT:%[0-9]+]] = function_ref @$s27FakeDistributedActorSystems0a9RoundtripC6SystemC7resolve2id2asxSgAA0C7AddressV_xmtK0B00bC0RzlF
// CHECK: [[ACTOR_INSTANCE:%[0-9]+]] = builtin "initializeDistributedRemoteActor"(%7 : $@thick MyDistActor.Type) : $MyDistActor
// CHECK: [[ID_PROPERTY:%[0-9]+]] = ref_element_addr [[ACTOR_INSTANCE]] : $MyDistActor, #MyDistActor.id
// CHECK: [[ID_PROPERTY:%[0-9]+]] = ref_element_addr [immutable] [[ACTOR_INSTANCE]] : $MyDistActor, #MyDistActor.id
// CHECK: retain_value [[ACTOR_ID_ARG]] : $ActorAddress
// CHECK: store [[ACTOR_ID_ARG]] to [[ID_PROPERTY]] : $*ActorAddress
// CHECK: [[SYSTEM_PROPERTY:%[0-9]+]] = ref_element_addr [[ACTOR_INSTANCE]] : $MyDistActor, #MyDistActor.actorSystem
// CHECK: [[SYSTEM_PROPERTY:%[0-9]+]] = ref_element_addr [immutable] [[ACTOR_INSTANCE]] : $MyDistActor, #MyDistActor.actorSystem
// CHECK: strong_retain [[SYSTEM_ARG]] : $FakeRoundtripActorSystem
// CHECK: store [[SYSTEM_ARG]] to [[SYSTEM_PROPERTY]] : $*FakeRoundtripActorSystem
// CHECK: br bb5([[ACTOR_INSTANCE]] : $MyDistActor)

View File

@@ -39,7 +39,7 @@ distributed actor Greeter {
// CHECK: [[TYPE:%[0-9]+]] = metatype $@thick Greeter.Type
// CHECK: [[INSTANCE:%[0-9]+]] = builtin "initializeDistributedRemoteActor"([[TYPE]] : $@thick Greeter.Type) : $Greeter
// CHECK: [[ID_PROPERTY:%[0-9]+]] = ref_element_addr [[INSTANCE]] : $Greeter, #Greeter.id
// CHECK: [[ID_PROPERTY:%[0-9]+]] = ref_element_addr [immutable] [[INSTANCE]] : $Greeter, #Greeter.id
// Note specifically that we don't [take] in the below copy_addr:
// CHECK: copy_addr [[ADDRESS_ARG]] to [init] [[ID_PROPERTY]] : $*NotLoadableActorAddress

View File

@@ -34,7 +34,8 @@ func useNode(n: Base) -> Int {
// CHECK-LABEL: sil [noinline] @$s9arc_crash14testMayReleaseAA4BaseCyF : $@convention(thin) () -> @owned Base {
// CHECK: [[BASE:%.*]] = alloc_ref $Base
// CHECK: strong_retain [[BASE]] : $Base
// CHECK: [[EI:%.*]] = end_init_let_ref [[BASE]]
// CHECK: strong_retain [[EI]] : $Base
// CHECK: apply %{{.*}} : $@convention(thin) (@owned Queue) -> ()
// CHECK-LABEL: } // end sil function '$s9arc_crash14testMayReleaseAA4BaseCyF'
@inline(never)

View File

@@ -14,9 +14,10 @@ func borrow(_ c: C)
// CHECK-LABEL: sil {{.*}}@test_hoist_over_non_barrier : {{.*}} {
// CHECK: [[INSTANCE:%[^,]+]] = alloc_ref
// CHECK: [[EI:%.*]] = end_init_let_ref [[INSTANCE]]
// CHECK: [[BORROW:%[^,]+]] = function_ref @borrow
// CHECK: apply [[BORROW]]([[INSTANCE]])
// CHECK: strong_release [[INSTANCE]]
// CHECK: apply [[BORROW]]([[EI]])
// CHECK: strong_release [[EI]]
// CHECK: [[NON_BARRIER:%[^,]+]] = function_ref @non_barrier
// CHECK: apply [[NON_BARRIER]]()
// CHECK-LABEL: } // end sil function 'test_hoist_over_non_barrier'

View File

@@ -1,6 +1,7 @@
// RUN: %target-swift-frontend -module-name test -disable-availability-checking -swift-version 5 -sil-verify-all -emit-sil %s | %FileCheck --enable-var-scope --implicit-check-not='hop_to_executor' %s
// REQUIRES: concurrency
// REQUIRES: swift_in_compiler
enum ActingError<T> : Error {
case forgotLine
@@ -15,14 +16,16 @@ actor BoringActor {
// CHECK-LABEL: sil hidden @$s4test11BoringActorCACyYacfc : $@convention(method) @async (@owned BoringActor) -> @owned BoringActor {
// CHECK: bb0([[SELF:%[0-9]+]] : $BoringActor):
// CHECK: initializeDefaultActor
// CHECK-NEXT: hop_to_executor [[SELF]]
// CHECK: [[EI:%.*]] = end_init_let_ref [[SELF]]
// CHECK-NEXT: hop_to_executor [[EI]]
// CHECK: } // end sil function '$s4test11BoringActorCACyYacfc'
init() async {}
// CHECK-LABEL: sil hidden @$s4test11BoringActorC4sizeACSi_tYacfc : $@convention(method) @async (Int, @owned BoringActor) -> @owned BoringActor {
// CHECK: bb0({{%[0-9]+}} : $Int, [[SELF:%[0-9]+]] : $BoringActor):
// CHECK: initializeDefaultActor
// CHECK-NEXT: hop_to_executor [[SELF]]
// CHECK: [[EI:%.*]] = end_init_let_ref [[SELF]]
// CHECK-NEXT: hop_to_executor [[EI]]
// CHECK: } // end sil function '$s4test11BoringActorC4sizeACSi_tYacfc'
init(size: Int) async {
var sz = size
@@ -47,14 +50,16 @@ actor BoringActor {
// CHECK-LABEL: sil hidden @$s4test11BoringActorC6crashyACSgyt_tYacfc : $@convention(method) @async (@owned BoringActor) -> @owned Optional<BoringActor> {
// CHECK: bb0([[SELF:%[0-9]+]] : $BoringActor):
// CHECK: initializeDefaultActor
// CHECK-NEXT: hop_to_executor [[SELF]]
// CHECK: [[EI:%.*]] = end_init_let_ref [[SELF]]
// CHECK-NEXT: hop_to_executor [[EI]]
// CHECK: } // end sil function '$s4test11BoringActorC6crashyACSgyt_tYacfc'
init!(crashy: Void) async { return nil }
// CHECK-LABEL: sil hidden @$s4test11BoringActorC5nillyACSgSi_tYacfc : $@convention(method) @async (Int, @owned BoringActor) -> @owned Optional<BoringActor> {
// CHECK: bb0({{%[0-9]+}} : $Int, [[SELF:%[0-9]+]] : $BoringActor):
// CHECK: initializeDefaultActor
// CHECK-NEXT: hop_to_executor [[SELF]]
// CHECK: [[EI:%.*]] = end_init_let_ref [[SELF]]
// CHECK-NEXT: hop_to_executor [[EI]]
// CHECK: } // end sil function '$s4test11BoringActorC5nillyACSgSi_tYacfc'
init?(nilly: Int) async {
guard nilly > 0 else { return nil }
@@ -70,9 +75,10 @@ actor BoringActor {
// CHECK-LABEL: sil hidden @$s4test14SingleVarActorCACyYacfc : $@convention(method) @async (@owned SingleVarActor) -> @owned SingleVarActor {
// CHECK: bb0([[SELF:%[0-9]+]] : $SingleVarActor):
// CHECK: [[EI:%.*]] = end_init_let_ref [[SELF]]
// CHECK: store {{%[0-9]+}} to [[ACCESS:%[0-9]+]]
// CHECK-NEXT: end_access [[ACCESS]]
// CHECK-NEXT: hop_to_executor [[SELF]] : $SingleVarActor
// CHECK-NEXT: hop_to_executor [[EI]] : $SingleVarActor
// CHECK: store {{%[0-9]+}} to {{%[0-9]+}}
// CHECK: } // end sil function '$s4test14SingleVarActorCACyYacfc'
init() async {
@@ -82,11 +88,12 @@ actor BoringActor {
// CHECK-LABEL: sil hidden @$s4test14SingleVarActorC10iterationsACSi_tYacfc : $@convention(method) @async (Int, @owned SingleVarActor) -> @owned SingleVarActor {
// CHECK: bb0({{%[0-9]+}} : $Int, [[SELF:%[0-9]+]] : $SingleVarActor):
// CHECK: [[MYVAR_REF:%[0-9]+]] = ref_element_addr [[SELF]] : $SingleVarActor, #SingleVarActor.myVar
// CHECK: [[EI:%.*]] = end_init_let_ref [[SELF]]
// CHECK: [[MYVAR_REF:%[0-9]+]] = ref_element_addr [[EI]] : $SingleVarActor, #SingleVarActor.myVar
// CHECK: [[MYVAR:%[0-9]+]] = begin_access [init] [static] [[MYVAR_REF]] : $*Int
// CHECK: store {{%[0-9]+}} to [[MYVAR]] : $*Int
// CHECK-NEXT: end_access [[MYVAR]]
// CHECK-NEXT: hop_to_executor [[SELF]] : $SingleVarActor
// CHECK-NEXT: hop_to_executor [[EI]] : $SingleVarActor
// CHECK: } // end sil function '$s4test14SingleVarActorC10iterationsACSi_tYacfc'
init(iterations: Int) async {
var iter = iterations
@@ -99,17 +106,18 @@ actor BoringActor {
// CHECK-LABEL: sil hidden @$s4test14SingleVarActorC2b12b2ACSb_SbtYacfc : $@convention(method) @async (Bool, Bool, @owned SingleVarActor) -> @owned SingleVarActor {
// CHECK: bb0({{%[0-9]+}} : $Bool, {{%[0-9]+}} : $Bool, [[SELF:%[0-9]+]] : $SingleVarActor):
// CHECK: [[EI:%.*]] = end_init_let_ref [[SELF]]
// CHECK: store {{%[0-9]+}} to [[A1:%[0-9]+]] : $*Int
// CHECK-NEXT: end_access [[A1]]
// CHECK-NEXT: hop_to_executor [[SELF]] : $SingleVarActor
// CHECK-NEXT: hop_to_executor [[EI]] : $SingleVarActor
// CHECK: store {{%[0-9]+}} to [[A2:%[0-9]+]] : $*Int
// CHECK-NEXT: end_access [[A2]]
// CHECK-NEXT: hop_to_executor [[SELF]] : $SingleVarActor
// CHECK-NEXT: hop_to_executor [[EI]] : $SingleVarActor
// CHECK: store {{%[0-9]+}} to [[A3:%[0-9]+]] : $*Int
// CHECK-NEXT: end_access [[A3]]
// CHECK-NEXT: hop_to_executor [[SELF]] : $SingleVarActor
// CHECK-NEXT: hop_to_executor [[EI]] : $SingleVarActor
// CHECK: } // end sil function '$s4test14SingleVarActorC2b12b2ACSb_SbtYacfc'
init(b1: Bool, b2: Bool) async {
@@ -171,15 +179,17 @@ actor DefaultInit {
// CHECK-LABEL: sil hidden @$s4test11DefaultInitCACyYacfc : $@convention(method) @async (@owned DefaultInit) -> @owned DefaultInit {
// CHECK: bb0([[SELF:%[0-9]+]] : $DefaultInit):
// CHECK: [[EI:%.*]] = end_init_let_ref [[SELF]]
// CHECK: store {{%[0-9]+}} to {{%[0-9]+}} : $*ActingError<Int>
// CHECK-NEXT: hop_to_executor [[SELF]] : $DefaultInit
// CHECK-NEXT: hop_to_executor [[EI]] : $DefaultInit
// CHECK: } // end sil function '$s4test11DefaultInitCACyYacfc'
init() async {}
// CHECK-LABEL: sil hidden @$s4test11DefaultInitC5nillyACSgSb_tYacfc : $@convention(method) @async (Bool, @owned DefaultInit) -> @owned Optional<DefaultInit> {
// CHECK: bb0({{%[0-9]+}} : $Bool, [[SELF:%[0-9]+]] : $DefaultInit):
// CHECK: [[EI:%.*]] = end_init_let_ref [[SELF]]
// CHECK: store {{%[0-9]+}} to {{%[0-9]+}} : $*ActingError<Int>
// CHECK-NEXT: hop_to_executor [[SELF]] : $DefaultInit
// CHECK-NEXT: hop_to_executor [[EI]] : $DefaultInit
// CHECK: } // end sil function '$s4test11DefaultInitC5nillyACSgSb_tYacfc'
init?(nilly: Bool) async {
guard nilly else { return nil }
@@ -195,11 +205,12 @@ actor MultiVarActor {
// CHECK-LABEL: sil hidden @$s4test13MultiVarActorC10doNotThrowACSb_tYaKcfc : $@convention(method) @async (Bool, @owned MultiVarActor) -> (@owned MultiVarActor, @error any Error) {
// CHECK: bb0({{%[0-9]+}} : $Bool, [[SELF:%[0-9]+]] : $MultiVarActor):
// CHECK: [[REF:%[0-9]+]] = ref_element_addr [[SELF]] : $MultiVarActor, #MultiVarActor.firstVar
// CHECK: [[EI:%.*]] = end_init_let_ref [[SELF]]
// CHECK: [[REF:%[0-9]+]] = ref_element_addr [[EI]] : $MultiVarActor, #MultiVarActor.firstVar
// CHECK: [[VAR:%[0-9]+]] = begin_access [init] [static] [[REF]] : $*Int
// CHECK: store {{%[0-9]+}} to [[VAR]] : $*Int
// CHECK-NEXT: end_access [[VAR]]
// CHECK-NEXT: hop_to_executor %1 : $MultiVarActor
// CHECK-NEXT: hop_to_executor [[EI]] : $MultiVarActor
// CHECK: } // end sil function '$s4test13MultiVarActorC10doNotThrowACSb_tYaKcfc'
init(doNotThrow: Bool) async throws {
secondVar = 0

View File

@@ -723,8 +723,9 @@ class FailableBaseClass {
// CHECK-LABEL: sil hidden @$s35definite_init_failable_initializers17FailableBaseClassC28failBeforeFullInitializationACSgyt_tcfc
// CHECK: bb0(%0 : $FailableBaseClass):
// CHECK: [[EI:%.*]] = end_init_let_ref %0
// CHECK: [[METATYPE:%.*]] = metatype $@thick FailableBaseClass.Type
// CHECK: dealloc_partial_ref %0 : $FailableBaseClass, [[METATYPE]]
// CHECK: dealloc_partial_ref [[EI]] : $FailableBaseClass, [[METATYPE]]
// CHECK: [[RESULT:%.*]] = enum $Optional<FailableBaseClass>, #Optional.none!enumelt
// CHECK: return [[RESULT]]
init?(failBeforeFullInitialization: ()) {
@@ -733,12 +734,13 @@ class FailableBaseClass {
// CHECK-LABEL: sil hidden @$s35definite_init_failable_initializers17FailableBaseClassC27failAfterFullInitializationACSgyt_tcfc
// CHECK: bb0(%0 : $FailableBaseClass):
// CHECK: [[EI:%.*]] = end_init_let_ref %0
// CHECK: [[CANARY:%.*]] = apply
// CHECK-NEXT: [[MEMBER_ADDR:%.*]] = ref_element_addr %0
// CHECK-NEXT: [[MEMBER_ADDR:%.*]] = ref_element_addr [[EI]]
// CHECK-NEXT: [[WRITE:%.*]] = begin_access [init] [static] [[MEMBER_ADDR]] : $*Canary
// CHECK-NEXT: store [[CANARY]] to [[WRITE]]
// CHECK-NEXT: end_access [[WRITE]] : $*Canary
// CHECK-NEXT: strong_release %0
// CHECK-NEXT: strong_release [[EI]]
// CHECK-NEXT: [[NEW_SELF:%.*]] = enum $Optional<FailableBaseClass>, #Optional.none!enumelt
// CHECK-NEXT: return [[NEW_SELF]]
init?(failAfterFullInitialization: ()) {

View File

@@ -244,7 +244,7 @@ bb0(%0 : $*T, %1 : $*T):
// CHECK-NEXT: copy_addr [[PB]] to [init] %0 : $*T
destroy_value %ba : $<τ_0_0> { var τ_0_0 } <T>
// CHECK-NEXT: destroy_value %2
// CHECK-NEXT: destroy_value %3
%9 = tuple ()
return %9 : $()
}
@@ -266,7 +266,7 @@ bb0:
// This should become an initialization.
store_weak %4 to %c : $*@sil_weak Optional<SomeClass>
// CHECK-NEXT: store_weak [[C1]] to [init] %1
// CHECK-NEXT: store_weak [[C1]] to [init] %2
destroy_value %4 : $Optional<SomeClass>
// CHECK-NEXT: destroy_value [[C1]]
@@ -275,7 +275,7 @@ bb0:
// CHECK-NEXT: [[C2:%[0-9]+]] = apply
store_weak %8 to %c : $*@sil_weak Optional<SomeClass>
// CHECK-NEXT: store_weak [[C2]] to %1
// CHECK-NEXT: store_weak [[C2]] to %2
destroy_value %8 : $Optional<SomeClass>
// CHECK-NEXT: destroy_value [[C2]]
@@ -376,7 +376,7 @@ bb0(%0 : $*SomeClass, %1 : @owned $SomeClass):
sil_global @int_global : $Int
// CHECK-LABEL: sil [ossa] @test_tlc
// CHECK-NOT: mark_uninitialized
// CHECK: mark_uninitialized
// CHECK: return
sil [ossa] @test_tlc : $() -> () {
%0 = global_addr @int_global : $*Int
@@ -395,8 +395,9 @@ sil [ossa] @use : $@convention(thin) (@in P) -> ()
// CHECK-LABEL: sil [ossa] @release_not_constructed
sil [ossa] @release_not_constructed : $@convention(thin) () -> () {
bb0: // CHECK: bb0:
%3 = alloc_stack $SomeClass
// CHECK-NEXT: alloc_stack
%3 = alloc_stack $SomeClass
// CHECK-NEXT: mark_uninitialized
%c = mark_uninitialized [var] %3 : $*SomeClass
@@ -445,7 +446,7 @@ entry(%a : $*C):
%q = init_existential_addr %b : $*P, $C
// CHECK: copy_addr {{.*}} to [init] %2 : $*C
// CHECK: copy_addr {{.*}} to [init] %3 : $*C
copy_addr %a to [init] %q : $*C
%u = function_ref @use : $@convention(thin) (@in P) -> ()
%v = apply %u(%b) : $@convention(thin) (@in P) -> ()
@@ -495,6 +496,7 @@ sil [ossa] @conditionalInitOrAssign : $@convention(thin) (Builtin.Int1) -> () {
bb0(%0 : $Builtin.Int1):
// CHECK: [[CONTROL:%[0-9]+]] = alloc_stack $Builtin.Int1
// CHECK: [[CLASSVAL:%[0-9]+]] = alloc_stack [dynamic_lifetime] $SomeClass
// CHECK: [[MU:%[0-9]+]] = mark_uninitialized [var] [[CLASSVAL]]
// CHECK: integer_literal $Builtin.Int1, 0
// CHECK: store
%5 = alloc_stack $SomeClass
@@ -511,7 +513,7 @@ bb1:
// updates the control variable to say that it is initialized.
// CHECK: integer_literal $Builtin.Int1, -1
// CHECK: store {{.*}} to [trivial] [[CONTROL]]
// CHECK: assign [[V1]] to [init] [[CLASSVAL]]
// CHECK: assign [[V1]] to [init] [[MU]]
assign %12 to %6 : $*SomeClass // id: %13
br bb3 // id: %14
@@ -529,10 +531,10 @@ bb3:
// CHECK: load [trivial] [[CONTROL]]
// CHECK: cond_br
// CHECK: bb4:
// CHECK: destroy_addr [[CLASSVAL]]
// CHECK: destroy_addr [[MU]]
// CHECK: br bb6
// CHECK: bb6:
// CHECK: assign [[V2]] to [init] [[CLASSVAL]]
// CHECK: assign [[V2]] to [init] [[MU]]
assign %17 to %6 : $*SomeClass // id: %18
destroy_addr %6 : $*SomeClass // id: %19
dealloc_stack %5 : $*SomeClass // id: %20
@@ -546,13 +548,14 @@ bb3:
// CHECK-LABEL: sil [ossa] @conditionalInitOrAssignAllocBox : $@convention(thin) () -> () {
// CHECK: bb0:
// CHECK: [[BOX:%.*]] = alloc_box
// CHECK: [[MU:%.*]] = mark_uninitialized [var] [[BOX]]
//
// CHECK: bb1:
// CHECK: destroy_value [[BOX]]
// CHECK: destroy_value [[MU]]
// CHECK: br bb3
//
// CHECK: bb2:
// CHECK: dealloc_box [[BOX]]
// CHECK: dealloc_box [[MU]]
// CHECK: br bb3
//
// CHECK: bb3:
@@ -587,7 +590,7 @@ bb3:
// pointer. LLDB shouldn't do this, but until it is removed and validated we
// need a test for this.
// CHECK-LABEL: sil [ossa] @lldb_unsupported_markuninitialized_testcase : $@convention(thin) (UnsafeMutablePointer<Any>) -> () {
// CHECK-NOT: mark_uninitialized [var]
// CHECK: mark_uninitialized [var]
// CHECK: } // end sil function 'lldb_unsupported_markuninitialized_testcase'
sil [ossa] @lldb_unsupported_markuninitialized_testcase : $@convention(thin) (UnsafeMutablePointer<Any>) -> () {
bb0(%0 : $UnsafeMutablePointer<Any>):

View File

@@ -13,7 +13,8 @@ sil @closureTakeVal : $@convention(thin) (@guaranteed { let S }) -> ()
// CHECK-LABEL: sil hidden [ossa] @letControlFlowDependentInitializationNoEscape : $@convention(thin) () -> () {
// CHECK: [[STACK:%.*]] = alloc_stack
// CHECK: [[MARK:%.*]] = mark_unresolved_non_copyable_value [consumable_and_assignable] [[STACK]]
// CHECK: [[MU:%.*]] = mark_uninitialized [var] [[STACK]]
// CHECK: [[MARK:%.*]] = mark_unresolved_non_copyable_value [consumable_and_assignable] [[MU]]
// CHECK: cond_br undef, [[LHS_BB:bb[0-9]+]], [[RHS_BB:bb[0-9]+]]
//
// CHECK: [[LHS_BB]]:
@@ -68,7 +69,8 @@ bb3:
// CHECK-LABEL: sil hidden [ossa] @letControlFlowDependentInitializationEscape : $@convention(thin) () -> () {
// CHECK: [[BOX:%.*]] = alloc_box
// CHECK: [[PROJECT:%.*]] = project_box [[BOX]]
// CHECK: [[MU:%.*]] = mark_uninitialized [var] [[BOX]]
// CHECK: [[PROJECT:%.*]] = project_box [[MU]]
// CHECK: cond_br undef, [[LHS_BB:bb[0-9]+]], [[RHS_BB:bb[0-9]+]]
//
// CHECK: [[LHS_BB]]:

View File

@@ -4,6 +4,8 @@
// output. At least until -enable-copy-propagation has been around
// long enough in the same form to be worth rewriting CHECK lines.
// REQUIRES: swift_in_compiler
class OtherClass {}
class FirstClass {
@@ -12,6 +14,7 @@ class FirstClass {
// CHECK-LABEL: sil hidden @$s24definite_init_root_class10FirstClassC1nACSgs5Int32V_tcfc : $@convention(method) (Int32, @owned FirstClass) -> @owned Optional<FirstClass>
init?(n: Int32) {
// CHECK: [[CONTROL:%.*]] = alloc_stack $Builtin.Int1
// CHECK: [[EI:%.*]] = end_init_let_ref %1
// CHECK: [[ZERO:%.*]] = integer_literal $Builtin.Int1, 0
// CHECK: store [[ZERO]] to [[CONTROL]] : $*Builtin.Int1
@@ -30,8 +33,8 @@ class FirstClass {
// CHECK: [[METATYPE:%.*]] = metatype $@thick OtherClass.Type
// CHECK: [[INIT:%.*]] = function_ref @$s24definite_init_root_class10OtherClassCACycfC : $@convention(method) (@thick OtherClass.Type) -> @owned OtherClass
// CHECK: [[OTHER:%.*]] = apply [[INIT]]([[METATYPE]]) : $@convention(method) (@thick OtherClass.Type) -> @owned OtherClass
// CHECK: [[X_ADDR:%.*]] = ref_element_addr %1 : $FirstClass, #FirstClass.x
// CHECK: [[X_ACCESS:%.*]] = begin_access [init] [static] %15 : $*OtherClass
// CHECK: [[X_ADDR:%.*]] = ref_element_addr [[EI]] : $FirstClass, #FirstClass.x
// CHECK: [[X_ACCESS:%.*]] = begin_access [init] [static] [[X_ADDR]] : $*OtherClass
// CHECK: [[ONE:%.*]] = integer_literal $Builtin.Int1, -1
// CHECK: store [[ONE]] to [[CONTROL]] : $*Builtin.Int1
// CHECK: store [[OTHER]] to [[X_ACCESS]] : $*OtherClass
@@ -50,7 +53,7 @@ class FirstClass {
// CHECK: br bb5
// CHECK: bb4:
// CHECK: [[RESULT:%.*]] = enum $Optional<FirstClass>, #Optional.some!enumelt, %1 : $FirstClass
// CHECK: [[RESULT:%.*]] = enum $Optional<FirstClass>, #Optional.some!enumelt, [[EI]] : $FirstClass
// CHECK: br bb12([[RESULT]] : $Optional<FirstClass>)
// CHECK: bb5:
@@ -58,7 +61,7 @@ class FirstClass {
// CHECK: cond_br [[BIT]], bb6, bb7
// CHECK: bb6:
// CHECK: strong_release %1 : $FirstClass
// CHECK: strong_release [[EI]] : $FirstClass
// CHECK: br bb11
// CHECK: bb7:
@@ -66,7 +69,7 @@ class FirstClass {
// CHECK: cond_br [[BIT]], bb8, bb9
// CHECK: bb8:
// CHECK: [[X_ADDR:%.*]] = ref_element_addr %1 : $FirstClass, #FirstClass.x
// CHECK: [[X_ADDR:%.*]] = ref_element_addr [[EI]] : $FirstClass, #FirstClass.x
// CHECK: [[X_ACCESS:%.*]] = begin_access [deinit] [static] [[X_ADDR]] : $*OtherClass
// CHECK: destroy_addr [[X_ACCESS]] : $*OtherClass
// CHECK: end_access [[X_ACCESS]] : $*OtherClass
@@ -76,7 +79,7 @@ class FirstClass {
// CHECK: br bb10
// CHECK: [[METATYPE:%.*]] = metatype $@thick FirstClass.Type
// CHECK: dealloc_partial_ref %1 : $FirstClass, [[METATYPE]] : $@thick FirstClass.Type
// CHECK: dealloc_partial_ref [[EI]] : $FirstClass, [[METATYPE]] : $@thick FirstClass.Type
// CHECK: br bb11
// CHECK: bb11:
@@ -96,6 +99,7 @@ class SecondClass {
// CHECK-LABEL: sil hidden @$s24definite_init_root_class11SecondClassC1nACSgs5Int32V_tcfc : $@convention(method) (Int32, @owned SecondClass) -> @owned Optional<SecondClass> {
init?(n: Int32) {
// CHECK: [[CONTROL:%.*]] = alloc_stack $Builtin.Int2
// CHECK: [[EI:%.*]] = end_init_let_ref %1
// CHECK: [[ZERO:%.*]] = integer_literal $Builtin.Int2, 0
// CHECK: store [[ZERO]] to [[CONTROL]] : $*Builtin.Int2
@@ -114,7 +118,7 @@ class SecondClass {
// CHECK: [[METATYPE:%.*]] = metatype $@thick OtherClass.Type
// CHECK: [[INIT:%.*]] = function_ref @$s24definite_init_root_class10OtherClassCACycfC : $@convention(method) (@thick OtherClass.Type) -> @owned OtherClass
// CHECK: [[OTHER:%.*]] = apply [[INIT]]([[METATYPE]]) : $@convention(method) (@thick OtherClass.Type) -> @owned OtherClass
// CHECK: [[X_ADDR:%.*]] = ref_element_addr %1 : $SecondClass, #SecondClass.x
// CHECK: [[X_ADDR:%.*]] = ref_element_addr [[EI]] : $SecondClass, #SecondClass.x
// CHECK: [[X_ACCESS:%.*]] = begin_access [init] [static] [[X_ADDR]] : $*OtherClass
// CHECK: [[ONE:%.*]] = integer_literal $Builtin.Int2, 1
// CHECK: store [[ONE]] to [[CONTROL]] : $*Builtin.Int2
@@ -137,7 +141,7 @@ class SecondClass {
// CHECK: [[METATYPE:%.*]] = metatype $@thick OtherClass.Type
// CHECK: [[INIT:%.*]] = function_ref @$s24definite_init_root_class10OtherClassCACycfC : $@convention(method) (@thick OtherClass.Type) -> @owned OtherClass
// CHECK: [[OTHER:%.*]] = apply [[INIT]]([[METATYPE]]) : $@convention(method) (@thick OtherClass.Type) -> @owned OtherClass
// CHECK: [[Y_ADDR:%.*]] = ref_element_addr %1 : $SecondClass, #SecondClass.y
// CHECK: [[Y_ADDR:%.*]] = ref_element_addr [[EI]] : $SecondClass, #SecondClass.y
// CHECK: [[Y_ACCESS:%.*]] = begin_access [init] [static] [[Y_ADDR]] : $*OtherClass
// CHECK: [[THREE:%.*]] = integer_literal $Builtin.Int2, -1
// CHECK: store [[THREE]] to [[CONTROL]] : $*Builtin.Int2
@@ -157,7 +161,7 @@ class SecondClass {
// CHECK: br bb7
// CHECK: bb6:
// CHECK: [[RESULT:%.*]] = enum $Optional<SecondClass>, #Optional.some!enumelt, %1 : $SecondClass
// CHECK: [[RESULT:%.*]] = enum $Optional<SecondClass>, #Optional.some!enumelt, [[EI]] : $SecondClass
// CHECK: br bb17([[RESULT]] : $Optional<SecondClass>)
// CHECK: bb7:
@@ -167,7 +171,7 @@ class SecondClass {
// CHECK: cond_br [[BIT]], bb8, bb9
// CHECK: bb8:
// CHECK: strong_release %1 : $SecondClass
// CHECK: strong_release [[EI]] : $SecondClass
// CHECK: br bb16
// CHECK: bb9:
@@ -176,7 +180,7 @@ class SecondClass {
// CHECK: cond_br [[BIT]], bb10, bb11
// CHECK: bb10:
// CHECK: [[X_ADDR:%.*]] = ref_element_addr %1 : $SecondClass, #SecondClass.x
// CHECK: [[X_ADDR:%.*]] = ref_element_addr [[EI]] : $SecondClass, #SecondClass.x
// CHECK: [[X_ACCESS:%.*]] = begin_access [deinit] [static] [[X_ADDR]] : $*OtherClass
// CHECK: destroy_addr [[X_ACCESS]] : $*OtherClass
// CHECK: end_access [[X_ACCESS]] : $*OtherClass
@@ -193,7 +197,7 @@ class SecondClass {
// CHECK: cond_br [[BIT]], bb13, bb14
// CHECK: bb13:
// CHECK: [[Y_ADDR:%.*]] = ref_element_addr %1 : $SecondClass, #SecondClass.y
// CHECK: [[Y_ADDR:%.*]] = ref_element_addr [[EI]] : $SecondClass, #SecondClass.y
// CHECK: [[Y_ACCESS:%.*]] = begin_access [deinit] [static] [[Y_ADDR]] : $*OtherClass
// CHECK: destroy_addr [[Y_ACCESS]] : $*OtherClass
// CHECK: end_access [[Y_ACCESS]] : $*OtherClass
@@ -204,7 +208,7 @@ class SecondClass {
// CHECK: bb15:
// CHECK: [[METATYPE:%.*]] = metatype $@thick SecondClass.Type
// CHECK: dealloc_partial_ref %1 : $SecondClass, [[METATYPE]] : $@thick SecondClass.Type
// CHECK: dealloc_partial_ref [[EI]] : $SecondClass, [[METATYPE]] : $@thick SecondClass.Type
// CHECK: br bb16
// CHECK: bb16:

View File

@@ -625,14 +625,16 @@ bb0:
(%2,%3) = begin_cow_mutation %0 : $Derived
%4 = end_cow_mutation %3 : $Derived
%4b = begin_dealloc_ref %4 : $Derived of %0 : $Derived
%4a = end_init_let_ref %4 : $Derived
%4b = begin_dealloc_ref %4a : $Derived of %0 : $Derived
%5 = upcast %4b : $Derived to $X
%6 = init_existential_ref %5 : $X : $X, $ClassP
%7 = open_existential_ref %6 : $ClassP to $@opened("53729A20-8747-11EB-82C4-D0817AD9985D", ClassP) Self
(%8,%9) = begin_cow_mutation %1 : $Derived
%10 = end_cow_mutation %9 : $Derived
%10b = begin_dealloc_ref %10 : $Derived of %1 : $Derived
%10a = end_init_let_ref %10 : $Derived
%10b = begin_dealloc_ref %10a : $Derived of %1 : $Derived
%11 = upcast %10b : $Derived to $X
%12 = init_existential_ref %11 : $X : $X, $ClassP
%13 = open_existential_ref %12 : $ClassP to $@opened("12345678-8747-11EB-82C4-D0817AD9985D", ClassP) Self
@@ -653,14 +655,16 @@ bb0(%0 : $DerivedZ):
%3 = alloc_ref $DerivedZ
(%4,%5) = begin_cow_mutation %3 : $DerivedZ
%6 = end_cow_mutation %5 : $DerivedZ
%6b = begin_dealloc_ref %6 : $DerivedZ of %3 : $DerivedZ
%6a = end_init_let_ref %6 : $DerivedZ
%6b = begin_dealloc_ref %6a : $DerivedZ of %3 : $DerivedZ
%7 = upcast %6b : $DerivedZ to $Z
%8 = ref_element_addr %7 : $Z, #Z.y
store %1 to %8 : $*Y
(%10,%11) = begin_cow_mutation %0 : $DerivedZ
%12 = end_cow_mutation %11 : $DerivedZ
%13 = upcast %12 : $DerivedZ to $Z
%12a = end_init_let_ref %12 : $DerivedZ
%13 = upcast %12a : $DerivedZ to $Z
%14 = ref_element_addr %13 : $Z, #Z.y
store %2 to %14 : $*Y

View File

@@ -42,30 +42,32 @@ final class TestIndirectionThroughStorage {
}
// CHECK-LABEL: sil hidden [ossa] @$s23assign_or_init_lowering29TestIndirectionThroughStorageC4name3ageACSS_Sitcfc : $@convention(method) (@owned String, Int, @owned TestIndirectionThroughStorage) -> @owned TestIndirectionThroughStorage
// CHECK: [[SELF:%.*]] = mark_uninitialized [rootself] %2
// CHECK: [[STORAGE_REF:%.*]] = ref_element_addr {{.*}} : $TestIndirectionThroughStorage, #TestIndirectionThroughStorage._storage
// CHECK: [[STORAGE_INIT:%.*]] = function_ref @$s23assign_or_init_lowering29TestIndirectionThroughStorageC8_storage33_DE106275C2F16FB3D05881E72FBD87C8LLAA0H0_pAC1TAaFPRts_XPvpfi : $@convention(thin) () -> @out any Storage<TestIndirectionThroughStorage>
// CHECK-NEXT: {{.*}} = apply [[STORAGE_INIT]]([[STORAGE_REF]]) : $@convention(thin) () -> @out any Storage<TestIndirectionThroughStorage>
// Initialization:
// CHECK: assign_or_init [init] #TestIndirectionThroughStorage.name, self %2 : $TestIndirectionThroughStorage, value {{.*}} : $String, init {{.*}} : $@convention(thin) (@owned String, @inout any Storage<TestIndirectionThroughStorage>) -> (), set {{.*}} : $@callee_guaranteed (@owned String) -> ()
// CHECK: assign_or_init [init] #TestIndirectionThroughStorage.age, self %2 : $TestIndirectionThroughStorage, value {{.*}} : $Optional<Int>, init {{.*}} : $@convention(thin) (Optional<Int>, @inout any Storage<TestIndirectionThroughStorage>) -> (), set {{.*}} : $@callee_guaranteed (Optional<Int>) -> ()
// CHECK: assign_or_init [init] #TestIndirectionThroughStorage.name, self [[SELF]] : $TestIndirectionThroughStorage, value {{.*}} : $String, init {{.*}} : $@convention(thin) (@owned String, @inout any Storage<TestIndirectionThroughStorage>) -> (), set {{.*}} : $@callee_guaranteed (@owned String) -> ()
// CHECK: assign_or_init [init] #TestIndirectionThroughStorage.age, self [[SELF]] : $TestIndirectionThroughStorage, value {{.*}} : $Optional<Int>, init {{.*}} : $@convention(thin) (Optional<Int>, @inout any Storage<TestIndirectionThroughStorage>) -> (), set {{.*}} : $@callee_guaranteed (Optional<Int>) -> ()
// Explicit set:
// CHECK: assign_or_init [set] #TestIndirectionThroughStorage.name, self %2 : $TestIndirectionThroughStorage, value {{.*}} : $String, init {{.*}} : $@convention(thin) (@owned String, @inout any Storage<TestIndirectionThroughStorage>) -> (), set {{.*}} : $@callee_guaranteed (@owned String) -> ()
// CHECK: assign_or_init [set] #TestIndirectionThroughStorage.age, self %2 : $TestIndirectionThroughStorage, value {{.*}} : $Optional<Int>, init {{.*}} : $@convention(thin) (Optional<Int>, @inout any Storage<TestIndirectionThroughStorage>) -> (), set {{.*}} : $@callee_guaranteed (Optional<Int>) -> ()
// CHECK: assign_or_init [set] #TestIndirectionThroughStorage.name, self [[SELF]] : $TestIndirectionThroughStorage, value {{.*}} : $String, init {{.*}} : $@convention(thin) (@owned String, @inout any Storage<TestIndirectionThroughStorage>) -> (), set {{.*}} : $@callee_guaranteed (@owned String) -> ()
// CHECK: assign_or_init [set] #TestIndirectionThroughStorage.age, self [[SELF]] : $TestIndirectionThroughStorage, value {{.*}} : $Optional<Int>, init {{.*}} : $@convention(thin) (Optional<Int>, @inout any Storage<TestIndirectionThroughStorage>) -> (), set {{.*}} : $@callee_guaranteed (Optional<Int>) -> ()
init(name: String, age: Int) {
self.name = name
self.age = age
}
// CHECK-LABEL: sil hidden [ossa] @$s23assign_or_init_lowering29TestIndirectionThroughStorageC7storageAcA0H0_pAC1TAaEPRts_XP_tcfc : $@convention(method) (@in any Storage<TestIndirectionThroughStorage>, @owned TestIndirectionThroughStorage) -> @owned TestIndirectionThroughStorage
// CHECK: [[SELF:%.*]] = mark_uninitialized [rootself] %1
// CHECK: [[STORAGE_REF:%.*]] = ref_element_addr {{.*}} : $TestIndirectionThroughStorage, #TestIndirectionThroughStorage._storage
// CHECK: [[STORAGE_INIT:%.*]] = function_ref @$s23assign_or_init_lowering29TestIndirectionThroughStorageC8_storage33_DE106275C2F16FB3D05881E72FBD87C8LLAA0H0_pAC1TAaFPRts_XPvpfi : $@convention(thin) () -> @out any Storage<TestIndirectionThroughStorage>
// CHECK-NEXT: {{.*}} = apply [[STORAGE_INIT]]([[STORAGE_REF]]) : $@convention(thin) () -> @out any Storage<TestIndirectionThroughStorage>
// Initialization:
// CHECK: assign_or_init [init] #TestIndirectionThroughStorage.name, self %1 : $TestIndirectionThroughStorage, value {{.*}} : $String, init {{.*}} : $@convention(thin) (@owned String, @inout any Storage<TestIndirectionThroughStorage>) -> (), set {{.*}} : $@callee_guaranteed (@owned String) -> ()
// CHECK: assign_or_init [init] #TestIndirectionThroughStorage.age, self %1 : $TestIndirectionThroughStorage, value {{.*}} : $Optional<Int>, init {{.*}} : $@convention(thin) (Optional<Int>, @inout any Storage<TestIndirectionThroughStorage>) -> (), set {{.*}} : $@callee_guaranteed (Optional<Int>) -> ()
// CHECK: assign_or_init [init] #TestIndirectionThroughStorage.name, self [[SELF]] : $TestIndirectionThroughStorage, value {{.*}} : $String, init {{.*}} : $@convention(thin) (@owned String, @inout any Storage<TestIndirectionThroughStorage>) -> (), set {{.*}} : $@callee_guaranteed (@owned String) -> ()
// CHECK: assign_or_init [init] #TestIndirectionThroughStorage.age, self [[SELF]] : $TestIndirectionThroughStorage, value {{.*}} : $Optional<Int>, init {{.*}} : $@convention(thin) (Optional<Int>, @inout any Storage<TestIndirectionThroughStorage>) -> (), set {{.*}} : $@callee_guaranteed (Optional<Int>) -> ()
// Explicit set:
// CHECK: [[STORAGE_SETTER:%.*]] = function_ref @$s23assign_or_init_lowering29TestIndirectionThroughStorageC7storageAA0H0_pAC1TAaEPRts_XPvs : $@convention(method) (@in any Storage<TestIndirectionThroughStorage>, @guaranteed TestIndirectionThroughStorage) -> ()
// CHECK-NEXT: {{.*}} = apply [[STORAGE_SETTER]]({{.*}}, %1) : $@convention(method) (@in any Storage<TestIndirectionThroughStorage>, @guaranteed TestIndirectionThroughStorage) -> ()
// CHECK-NEXT: {{.*}} = apply [[STORAGE_SETTER]]({{.*}}, [[SELF]]) : $@convention(method) (@in any Storage<TestIndirectionThroughStorage>, @guaranteed TestIndirectionThroughStorage) -> ()
init(storage: any Storage<TestIndirectionThroughStorage>) {
self.storage = storage
}
@@ -219,26 +221,28 @@ func test_default_inits() {
}
// CHECK-LABEL: sil private [ossa] @$s23assign_or_init_lowering18test_default_initsyyF5Test1L_VADycfC : $@convention(method) (@thin Test1.Type) -> Test1
// CHECK: [[SELF:%.*]] = mark_uninitialized [rootself] %1
// CHECK: [[DEFAULT:%.*]] = function_ref @$s23assign_or_init_lowering18test_default_initsyyF5Test1L_V1xSivpfi : $@convention(thin) () -> Int
// CHECK-NEXT: [[INIT_VAL:%.*]] = apply [[DEFAULT]]() : $@convention(thin) () -> Int
// CHECK-NEXT: [[SELF_REF:%.*]] = begin_access [modify] [static] %1 : $*Test1
// CHECK-NEXT: [[SELF_REF:%.*]] = begin_access [modify] [static] [[SELF]] : $*Test1
// CHECK: [[INIT_ACCESSOR:%.*]] = function_ref @$s23assign_or_init_lowering18test_default_initsyyF5Test1L_V1xSivi : $@convention(thin) (Int) -> @out Int
// CHECK: [[SETTER_REF:%.*]] = function_ref @$s23assign_or_init_lowering18test_default_initsyyF5Test1L_V1xSivs : $@convention(method) (Int, @inout Test1) -> ()
// CHECK-NEXT: [[SETTER:%.*]] = partial_apply [callee_guaranteed] [[SETTER_REF]]([[SELF_REF]]) : $@convention(method) (Int, @inout Test1) -> ()
// CHECK-NEXT: assign_or_init [init] #<abstract function>Test1.x, self %1 : $*Test1, value [[INIT_VAL]] : $Int, init [[INIT_ACCESSOR]] : $@convention(thin) (Int) -> @out Int, set [[SETTER]] : $@callee_guaranteed (Int) -> ()
// CHECK-NEXT: assign_or_init [init] #<abstract function>Test1.x, self %2 : $*Test1, value [[INIT_VAL]] : $Int, init [[INIT_ACCESSOR]] : $@convention(thin) (Int) -> @out Int, set [[SETTER]] : $@callee_guaranteed (Int) -> ()
// CHECK-NEXT: end_access [[SELF_REF]] : $*Test1
// CHECK-NEXT: destroy_value [[SETTER]] : $@callee_guaranteed (Int) -> ()
init() {
}
// CHECK-LABEL: sil private [ossa] @$s23assign_or_init_lowering18test_default_initsyyF5Test1L_V1xADSi_tcfC : $@convention(method) (Int, @thin Test1.Type) -> Test1
// CHECK: [[SELF:%.*]] = mark_uninitialized [rootself] %2
// CHECK: [[DEFAULT:%.*]] = function_ref @$s23assign_or_init_lowering18test_default_initsyyF5Test1L_V1xSivpfi : $@convention(thin) () -> Int
// CHECK-NEXT: [[INIT_VAL:%.*]] = apply [[DEFAULT]]() : $@convention(thin) () -> Int
// CHECK-NEXT: [[SELF_REF:%.*]] = begin_access [modify] [static] %2 : $*Test1
// CHECK-NEXT: [[SELF_REF:%.*]] = begin_access [modify] [static] [[SELF]] : $*Test1
// CHECK: [[INIT_ACCESSOR:%.*]] = function_ref @$s23assign_or_init_lowering18test_default_initsyyF5Test1L_V1xSivi : $@convention(thin) (Int) -> @out Int
// CHECK: [[SETTER_REF:%.*]] = function_ref @$s23assign_or_init_lowering18test_default_initsyyF5Test1L_V1xSivs : $@convention(method) (Int, @inout Test1) -> ()
// CHECK-NEXT: [[SETTER:%.*]] = partial_apply [callee_guaranteed] [[SETTER_REF]]([[SELF_REF]]) : $@convention(method) (Int, @inout Test1) -> ()
// CHECK-NEXT: assign_or_init [init] #<abstract function>Test1.x, self %2 : $*Test1, value [[INIT_VAL]] : $Int, init [[INIT_ACCESSOR]] : $@convention(thin) (Int) -> @out Int, set [[SETTER]] : $@callee_guaranteed (Int) -> ()
// CHECK-NEXT: assign_or_init [init] #<abstract function>Test1.x, self %3 : $*Test1, value [[INIT_VAL]] : $Int, init [[INIT_ACCESSOR]] : $@convention(thin) (Int) -> @out Int, set [[SETTER]] : $@callee_guaranteed (Int) -> ()
// CHECK-NEXT: end_access [[SELF_REF]] : $*Test1
// CHECK-NEXT: destroy_value [[SETTER]] : $@callee_guaranteed (Int) -> ()
//
@@ -263,6 +267,7 @@ func test_default_inits() {
var y: Int
// CHECK-LABEL: sil private [ossa] @$s23assign_or_init_lowering18test_default_initsyyF5Test2L_CADyxGycfc : $@convention(method) <T where T : Initializable> (@owned Test2<T>) -> @owned Test2<T>
// CHECK: [[SL:%.*]] = mark_uninitialized [rootself] %0
// CHECK: [[DEFAULT:%.*]] = function_ref @$s23assign_or_init_lowering18test_default_initsyyF5Test2L_C1xx_SStvpfi : $@convention(thin) <τ_0_0 where τ_0_0 : Initializable> () -> (@out τ_0_0, @owned String)
// CHECK-NEXT: [[T:%.*]] = alloc_stack $T
// CHECK-NEXT: [[STR:%.*]] = apply [[DEFAULT]]<T>([[T]]) : $@convention(thin) <τ_0_0 where τ_0_0 : Initializable> () -> (@out τ_0_0, @owned String)
@@ -274,9 +279,9 @@ func test_default_inits() {
// CHECK: [[INIT_ACCESSOR_REF:%.*]] = function_ref @$s23assign_or_init_lowering18test_default_initsyyF5Test2L_C1xx_SStvi : $@convention(thin) <τ_0_0 where τ_0_0 : Initializable> (@in τ_0_0, @owned String) -> @out (τ_0_0, String)
// CHECK-NEXT: [[INIT_ACCESSOR:%.*]] = partial_apply [callee_guaranteed] [[INIT_ACCESSOR_REF]]<T>() : $@convention(thin) <τ_0_0 where τ_0_0 : Initializable> (@in τ_0_0, @owned String) -> @out (τ_0_0, String)
// CHECK: [[SETTER_REF:%.*]] = function_ref @$s23assign_or_init_lowering18test_default_initsyyF5Test2L_C1xx_SStvs : $@convention(method) <τ_0_0 where τ_0_0 : Initializable> (@in τ_0_0, @owned String, @guaranteed Test2<τ_0_0>) -> ()
// CHECK-NEXT: [[SELF:%.*]] = copy_value %0 : $Test2<T>
// CHECK-NEXT: [[SELF:%.*]] = copy_value [[SL]] : $Test2<T>
// CHECK-NEXT: [[SETTER:%.*]] = partial_apply [callee_guaranteed] [[SETTER_REF]]<T>([[SELF]]) : $@convention(method) <τ_0_0 where τ_0_0 : Initializable> (@in τ_0_0, @owned String, @guaranteed Test2<τ_0_0>) -> ()
// CHECK-NEXT: assign_or_init [init] #<abstract function>Test2.x, self %0 : $Test2<T>, value [[NEW_VALUE]] : $*(T, String), init [[INIT_ACCESSOR]] : $@callee_guaranteed (@in T, @owned String) -> @out (T, String), set [[SETTER]] : $@callee_guaranteed (@in T, @owned String) -> ()
// CHECK-NEXT: assign_or_init [init] #<abstract function>Test2.x, self [[SL]] : $Test2<T>, value [[NEW_VALUE]] : $*(T, String), init [[INIT_ACCESSOR]] : $@callee_guaranteed (@in T, @owned String) -> @out (T, String), set [[SETTER]] : $@callee_guaranteed (@in T, @owned String) -> ()
// CHECK-NEXT: destroy_value [[SETTER]] : $@callee_guaranteed (@in T, @owned String) -> ()
// CHECK-NEXT: destroy_value [[INIT_ACCESSOR]] : $@callee_guaranteed (@in T, @owned String) -> @out (T, String)
// CHECK-NEXT: dealloc_stack [[NEW_VALUE]] : $*(T, String)
@@ -286,6 +291,7 @@ func test_default_inits() {
}
// CHECK-LABEL: sil private [ossa] @$s23assign_or_init_lowering18test_default_initsyyF5Test2L_C1x1yADyxGx_SSt_Sitcfc : $@convention(method) <T where T : Initializable> (@in T, @owned String, Int, @owned Test2<T>) -> @owned Test2<T>
// CHECK: [[SL:%.*]] = mark_uninitialized [rootself] %3
// CHECK: [[DEFAULT:%.*]] = function_ref @$s23assign_or_init_lowering18test_default_initsyyF5Test2L_C1xx_SStvpfi : $@convention(thin) <τ_0_0 where τ_0_0 : Initializable> () -> (@out τ_0_0, @owned String)
// CHECK-NEXT: [[T:%.*]] = alloc_stack $T
// CHECK-NEXT: [[STR:%.*]] = apply [[DEFAULT]]<T>([[T]]) : $@convention(thin) <τ_0_0 where τ_0_0 : Initializable> () -> (@out τ_0_0, @owned String)
@@ -297,17 +303,17 @@ func test_default_inits() {
// CHECK: [[INIT_ACCESSOR_REF:%.*]] = function_ref @$s23assign_or_init_lowering18test_default_initsyyF5Test2L_C1xx_SStvi : $@convention(thin) <τ_0_0 where τ_0_0 : Initializable> (@in τ_0_0, @owned String) -> @out (τ_0_0, String)
// CHECK-NEXT: [[INIT_ACCESSOR:%.*]] = partial_apply [callee_guaranteed] [[INIT_ACCESSOR_REF]]<T>() : $@convention(thin) <τ_0_0 where τ_0_0 : Initializable> (@in τ_0_0, @owned String) -> @out (τ_0_0, String)
// CHECK: [[SETTER_REF:%.*]] = function_ref @$s23assign_or_init_lowering18test_default_initsyyF5Test2L_C1xx_SStvs : $@convention(method) <τ_0_0 where τ_0_0 : Initializable> (@in τ_0_0, @owned String, @guaranteed Test2<τ_0_0>) -> ()
// CHECK-NEXT: [[SELF:%.*]] = copy_value %3 : $Test2<T>
// CHECK-NEXT: [[SELF:%.*]] = copy_value [[SL]] : $Test2<T>
// CHECK-NEXT: [[SETTER:%.*]] = partial_apply [callee_guaranteed] [[SETTER_REF]]<T>([[SELF]]) : $@convention(method) <τ_0_0 where τ_0_0 : Initializable> (@in τ_0_0, @owned String, @guaranteed Test2<τ_0_0>) -> ()
// CHECK-NEXT: assign_or_init [init] #<abstract function>Test2.x, self %3 : $Test2<T>, value [[NEW_VALUE]] : $*(T, String), init [[INIT_ACCESSOR]] : $@callee_guaranteed (@in T, @owned String) -> @out (T, String), set [[SETTER]] : $@callee_guaranteed (@in T, @owned String) -> ()
// CHECK-NEXT: assign_or_init [init] #<abstract function>Test2.x, self [[SL]] : $Test2<T>, value [[NEW_VALUE]] : $*(T, String), init [[INIT_ACCESSOR]] : $@callee_guaranteed (@in T, @owned String) -> @out (T, String), set [[SETTER]] : $@callee_guaranteed (@in T, @owned String) -> ()
// CHECK-NEXT: destroy_value [[SETTER]] : $@callee_guaranteed (@in T, @owned String) -> ()
// CHECK-NEXT: destroy_value [[INIT_ACCESSOR]] : $@callee_guaranteed (@in T, @owned String) -> @out (T, String)
// CHECK-NEXT: dealloc_stack [[NEW_VALUE]] : $*(T, String)
// CHECK-NEXT: dealloc_stack [[T]] : $*T
//
// CHECK: assign_or_init [init] [assign=0] #<abstract function>Test2.x, self %3 : $Test2<T>, value {{.*}} : $*(T, String), init {{.*}} : $@callee_guaranteed (@in T, @owned String) -> @out (T, String), set {{.*}} : $@callee_guaranteed (@in T, @owned String) -> ()
// CHECK: assign_or_init [init] [assign=0] #<abstract function>Test2.x, self [[SL]] : $Test2<T>, value {{.*}} : $*(T, String), init {{.*}} : $@callee_guaranteed (@in T, @owned String) -> @out (T, String), set {{.*}} : $@callee_guaranteed (@in T, @owned String) -> ()
// CHECK: assign %2 to [init] [[Y_REF:%.*]] : $*Int
// CHECK: assign_or_init [set] #<abstract function>Test2.x, self %3 : $Test2<T>, value {{.*}} : $*(T, String), init {{.*}} : $@callee_guaranteed (@in T, @owned String) -> @out (T, String), set {{.*}} : $@callee_guaranteed (@in T, @owned String) -> ()
// CHECK: assign_or_init [set] #<abstract function>Test2.x, self [[SL]] : $Test2<T>, value {{.*}} : $*(T, String), init {{.*}} : $@callee_guaranteed (@in T, @owned String) -> @out (T, String), set {{.*}} : $@callee_guaranteed (@in T, @owned String) -> ()
init(x: (T, String), y: Int) {
self.x = x
self.y = y
@@ -364,12 +370,13 @@ func test_default_inits() {
}
// CHECK-LABEL: sil private [ossa] @$s23assign_or_init_lowering18test_default_initsyyF5Test4L_CADycfc : $@convention(method) (@owned Test4) -> @owned Test4
// CHECK: [[SL:%.*]] = mark_uninitialized [rootself] %0
// CHECK: [[X_DEFAULT:%.*]] = function_ref @$s23assign_or_init_lowering18test_default_initsyyF5Test4L_C1xSivpfi : $@convention(thin) () -> Int
// CHECK-NEXT: [[X_VALUE:%.*]] = apply [[X_DEFAULT]]() : $@convention(thin) () -> Int
// CHECK: assign_or_init [init] #<abstract function>Test4.x, self %0 : $Test4, value [[X_VALUE]] : $Int, init {{.*}} : $@convention(thin) (Int) -> @out Int, set undef : $@convention(thin) (Int) -> @out Int
// CHECK: assign_or_init [init] #<abstract function>Test4.x, self [[SL]] : $Test4, value [[X_VALUE]] : $Int, init {{.*}} : $@convention(thin) (Int) -> @out Int, set undef : $@convention(thin) (Int) -> @out Int
// CHECK: [[Y_DEFAULT:%.*]] = function_ref @$s23assign_or_init_lowering18test_default_initsyyF5Test4L_C1ySSvpfi : $@convention(thin) () -> @owned String
// CHECK-NEXT: [[Y_VALUE:%.*]] = apply [[Y_DEFAULT]]() : $@convention(thin) () -> @owned String
// CHECK: assign_or_init [init] #<abstract function>Test4.y, self %0 : $Test4, value [[Y_VALUE]] : $String, init {{.*}} : $@convention(thin) (@owned String) -> @out String, set undef : $@convention(thin) (@owned String) -> @out String
// CHECK: assign_or_init [init] #<abstract function>Test4.y, self [[SL]] : $Test4, value [[Y_VALUE]] : $String, init {{.*}} : $@convention(thin) (@owned String) -> @out String, set undef : $@convention(thin) (@owned String) -> @out String
}
}
@@ -386,7 +393,8 @@ func test_handling_of_superclass_properties() {
class Person : Entity {
// CHECK-LABEL: sil private [ossa] @$s23assign_or_init_lowering38test_handling_of_superclass_propertiesyyF6PersonL_C3ageADSi_tcfc : $@convention(method) (Int, @owned Person) -> @owned Person
// CHECK: [[SELF:%.*]] = load [copy] %2 : $*Person
// CHECK: [[SL:%.*]] = mark_uninitialized [derivedself] %2
// CHECK: [[SELF:%.*]] = load [copy] [[SL]] : $*Person
// CHECK-NEXT: [[SELF_AS_ENTITY:%.*]] = upcast [[SELF]] : $Person to $Entity
// CHECK-NEXT: [[AGE_SETTER:%.*]] = class_method [[SELF_AS_ENTITY]] : $Entity, #<abstract function>Entity.age!setter : (Entity) -> (Int) -> (), $@convention(method) (Int, @guaranteed Entity) -> ()
// CHECK-NEXT: {{.*}} = apply [[AGE_SETTER]](%0, [[SELF_AS_ENTITY]]) : $@convention(method) (Int, @guaranteed Entity) -> ()
@@ -417,9 +425,9 @@ func test_handling_of_nonmutating_set() {
// CHECK-LABEL: sil private [ossa] @$s23assign_or_init_lowering32test_handling_of_nonmutating_setyyF4TestL_V5countADSi_tcfC : $@convention(method) (Int, @thin Test.Type) -> Test
// CHECK: [[INIT_VALUE:%.*]] = function_ref @$s23assign_or_init_lowering32test_handling_of_nonmutating_setyyF4TestL_V5countSivpfi : $@convention(thin) () -> Int
// CHECK-NEXT: [[VALUE:%.*]] = apply [[INIT_VALUE]]() : $@convention(thin) () -> Int
// CHECK: assign_or_init [init] #<abstract function>Test.count, self %2 : $*Test, value [[VALUE]] : $Int, init {{.*}} : $@convention(thin) (Int) -> @out Int, set {{.*}} : $@callee_guaranteed (Int) -> ()
// CHECK: assign_or_init [set] #<abstract function>Test.count, self %2 : $*Test, value %0 : $Int, init {{.*}} : $@convention(thin) (Int) -> @out Int, set {{.*}} : $@callee_guaranteed (Int) -> ()
// CHECK: assign_or_init [set] #<abstract function>Test.count, self %2 : $*Test, value [[ZERO:%.*]] : $Int, init {{.*}} : $@convention(thin) (Int) -> @out Int, set {{.*}} : $@callee_guaranteed (Int) -> ()
// CHECK: assign_or_init [init] #<abstract function>Test.count, self %3 : $*Test, value [[VALUE]] : $Int, init {{.*}} : $@convention(thin) (Int) -> @out Int, set {{.*}} : $@callee_guaranteed (Int) -> ()
// CHECK: assign_or_init [set] #<abstract function>Test.count, self %3 : $*Test, value %0 : $Int, init {{.*}} : $@convention(thin) (Int) -> @out Int, set {{.*}} : $@callee_guaranteed (Int) -> ()
// CHECK: assign_or_init [set] #<abstract function>Test.count, self %3 : $*Test, value [[ZERO:%.*]] : $Int, init {{.*}} : $@convention(thin) (Int) -> @out Int, set {{.*}} : $@callee_guaranteed (Int) -> ()
init(count: Int) {
self.count = count
self.count = 0

View File

@@ -28,18 +28,19 @@ public class Test {
// CHECK-LABEL: sil [ossa] @$s14init_accessors4TestCACycfc : $@convention(method) (@owned Test) -> @owned Test
//
// CHECK: [[MU:%.*]] = mark_uninitialized [rootself] %0 : $Test
// CHECK: [[DEFAULT_VALUE_INIT:%.*]] = function_ref @$s14init_accessors4TestC5stateAC5StateOvpfi : $@convention(thin) () -> @out Test.State
// CHECK-NEXT: [[DEFAULT_VALUE_SLOT:%.*]] = alloc_stack $Test.State
// CHECK-NEXT: {{.*}} = apply [[DEFAULT_VALUE_INIT]]([[DEFAULT_VALUE_SLOT]]) : $@convention(thin) () -> @out Test.State
// CHECK-NEXT: [[DEFAULT_VALUE:%.*]] = load [take] [[DEFAULT_VALUE_SLOT]] : $*Test.State
// CHECK: [[NEW_VALUE:%.*]] = alloc_stack $Test.State
// CHECK-NEXT: store [[DEFAULT_VALUE]] to [init] [[NEW_VALUE]] : $*Test.State
// CHECK: assign_or_init [init] #Test.state, self %0 : $Test, value [[NEW_VALUE]] : $*Test.State, init {{.*}} : $@convention(thin) (@in Test.State) -> @out Test.State, set {{.*}} : $@callee_guaranteed (@in Test.State) -> ()
// CHECK: assign_or_init [init] #Test.state, self [[MU]] : $Test, value [[NEW_VALUE]] : $*Test.State, init {{.*}} : $@convention(thin) (@in Test.State) -> @out Test.State, set {{.*}} : $@callee_guaranteed (@in Test.State) -> ()
//
// CHECK: [[START_STATE:%.*]] = enum $Test.State, #Test.State.start!enumelt
// CHECK-NEXT: [[NEW_VALUE:%.*]] = alloc_stack $Test.State
// CHECK-NEXT: store [[START_STATE]] to [trivial] [[NEW_VALUE]] : $*Test.State
// CHECK: assign_or_init [set] #Test.state, self %0 : $Test, value [[NEW_VALUE]] : $*Test.State, init {{.*}} : $@convention(thin) (@in Test.State) -> @out Test.State, set {{.*}} : $@callee_guaranteed (@in Test.State) -> ()
// CHECK: assign_or_init [set] #Test.state, self [[MU]] : $Test, value [[NEW_VALUE]] : $*Test.State, init {{.*}} : $@convention(thin) (@in Test.State) -> @out Test.State, set {{.*}} : $@callee_guaranteed (@in Test.State) -> ()
public init() {
state = .start
}

View File

@@ -80,9 +80,12 @@ _ = Z().capturesSelf()
// CHECK: apply [[F]](%{{.+}}, %{{.+}}) : $@convention(method) (Int, @thick C.Type) -> @owned C
// CHECK: [[Z:%.*]] = alloc_ref $Z
// CHECK: [[C:%.*]] = upcast [[Z]]
// CHECK: [[EI:%.*]] = end_init_let_ref [[C]]
// CHECK: [[DC:%.*]] = unchecked_ref_cast [[EI]]
// CHECK: function_ref inline_self.Z.capturesSelf() -> Self
// CHECK: [[F:%[0-9]+]] = function_ref @$s11inline_self1ZC12capturesSelfACXDyF : $@convention(method) (@guaranteed Z) -> @owned Z
// CHECK: apply [[F]]([[Z]]) : $@convention(method) (@guaranteed Z) -> @owned
// CHECK: apply [[F]]([[DC]]) : $@convention(method) (@guaranteed Z) -> @owned
// CHECK: return
// CHECK-LABEL: sil hidden @$s11inline_self1ZC16callCapturesSelfACXDyF : $@convention(method)

View File

@@ -0,0 +1,256 @@
// RUN: %target-sil-opt %s -let-property-lowering | %FileCheck %s
// REQUIRES: swift_in_compiler
sil_stage raw
import Builtin
import Swift
import SwiftShims
class C {
@_hasStorage let a: Int
}
class B {
}
class D : B {
@_hasStorage let a: Int
}
class E {
@_hasStorage let a: Int
@_hasStorage let b: Int
@_hasStorage var c: Int
}
sil @unknown_func : $@convention(thin) (@guaranteed C) -> ()
// CHECK-LABEL: sil [ossa] @test_init_store :
// CHECK: ref_element_addr %3
// CHECK-NEXT: store
// CHECK-NEXT: end_borrow
// CHECK-NEXT: [[EI:%.*]] = end_init_let_ref %2
// CHECK-NEXT: [[B:%.*]] = begin_borrow [[EI]]
// CHECK-NEXT: [[A:%.*]] = ref_element_addr [immutable] [[B]]
// CHECK-NEXT: load [trivial] [[A]]
// CHECK: return [[EI]]
// CHECK: } // end sil function 'test_init_store'
sil [ossa] @test_init_store : $@convention(thin) (@owned C, Int) -> @owned C {
bb0(%0 : @owned $C, %1 : $Int):
%2 = mark_uninitialized [rootself] %0 : $C
%3 = begin_borrow %2 : $C
%4 = ref_element_addr %3 : $C, #C.a
store %1 to [trivial] %4 : $*Int
end_borrow %3 : $C
%7 = begin_borrow %2 : $C
%8 = ref_element_addr %7 : $C, #C.a
%9 = load [trivial] %8 : $*Int
end_borrow %7 : $C
return %2 : $C
}
// CHECK-LABEL: sil [ossa] @test_let_read :
// CHECK: ref_element_addr [immutable] %0
// CHECK: } // end sil function 'test_let_read'
sil [ossa] @test_let_read : $@convention(thin) (@guaranteed C) -> Int {
bb0(%0 : @guaranteed $C):
%1 = ref_element_addr %0 : $C, #C.a
%2 = load [trivial] %1 : $*Int
return %2 : $Int
}
// CHECK-LABEL: sil [ossa] @test_init_assign :
// CHECK: ref_element_addr %3
// CHECK-NEXT: assign
// CHECK-NEXT: end_borrow
// CHECK-NEXT: [[EI:%.*]] = end_init_let_ref %2
// CHECK-NEXT: [[B:%.*]] = begin_borrow [[EI]]
// CHECK-NEXT: [[A:%.*]] = ref_element_addr [immutable] [[B]]
// CHECK-NEXT: load [trivial] [[A]]
// CHECK: return [[EI]]
// CHECK: } // end sil function 'test_init_assign'
sil [ossa] @test_init_assign : $@convention(thin) (@owned C, Int) -> @owned C {
bb0(%0 : @owned $C, %1 : $Int):
%2 = mark_uninitialized [rootself] %0 : $C
%3 = begin_borrow %2 : $C
%4 = ref_element_addr %3 : $C, #C.a
assign %1 to [init] %4 : $*Int
end_borrow %3 : $C
%7 = begin_borrow %2 : $C
%8 = ref_element_addr %7 : $C, #C.a
%9 = load [trivial] %8 : $*Int
end_borrow %7 : $C
return %2 : $C
}
// CHECK-LABEL: sil [ossa] @test_init_copy_addr :
// CHECK: ref_element_addr %3
// CHECK-NEXT: copy_addr
// CHECK-NEXT: end_borrow
// CHECK-NEXT: [[EI:%.*]] = end_init_let_ref %2
// CHECK-NEXT: [[B:%.*]] = begin_borrow [[EI]]
// CHECK-NEXT: [[A:%.*]] = ref_element_addr [immutable] [[B]]
// CHECK-NEXT: load [trivial] [[A]]
// CHECK: return [[EI]]
// CHECK: } // end sil function 'test_init_copy_addr'
sil [ossa] @test_init_copy_addr : $@convention(thin) (@owned C, @in Int) -> @owned C {
bb0(%0 : @owned $C, %1 : $*Int):
%2 = mark_uninitialized [rootself] %0 : $C
%3 = begin_borrow %2 : $C
%4 = ref_element_addr %3 : $C, #C.a
copy_addr %1 to [init] %4 : $*Int
end_borrow %3 : $C
%7 = begin_borrow %2 : $C
%8 = ref_element_addr %7 : $C, #C.a
%9 = load [trivial] %8 : $*Int
end_borrow %7 : $C
return %2 : $C
}
// CHECK-LABEL: sil [ossa] @test_empty :
// CHECK: %1 = mark_uninitialized [rootself] %0
// CHECK-NEXT: %2 = end_init_let_ref %1
// CHECK: return %2
// CHECK: } // end sil function 'test_empty'
sil [ossa] @test_empty : $@convention(thin) (@owned C) -> @owned C {
bb0(%0 : @owned $C):
%1 = mark_uninitialized [rootself] %0 : $C
return %1 : $C
}
// CHECK-LABEL: sil [ossa] @test_multiple_fields :
// CHECK: ref_element_addr {{.*}}, #E.a
// CHECK: ref_element_addr {{.*}}, #E.b
// CHECK: end_borrow
// CHECK-NEXT: [[EI:%.*]] = end_init_let_ref
// CHECK-NEXT: begin_borrow [[EI]]
// CHECK: ref_element_addr {{.*}}, #E.c
// CHECK: return [[EI]]
// CHECK: } // end sil function 'test_multiple_fields'
sil [ossa] @test_multiple_fields : $@convention(thin) (@owned E, Int) -> @owned E {
bb0(%0 : @owned $E, %1 : $Int):
%2 = mark_uninitialized [rootself] %0 : $E
%3 = begin_borrow %2 : $E
%4 = ref_element_addr %3 : $E, #E.a
store %1 to [trivial] %4 : $*Int
end_borrow %3 : $E
%6 = begin_borrow %2 : $E
%7 = ref_element_addr %6 : $E, #E.b
store %1 to [trivial] %7 : $*Int
end_borrow %6 : $E
%10 = begin_borrow %2 : $E
%11 = ref_element_addr %10 : $E, #E.c
store %1 to [trivial] %11 : $*Int
end_borrow %10 : $E
return %2 : $E
}
// CHECK-LABEL: sil [ossa] @test_derived :
// CHECK-NOT: end_init_let_ref
// CHECK: [[B:%.*]] = load_borrow
// CHECK-NEXT: ref_element_addr [[B]]
// CHECK-NOT: end_init_let_ref
// CHECK: } // end sil function 'test_derived'
sil [ossa] @test_derived : $@convention(thin) (@owned D, Int) -> @owned D {
bb0(%0 : @owned $D, %1 : $Int):
%2 = alloc_stack $D
%3 = mark_uninitialized [derivedself] %2 : $*D
store %0 to [init] %3 : $*D
%5 = load_borrow %3 : $*D
%6 = ref_element_addr %5 : $D, #D.a
assign %1 to [init] %6 : $*Int
end_borrow %5 : $D
%9 = load [take] %2 : $*D
dealloc_stack %2 : $*D
return %9 : $D
}
// CHECK-LABEL: sil [ossa] @test_multi_block1 :
// CHECK: bb1:
// CHECK: end_borrow
// CHECK-NEXT: [[EI1:%.*]] = end_init_let_ref %2
// CHECK-NEXT: br bb3([[EI1]] : $C)
// CHECK: bb2:
// CHECK: end_borrow
// CHECK-NEXT: [[EI2:%.*]] = end_init_let_ref %2
// CHECK-NEXT: br bb3([[EI2]] : $C)
// CHECK: bb3([[P:%.*]] : @owned $C):
// CHECK-NEXT: return [[P]]
// CHECK: } // end sil function 'test_multi_block1'
sil [ossa] @test_multi_block1 : $@convention(thin) (@owned C, Int) -> @owned C {
bb0(%0 : @owned $C, %1 : $Int):
%2 = mark_uninitialized [rootself] %0 : $C
cond_br undef, bb1, bb2
bb1:
%3 = begin_borrow %2 : $C
%4 = ref_element_addr %3 : $C, #C.a
store %1 to [trivial] %4 : $*Int
end_borrow %3 : $C
br bb3
bb2:
%7 = begin_borrow %2 : $C
%8 = ref_element_addr %7 : $C, #C.a
store %1 to [trivial] %8 : $*Int
end_borrow %7 : $C
br bb3
bb3:
return %2 : $C
}
// CHECK-LABEL: sil [ossa] @test_multi_block2 :
// CHECK: bb1:
// CHECK: end_borrow
// CHECK-NEXT: end_init_let_ref %2
// CHECK: bb2:
// CHECK-NEXT: end_init_let_ref %2
// CHECK-NEXT: unreachable
// CHECK: bb3:
// CHECK: } // end sil function 'test_multi_block2'
sil [ossa] @test_multi_block2 : $@convention(thin) (@owned C, Int) -> @owned C {
bb0(%0 : @owned $C, %1 : $Int):
%2 = mark_uninitialized [rootself] %0 : $C
cond_br undef, bb1, bb2
bb1:
%3 = begin_borrow %2 : $C
%4 = ref_element_addr %3 : $C, #C.a
store %1 to [trivial] %4 : $*Int
end_borrow %3 : $C
br bb3
bb2:
unreachable
bb3:
return %2 : $C
}
// CHECK-LABEL: sil [ossa] @test_partial_deinitialization :
// CHECK: bb1:
// CHECK: end_borrow
// CHECK-NEXT: end_init_let_ref %2
// CHECK: bb2:
// CHECK: end_borrow
// CHECK-NEXT: end_init_let_ref %2
// CHECK: bb3:
// CHECK: } // end sil function 'test_partial_deinitialization'
sil [ossa] @test_partial_deinitialization : $@convention(thin) (@owned C, Int) -> @owned C {
bb0(%0 : @owned $C, %1 : $Int):
%2 = mark_uninitialized [rootself] %0 : $C
cond_br undef, bb1, bb2
bb1:
%3 = begin_borrow %2 : $C
%4 = ref_element_addr %3 : $C, #C.a
store %1 to [trivial] %4 : $*Int
end_borrow %3 : $C
br bb3
bb2:
%7 = begin_borrow %2 : $C
%8 = ref_element_addr %7 : $C, #C.a
%9 = begin_access [deinit] [static] %8 : $*Int
destroy_addr %9 : $*Int
end_access %9 : $*Int
end_borrow %7 : $C
unreachable
bb3:
return %2 : $C
}

View File

@@ -0,0 +1,193 @@
// RUN: %target-swift-frontend -emit-sil -module-name=test %s | %FileCheck %s
// REQUIRES: swift_in_compiler
// CHECK-LABEL: sil hidden @$s4test6testitySiAA1CCF :
// CHECK: ref_element_addr [immutable] %0 : $C, #C.a
// CHECK: } // end sil function '$s4test6testitySiAA1CCF'
@discardableResult
func testit(_ c: C) -> Int {
return c.a
}
class C {
final let a: Int
final var b: Int
// CHECK-LABEL: sil hidden @$s4test1CCACycfc :
// CHECK: ref_element_addr %0 : $C, #C.a
// CHECK: store
// CHECK: [[EI:%.*]] = end_init_let_ref %0
// CHECK: ref_element_addr [[EI]] : $C, #C.b
// CHECK: store
// CHECK: [[A:%.*]] = ref_element_addr [immutable] [[EI]] : $C, #C.a
// CHECK: [[L:%.*]] = load [[A]]
// CHECK: apply {{.*}}([[L]])
// CHECK: } // end sil function '$s4test1CCACycfc'
init() {
self.a = 1
self.b = 2
takeint(self.a)
}
// CHECK-LABEL: sil hidden @$s4test1CC1bACSgSb_tcfc :
// CHECK: bb1:
// CHECK: ref_element_addr %1 : $C, #C.a
// CHECK: store
// CHECK: [[EI1:%.*]] = end_init_let_ref %1
// CHECK: ref_element_addr [[EI1]] : $C, #C.b
// CHECK: store
// CHECK: apply {{.*}}([[EI1]])
// CHECK: br bb3([[EI1]] : $C)
// CHECK: bb2:
// CHECK: ref_element_addr %1 : $C, #C.a
// CHECK: store
// CHECK: [[EI2:%.*]] = end_init_let_ref %1
// CHECK: ref_element_addr [[EI2]] : $C, #C.b
// CHECK: store
// CHECK: apply {{.*}}([[EI2]])
// CHECK: br bb3([[EI2]] : $C)
// CHECK: bb3([[P:%.*]] : $C):
// CHECK: [[O:%.*]] = enum $Optional<C>, #Optional.some!enumelt, [[P]]
// CHECK: return [[O]]
// CHECK: } // end sil function '$s4test1CC1bACSgSb_tcfc'
init?(b: Bool) {
if b {
self.a = 1
self.b = 2
testit(self)
} else {
self.a = 3
self.b = 4
testit(self)
}
}
// CHECK-LABEL: sil hidden @$s4test1CC1cACSb_tcfc :
// CHECK: [[A:%.*]] = ref_element_addr %1 : $C, #C.a
// CHECK: store {{.*}} to [[A]] : $*Int
// CHECK: [[EI:%.*]] = end_init_let_ref %1
// CHECK: bb1:
// CHEKC: ref_element_addr [[EI]] : $C, #C.b
// CHECK: return [[EI]]
// CHECK: } // end sil function '$s4test1CC1cACSb_tcfc'
init(c: Bool) {
self.a = 1
repeat {
self.b = 2
} while pred()
}
// CHECK-LABEL: sil hidden @$s4test1CC1dACSgSb_tcfc :
// CHECK: ref_element_addr %1 : $C, #C.a
// CHECK-NEXT: store
// CHECK: ref_element_addr %1 : $C, #C.a
// CHECK-NEXT: begin_access [deinit]
// CHECK: end_access
// CHECK: end_init_let_ref %1
// CHECK: } // end sil function '$s4test1CC1dACSgSb_tcfc'
init?(d: Bool) {
self.a = 1
return nil
}
// CHECK-LABEL: sil hidden @$s4test1CC1eACSgSb_tcfc :
// CHECK: ref_element_addr %1 : $C, #C.a
// CHECK: [[EI:%.*]] = end_init_let_ref %1
// CHECK: ref_element_addr [[EI]] : $C, #C.b
// CHECK: apply {{.*}}([[EI]])
// CHECK: } // end sil function '$s4test1CC1eACSgSb_tcfc'
init?(e: Bool) {
self.a = 1
self.b = 2
testit(self)
return nil
}
// CHECK-LABEL: sil hidden @$s4test1CC1fACSb_tKcfc :
// CHECK: ref_element_addr %1 : $C, #C.a
// CHECK-NEXT: store
// CHECK: ref_element_addr %1 : $C, #C.a
// CHECK-NEXT: begin_access [deinit]
// CHECK: end_access
// CHECK: end_init_let_ref %1
// CHECK: } // end sil function '$s4test1CC1fACSb_tKcfc'
init(f: Bool) throws {
self.a = 1
throw E()
}
// CHECK-LABEL: sil hidden @$s4test1CC1gACSb_tKcfc :
// CHECK: ref_element_addr %1 : $C, #C.a
// CHECK: [[EI:%.*]] = end_init_let_ref %1
// CHECK: ref_element_addr [[EI]] : $C, #C.b
// CHECK: apply {{.*}}([[EI]])
// CHECK: } // end sil function '$s4test1CC1gACSb_tKcfc'
init(g: Bool) throws {
self.a = 1
self.b = 2
testit(self)
throw E()
}
// CHECK-LABEL: sil hidden @$s4test1CC1hACSgSb_tcfc :
// CHECK: bb1:
// CHECK: [[EI:%.*]] = end_init_let_ref %1
// CHECK: enum {{.*}} #Optional.none
// CHECK: bb2:
// CHECK: [[EI:%.*]] = end_init_let_ref %1
// CHECK: enum {{.*}} #Optional.some!enumelt, [[EI]]
// CHECK: } // end sil function '$s4test1CC1hACSgSb_tcfc'
init?(h: Bool) {
self.a = 1
if h {
return nil
}
self.b = 2
}
}
class X {
final let c: C
// CHECK-LABEL: sil hidden @$s4test1XCyAcA1CCcfc :
// CHECK: ref_element_addr %1 : $X, #X.c
// CHECK: [[EI:%.*]] = end_init_let_ref %1
// CHECK: return [[EI]]
// CHECK: } // end sil function '$s4test1XCyAcA1CCcfc'
init(_ c: C) {
self.c = c
}
// CHECK-LABEL: sil hidden @$s4test1XCfd :
// CHECK: ref_element_addr %0 : $X, #X.c
// CHECK: ref_element_addr %0 : $X, #X.c
// CHECK: } // end sil function '$s4test1XCfd'
deinit {
testit(c)
}
}
class D : C {
final let c: Int
// CHECK-LABEL: sil hidden @$s4test1DCACycfc :
// CHECK-NOT: end_init_let_ref
// CHECK: ref_element_addr %0 : $D, #D.c
// CHECK-NOT: end_init_let_ref
// CHECK: } // end sil function '$s4test1DCACycfc'
override init() {
self.c = 27
super.init()
}
}
func takeint(_ i: Int) {
}
func pred() -> Bool {
return true
}
struct E : Error {}

View File

@@ -10,7 +10,7 @@
// Check that it doesn't crash with properties in ObjC extensions
// CHECK-LABEL: sil @$s4test0A13ObjcInterfaceySiSo0bC0CF
// CHECK: ref_element_addr %0 : $ObjcInterface, #ObjcInterface.i
// CHECK: ref_element_addr [immutable] %0 : $ObjcInterface, #ObjcInterface.i
// CHECK: } // end sil function '$s4test0A13ObjcInterfaceySiSo0bC0CF'
public func testObjcInterface(_ x: ObjcInterface) -> Int {
return x.i

View File

@@ -12,11 +12,12 @@ func barrier()
// CHECK-LABEL: sil {{.*}} [lexical_lifetimes] @funky : {{.*}} {
// CHECK: [[INSTANCE:%[^,]+]] = alloc_ref $C
// CHECK: [[EI:%.*]] = end_init_let_ref [[INSTANCE]]
// CHECK: [[BORROW:%[^,]+]] = function_ref @borrow
// CHECK: apply [[BORROW]]([[INSTANCE]])
// CHECK: apply [[BORROW]]([[EI]])
// CHECK: [[BARRIER:%[^,]+]] = function_ref @barrier
// CHECK: apply [[BARRIER]]()
// CHECK: strong_release [[INSTANCE]]
// CHECK: strong_release [[EI]]
// CHECK-LABEL: } // end sil function 'funky'
@_silgen_name("funky")
@_lexicalLifetimes

View File

@@ -24,7 +24,8 @@ struct ListEntry<T> : ~Copyable {
}
// CHECK-LABEL: sil private [ossa] @boxInit : $@convention(method) <T> (@in _Node<T>, @owned _Box<T>) -> @owned _Box<T> {
// CHECK: bb0([[INPUT:%.*]] : $*_Node<T>, [[SELF:%.*]] : @owned
// CHECK: bb0([[INPUT:%.*]] : $*_Node<T>, %1 : @owned
// CHECK: [[SELF:%.*]] = mark_uninitialized [rootself] %1
// CHECK: [[BORROW_SELF:%.*]] = begin_borrow [[SELF]]
// CHECK: [[REF:%.*]] = ref_element_addr [[BORROW_SELF]]
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [dynamic] [[REF]]

View File

@@ -4,6 +4,8 @@
// A test that makes sure end to end in a copyable class containing a
// non-copyable type, in the init, we only have a single destroy_addr.
// REQUIRES: swift_in_compiler
public struct MO: ~Copyable {
var x: Int8 = 0
deinit { print("destroyed MO") }
@@ -15,15 +17,16 @@ public class MOHaver {
// CHECK-LABEL: sil hidden @$s028moveonly_class_inits_end_to_D07MOHaverCACycfc : $@convention(method) (@owned MOHaver) -> @owned MOHaver {
// CHECK: bb0([[ARG:%.*]] :
// CHECK-NEXT: debug_value [[ARG]]
// CHECK-NEXT: [[EI:%.*]] = end_init_let_ref [[ARG]]
// CHECK-NEXT: [[META:%.*]] = metatype
// CHECK-NEXT: function_ref MO.init()
// CHECK-NEXT: [[FUNC:%.*]] = function_ref @$s028moveonly_class_inits_end_to_D02MOVACycfC :
// CHECK-NEXT: [[RESULT:%.*]] = apply [[FUNC]]([[META]])
// CHECK-NEXT: [[REF:%.*]] = ref_element_addr [[ARG]]
// CHECK-NEXT: [[REF:%.*]] = ref_element_addr [[EI]]
// CHECK-NEXT: [[REF_ACCESS:%.*]] = begin_access [modify] [dynamic] [[REF]]
// CHECK-NEXT: store [[RESULT]] to [[REF_ACCESS]]
// CHECK-NEXT: end_access [[REF_ACCESS]]
// CHECK-NEXT: return [[ARG]]
// CHECK-NEXT: return [[EI]]
// CHECK-NEXT: } // end sil function '$s028moveonly_class_inits_end_to_D07MOHaverCACycfc'
init() {
self.mo = MO()

View File

@@ -0,0 +1,27 @@
// RUN: %target-swift-frontend -parse-as-library -module-name test %s -O -emit-sil | %FileCheck %s
// REQUIRES: swift_in_compiler
public final class C {
let i: Int
init(i: Int) {
self.i = i
}
}
// CHECK-LABEL: sil @$s4test0A8LetField_1fSi_SitAA1CC_yyXEtF :
// CHECK: [[A:%.*]] = ref_element_addr [immutable] %0 : $C, #C.i
// CHECK: [[L:%.*]] = load [[A]]
// CHECK: apply
// CHECK-NOT: load
// CHECK: tuple ([[L]] : $Int, [[L]] : $Int)
// CHECK: } // end sil function '$s4test0A8LetField_1fSi_SitAA1CC_yyXEtF'
public func testLetField(_ c: C, f: () -> ()) -> (Int, Int) {
let a = c.i
f()
let b = c.i
return (a, b)
}

View File

@@ -24,7 +24,8 @@ extension P {
final class C: P {}
// CHECK-LABEL: sil @$s32sil_combine_concrete_existential14testReturnSelfAA1P_pyF : $@convention(thin) () -> @owned any P {
// CHECK: [[E1:%.*]] = init_existential_ref %0 : $C : $C, $any P
// CHECK: [[EI:%.*]] = end_init_let_ref %0
// CHECK: [[E1:%.*]] = init_existential_ref [[EI]] : $C : $C, $any P
// CHECK: [[O1:%.*]] = open_existential_ref [[E1]] : $any P to $@opened("{{.*}}", any P) Self
// CHECK: [[F1:%.*]] = function_ref @$s32sil_combine_concrete_existential1PPAAE10returnSelfxyF : $@convention(method) <τ_0_0 where τ_0_0 : P> (@guaranteed τ_0_0) -> @owned τ_0_0
// CHECK: [[C1:%.*]] = apply [[F1]]<@opened("{{.*}}", any P) Self>([[O1]]) : $@convention(method) <τ_0_0 where τ_0_0 : P> (@guaranteed τ_0_0) -> @owned τ_0_0
@@ -59,7 +60,8 @@ final class CC: PP {
// The first apply has been devirtualized and inlined. The second remains unspecialized.
// CHECK-LABEL: sil @$s32sil_combine_concrete_existential29testWitnessReturnOptionalSelfAA2PP_pSgyF : $@convention(thin) () -> @owned Optional<any PP> {
// CHECK: [[E1:%.*]] = init_existential_ref %0 : $CC : $CC, $any PP
// CHECK: [[EI:%.*]] = end_init_let_ref %0
// CHECK: [[E1:%.*]] = init_existential_ref [[EI]] : $CC : $CC, $any PP
// CHECK: [[O1:%.*]] = open_existential_ref [[E1]] : $any PP to $@opened("{{.*}}", any PP) Self
// CHECK: [[E2:%.*]] = init_existential_ref %{{.*}} : $@opened("{{.*}}", any PP) Self : $@opened("{{.*}}", any PP) Self, $any PP
// CHECK: [[O2:%.*]] = open_existential_ref [[E2]] : $any PP to $@opened("{{.*}}", any PP) Self

View File

@@ -119,7 +119,7 @@ public class Other {
// CHECK: bb0
// CHECK: debug_value
// CHECK: integer_literal
// CHECK: [[R1:%.*]] = ref_element_addr %0 : $Other, #Other.z
// CHECK: [[R1:%.*]] = ref_element_addr [immutable] %0 : $Other, #Other.z
// CHECK: [[O1:%.*]] = open_existential_addr immutable_access [[R1]] : $*any DerivedProtocol to $*@opened("{{.*}}", any DerivedProtocol) Self
// CHECK: [[W1:%.*]] = witness_method $@opened("{{.*}}", any DerivedProtocol) Self, #DerivedProtocol.foo : <Self where Self : DerivedProtocol> (Self) -> () -> Int, [[O1]] : $*@opened("{{.*}}", any DerivedProtocol) Self : $@convention(witness_method: DerivedProtocol) <τ_0_0 where τ_0_0 : DerivedProtocol> (@in_guaranteed τ_0_0) -> Int
// CHECK: apply [[W1]]<@opened("{{.*}}", any DerivedProtocol) Self>([[O1]]) : $@convention(witness_method: DerivedProtocol) <τ_0_0 where τ_0_0 : DerivedProtocol> (@in_guaranteed τ_0_0) -> Int
@@ -129,7 +129,7 @@ public class Other {
// CHECK: tuple_extract
// CHECK: tuple_extract
// CHECK: cond_fail
// CHECK: [[R2:%.*]] = ref_element_addr %0 : $Other, #Other.p
// CHECK: [[R2:%.*]] = ref_element_addr [immutable] %0 : $Other, #Other.p
// CHECK: [[O2:%.*]] = open_existential_addr immutable_access [[R2]] : $*any PublicProtocol to $*@opened("{{.*}}", any PublicProtocol) Self
// CHECK: [[W2:%.*]] = witness_method $@opened("{{.*}}", any PublicProtocol) Self, #PublicProtocol.foo : <Self where Self : PublicProtocol> (Self) -> () -> Int, [[O2]] : $*@opened("{{.*}}", any PublicProtocol) Self : $@convention(witness_method: PublicProtocol) <τ_0_0 where τ_0_0 : PublicProtocol> (@in_guaranteed τ_0_0) -> Int
// CHECK: apply [[W2]]<@opened("{{.*}}", any PublicProtocol) Self>([[O2]]) : $@convention(witness_method: PublicProtocol) <τ_0_0 where τ_0_0 : PublicProtocol> (@in_guaranteed τ_0_0) -> Int
@@ -143,7 +143,7 @@ public class Other {
// CHECK: tuple_extract
// CHECK: tuple_extract
// CHECK: cond_fail
// CHECK: [[R3:%.*]] = ref_element_addr %0 : $Other, #Other.r
// CHECK: [[R3:%.*]] = ref_element_addr [immutable] %0 : $Other, #Other.r
// CHECK: [[O3:%.*]] = open_existential_addr immutable_access [[R3]] : $*any GenericProtocol to $*@opened("{{.*}}", any GenericProtocol) Self
// CHECK: [[W3:%.*]] = witness_method $@opened("{{.*}}", any GenericProtocol) Self, #GenericProtocol.foo : <Self where Self : GenericProtocol> (Self) -> () -> Int, [[O3]] : $*@opened("{{.*}}", any GenericProtocol) Self : $@convention(witness_method: GenericProtocol) <τ_0_0 where τ_0_0 : GenericProtocol> (@in_guaranteed τ_0_0) -> Int
// CHECK: apply [[W3]]<@opened("{{.*}}", any GenericProtocol) Self>([[O3]]) : $@convention(witness_method: GenericProtocol) <τ_0_0 where τ_0_0 : GenericProtocol> (@in_guaranteed τ_0_0) -> Int
@@ -152,7 +152,7 @@ public class Other {
// CHECK: tuple_extract
// CHECK: tuple_extract
// CHECK: cond_fail
// CHECK: [[R4:%.*]] = ref_element_addr %0 : $Other, #Other.s
// CHECK: [[R4:%.*]] = ref_element_addr [immutable] %0 : $Other, #Other.s
// CHECK: [[O4:%.*]] = open_existential_addr immutable_access %36 : $*any MultipleConformanceProtocol to $*@opened("{{.*}}", any MultipleConformanceProtocol) Self
// CHECK: [[W4:%.*]] = witness_method $@opened("{{.*}}", any MultipleConformanceProtocol) Self, #MultipleConformanceProtocol.foo : <Self where Self : MultipleConformanceProtocol> (Self) -> () -> Int, %37 : $*@opened("{{.*}}", any MultipleConformanceProtocol) Self : $@convention(witness_method: MultipleConformanceProtocol) <τ_0_0 where τ_0_0 : MultipleConformanceProtocol> (@in_guaranteed τ_0_0) -> Int
// CHECK: apply [[W4]]<@opened("{{.*}}", any MultipleConformanceProtocol) Self>(%37) : $@convention(witness_method: MultipleConformanceProtocol) <τ_0_0 where τ_0_0 : MultipleConformanceProtocol> (@in_guaranteed τ_0_0) -> Int

View File

@@ -46,6 +46,7 @@
// EXTRACT-INIT-LABEL: sil @$s5basic7VehicleC1nACSi_tcfc : $@convention(method) (Int, @owned Vehicle) -> @owned Vehicle {
// EXTRACT-INIT: bb0
// EXTRACT-INIT-NEXT: end_init_let_ref
// EXTRACT-INIT-NEXT: ref_element_addr
// EXTRACT-INIT-NEXT: begin_access [init] [static]
// EXTRACT-INIT-NEXT: store

View File

@@ -29,7 +29,7 @@ public func myPrint(_ k: Klass) { print(k) }
// OPT: bb0([[UNMANAGED:%.*]] :
// OPT: [[UNMANAGED_REF:%.*]] = struct_extract [[UNMANAGED]]
// OPT: [[REF:%.*]] = unmanaged_to_ref [[UNMANAGED_REF]]
// OPT: [[REF_ELT_ADDR:%.*]] = ref_element_addr [[REF]] : $KlassContainer, #KlassContainer.k
// OPT: [[REF_ELT_ADDR:%.*]] = ref_element_addr [immutable] [[REF]] : $KlassContainer, #KlassContainer.k
// OPT: [[VALUE:%.*]] = load [[REF_ELT_ADDR]]
// OPT: apply {{%.*}}([[VALUE]])
// OPT: } // end sil function '$s12unmanaged_rc12useUnmanagedyys0D0VyAA14KlassContainerCGF'