Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 8 additions & 0 deletions lib/SILGen/Cleanup.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,14 @@ class LLVM_LIBRARY_VISIBILITY Cleanup {
}
};

struct EndBorrowCleanup final : Cleanup {
SILValue borrowedValue;
EndBorrowCleanup(SILValue borrowedValue);
void emit(SILGenFunction &SGF, CleanupLocation l,
ForUnwind_t forUnwind) override;
void dump(SILGenFunction &) const override;
};

/// A cleanup depth is generally used to denote the set of cleanups
/// between the given cleanup (and not including it) and the top of
/// the stack.
Expand Down
40 changes: 18 additions & 22 deletions lib/SILGen/SILGenExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,34 +158,30 @@ SILGenFunction::emitManagedBeginBorrow(SILLocation loc, SILValue v,
return emitManagedBorrowedRValueWithCleanup(v, bbi, lowering);
}

namespace {

struct EndBorrowCleanup : Cleanup {
SILValue borrowedValue;

EndBorrowCleanup(SILValue borrowedValue) : borrowedValue(borrowedValue) {
if (auto *arg = dyn_cast<SILPhiArgument>(borrowedValue)) {
if (auto *ti = arg->getSingleTerminator()) {
assert(!ti->isTransformationTerminator() &&
"Transforming terminators do not have end_borrow");
}
EndBorrowCleanup::EndBorrowCleanup(SILValue borrowedValue)
: borrowedValue(borrowedValue) {
if (auto *arg = dyn_cast<SILPhiArgument>(borrowedValue)) {
if (auto *ti = arg->getSingleTerminator()) {
assert(!ti->isTransformationTerminator() &&
"Transforming terminators do not have end_borrow");
}
}
}

void emit(SILGenFunction &SGF, CleanupLocation l,
ForUnwind_t forUnwind) override {
SGF.B.createEndBorrow(l, borrowedValue);
}
void EndBorrowCleanup::emit(SILGenFunction &SGF, CleanupLocation l,
ForUnwind_t forUnwind) {
SGF.B.createEndBorrow(l, borrowedValue);
}

void dump(SILGenFunction &) const override {
void EndBorrowCleanup::dump(SILGenFunction &) const {
#ifndef NDEBUG
llvm::errs() << "EndBorrowCleanup "
<< "State:" << getState() << "\n"
<< "borrowed:" << borrowedValue
<< "\n";
llvm::errs() << "EndBorrowCleanup "
<< "State:" << getState() << "\n"
<< "borrowed:" << borrowedValue << "\n";
#endif
}
};
}

namespace {

struct FormalEvaluationEndBorrowCleanup : Cleanup {
FormalEvaluationContext::stable_iterator Depth;
Expand Down
8 changes: 7 additions & 1 deletion lib/SILGen/SILGenProlog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,17 +251,23 @@ struct ArgumentInitHelper {
// Leave the cleanup on the argument, if any, in place to consume the
// argument if we're responsible for it.
}
SGF.VarLocs[pd] = SILGenFunction::VarLoc::get(argrv.getValue());
SILValue value = argrv.getValue();
SILDebugVariable varinfo(pd->isImmutable(), ArgNo);
if (!argrv.getType().isAddress()) {
if (SGF.getASTContext().LangOpts.EnableExperimentalLexicalLifetimes &&
value->getOwnershipKind() != OwnershipKind::None) {
value =
SILValue(SGF.B.createBeginBorrow(loc, value, /*isLexical*/ true));
SGF.Cleanups.pushCleanup<EndBorrowCleanup>(value);
}
SGF.B.createDebugValue(loc, value, varinfo);
} else {
if (auto AllocStack = dyn_cast<AllocStackInst>(value))
AllocStack->setArgNo(ArgNo);
else
SGF.B.createDebugValueAddr(loc, value, varinfo);
}
SGF.VarLocs[pd] = SILGenFunction::VarLoc::get(value);
}

void emitParam(ParamDecl *PD) {
Expand Down
58 changes: 1 addition & 57 deletions test/SILGen/borrow.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

// RUN: %target-swift-emit-silgen -enable-experimental-lexical-lifetimes -module-name borrow -parse-stdlib %s | %FileCheck %s
// RUN: %target-swift-emit-silgen -module-name borrow -parse-stdlib %s | %FileCheck %s

import Swift

Expand All @@ -13,7 +13,6 @@ final class C {
var d: D = D()
}

func use<T>(_ t: T) {}
func useD(_ d: D) {}

// CHECK-LABEL: sil hidden [ossa] @$s6borrow44lvalueBorrowShouldBeAtEndOfFormalAccessScope{{.*}} : $@convention(thin) () -> () {
Expand All @@ -36,58 +35,3 @@ func lvalueBorrowShouldBeAtEndOfFormalAccessScope() {
var c = C()
useD(c.d)
}

// CHECK-LABEL: sil hidden [ossa] @lexical_borrow_let_class
// CHECK: [[INIT_C:%[^,]+]] = function_ref @$s6borrow1CCACycfC
// CHECK: [[INSTANCE:%[^,]+]] = apply [[INIT_C]]({{%[0-9]+}})
// CHECK: [[BORROW:%[^,]+]] = begin_borrow [lexical] [[INSTANCE]] : $C
// CHECK: end_borrow [[BORROW:%[^,]+]]
// CHECK-LABEL: } // end sil function 'lexical_borrow_let_class'
@_silgen_name("lexical_borrow_let_class")
func lexical_borrow_let_class() {
let c = C()
}

// CHECK-LABEL: sil hidden [ossa] @lexical_borrow_if_let_class
// CHECK: [[INIT_C:%[^,]+]] = function_ref @$s6borrow1CC8failablyACSgyt_tcfC
// CHECK: [[INSTANCE:%[^,]+]] = apply [[INIT_C]]({{%[^,]+}})
// CHECK: switch_enum [[INSTANCE]] : $Optional<C>, case #Optional.some!enumelt: [[BASIC_BLOCK2:bb[^,]+]], case #Optional.none!enumelt: {{bb[^,]+}}
// CHECK: [[BASIC_BLOCK2]]([[INSTANCE:%[^,]+]] : @owned $C):
// CHECK: [[BORROW:%[^,]+]] = begin_borrow [lexical] [[INSTANCE]] : $C
// CHECK: end_borrow [[BORROW]] : $C
// CHECK-LABEL: // end sil function 'lexical_borrow_if_let_class'
@_silgen_name("lexical_borrow_if_let_class")
func lexical_borrow_if_let_class() {
if let c = C(failably: ()) {
use(())
}
}

struct S {
let c: C
}

// CHECK-LABEL: sil hidden [ossa] @lexical_borrow_let_class_in_struct
// CHECK: [[INIT_S:%[^,]+]] = function_ref @$s6borrow1SV1cAcA1CC_tcfC
// CHECK: [[INSTANCE:%[^,]+]] = apply [[INIT_S]]({{%[0-9]+}}, {{%[0-9]+}})
// CHECK: [[BORROW:%[^,]+]] = begin_borrow [lexical] [[INSTANCE]] : $S
// CHECK: end_borrow [[BORROW:%[^,]+]]
// CHECK-LABEL: } // end sil function 'lexical_borrow_let_class_in_struct'
@_silgen_name("lexical_borrow_let_class_in_struct")
func lexical_borrow_let_class_in_struct() {
let s = S(c: C())
}

enum E {
case e(C)
}

// CHECK-LABEL: sil hidden [ossa] @lexical_borrow_let_class_in_enum
// CHECK: [[INSTANCE:%[^,]+]] = enum $E, #E.e!enumelt, {{%[0-9]+}} : $C
// CHECK: [[BORROW:%[^,]+]] = begin_borrow [lexical] [[INSTANCE]] : $E
// CHECK: end_borrow [[BORROW:%[^,]+]]
// CHECK-LABEL: } // end sil function 'lexical_borrow_let_class_in_enum'
@_silgen_name("lexical_borrow_let_class_in_enum")
func lexical_borrow_let_class_in_enum() {
let s = E.e(C())
}
126 changes: 126 additions & 0 deletions test/SILGen/lexical_lifetime.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
// RUN: %target-swift-emit-silgen -enable-experimental-lexical-lifetimes -module-name borrow -parse-stdlib %s | %FileCheck %s

import Swift

////////////////////////////////////////////////////////////////////////////////
// Declarations {{
////////////////////////////////////////////////////////////////////////////////

final class C {
init() {}
init?(failably: ()) {}
}

struct S {
let c: C
}

struct Trivial {
let i: Int
}

enum E {
case e(C)
}

@_silgen_name("use_generic")
func use_generic<T>(_ t: T) {}

////////////////////////////////////////////////////////////////////////////////
// Declarations }}
////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////
// Tests {{
////////////////////////////////////////////////////////////////////////////////

// let bindings:

// CHECK-LABEL: sil hidden [ossa] @lexical_borrow_let_class
// CHECK: [[INIT_C:%[^,]+]] = function_ref @$s6borrow1CCACycfC
// CHECK: [[INSTANCE:%[^,]+]] = apply [[INIT_C]]({{%[0-9]+}})
// CHECK: [[BORROW:%[^,]+]] = begin_borrow [lexical] [[INSTANCE]] : $C
// CHECK: end_borrow [[BORROW:%[^,]+]]
// CHECK-LABEL: } // end sil function 'lexical_borrow_let_class'
@_silgen_name("lexical_borrow_let_class")
func lexical_borrow_let_class() {
let c = C()
}

// CHECK-LABEL: sil hidden [ossa] @lexical_borrow_if_let_class
// CHECK: [[INIT_C:%[^,]+]] = function_ref @$s6borrow1CC8failablyACSgyt_tcfC
// CHECK: [[INSTANCE:%[^,]+]] = apply [[INIT_C]]({{%[^,]+}})
// CHECK: switch_enum [[INSTANCE]] : $Optional<C>, case #Optional.some!enumelt: [[BASIC_BLOCK2:bb[^,]+]], case #Optional.none!enumelt: {{bb[^,]+}}
// CHECK: [[BASIC_BLOCK2]]([[INSTANCE:%[^,]+]] : @owned $C):
// CHECK: [[BORROW:%[^,]+]] = begin_borrow [lexical] [[INSTANCE]] : $C
// CHECK: end_borrow [[BORROW]] : $C
// CHECK-LABEL: // end sil function 'lexical_borrow_if_let_class'
@_silgen_name("lexical_borrow_if_let_class")
func lexical_borrow_if_let_class() {
if let c = C(failably: ()) {
use_generic(())
}
}

// CHECK-LABEL: sil hidden [ossa] @lexical_borrow_let_class_in_struct
// CHECK: [[INIT_S:%[^,]+]] = function_ref @$s6borrow1SV1cAcA1CC_tcfC
// CHECK: [[INSTANCE:%[^,]+]] = apply [[INIT_S]]({{%[0-9]+}}, {{%[0-9]+}})
// CHECK: [[BORROW:%[^,]+]] = begin_borrow [lexical] [[INSTANCE]] : $S
// CHECK: end_borrow [[BORROW:%[^,]+]]
// CHECK-LABEL: } // end sil function 'lexical_borrow_let_class_in_struct'
@_silgen_name("lexical_borrow_let_class_in_struct")
func lexical_borrow_let_class_in_struct() {
let s = S(c: C())
}

// CHECK-LABEL: sil hidden [ossa] @lexical_borrow_let_class_in_enum
// CHECK: [[INSTANCE:%[^,]+]] = enum $E, #E.e!enumelt, {{%[0-9]+}} : $C
// CHECK: [[BORROW:%[^,]+]] = begin_borrow [lexical] [[INSTANCE]] : $E
// CHECK: end_borrow [[BORROW:%[^,]+]]
// CHECK-LABEL: } // end sil function 'lexical_borrow_let_class_in_enum'
@_silgen_name("lexical_borrow_let_class_in_enum")
func lexical_borrow_let_class_in_enum() {
let s = E.e(C())
}

// arguments:

// CHECK-LABEL: sil hidden [ossa] @lexical_borrow_arg_guaranteed_class : $@convention(thin) (@guaranteed C) -> () {
// CHECK: {{bb[^,]+}}([[INSTANCE:%[^,]+]] : @guaranteed $C):
// CHECK: [[LIFETIME:%[^,]+]] = begin_borrow [lexical] [[INSTANCE]]
// CHECK: debug_value [[LIFETIME]]
// CHECK: [[ADDR:%[^,]+]] = alloc_stack $C
// CHECK: store_borrow [[LIFETIME]] to [[ADDR]]
// CHECK: [[USE_GENERIC:%[^,]+]] = function_ref @use_generic
// CHECK: [[REGISTER_6:%[^,]+]] = apply [[USE_GENERIC]]<C>([[ADDR]])
// CHECK: dealloc_stack [[ADDR]]
// CHECK: end_borrow [[LIFETIME]]
// CHECK: [[RETVAL:%[^,]+]] = tuple ()
// CHECK: return [[RETVAL]]
// CHECK-LABEL: } // end sil function 'lexical_borrow_arg_guaranteed_class'
@_silgen_name("lexical_borrow_arg_guaranteed_class")
func lexical_borrow_arg_guaranteed_class(_ c: C) {
use_generic(c)
}

// CHECK-LABEL: sil hidden [ossa] @lexical_borrow_arg_class_addr : $@convention(thin) (@inout C) -> () {
// CHECK-NOT: begin_borrow [lexical]
// CHECK-LABEL: } // end sil function 'lexical_borrow_arg_class_addr'
@_silgen_name("lexical_borrow_arg_class_addr")
func lexical_borrow_arg_class_addr(_ c: inout C) {
use_generic(c)
}

// CHECK-LABEL: sil hidden [ossa] @lexical_borrow_arg_trivial : $@convention(thin) (Trivial) -> () {
// CHECK-NOT: begin_borrow [lexical]
// CHECK-LABEL: } // end sil function 'lexical_borrow_arg_trivial'
@_silgen_name("lexical_borrow_arg_trivial")
func lexical_borrow_arg_trivial(_ trivial: Trivial) {
use_generic(trivial)
}

////////////////////////////////////////////////////////////////////////////////
// Test }}
////////////////////////////////////////////////////////////////////////////////