diff --git a/lib/SILGen/Cleanup.h b/lib/SILGen/Cleanup.h index 6c21245fb8e6a..ed89eb83e33b1 100644 --- a/lib/SILGen/Cleanup.h +++ b/lib/SILGen/Cleanup.h @@ -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. diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index 819efc2582d1f..d61214cd1e00a 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -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(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(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; diff --git a/lib/SILGen/SILGenProlog.cpp b/lib/SILGen/SILGenProlog.cpp index ab734dda666d8..8bd4a02ba9a2e 100644 --- a/lib/SILGen/SILGenProlog.cpp +++ b/lib/SILGen/SILGenProlog.cpp @@ -251,10 +251,15 @@ 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(value); + } SGF.B.createDebugValue(loc, value, varinfo); } else { if (auto AllocStack = dyn_cast(value)) @@ -262,6 +267,7 @@ struct ArgumentInitHelper { else SGF.B.createDebugValueAddr(loc, value, varinfo); } + SGF.VarLocs[pd] = SILGenFunction::VarLoc::get(value); } void emitParam(ParamDecl *PD) { diff --git a/test/SILGen/borrow.swift b/test/SILGen/borrow.swift index 9688dfb7602e3..02fa3238284ce 100644 --- a/test/SILGen/borrow.swift +++ b/test/SILGen/borrow.swift @@ -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 @@ -13,7 +13,6 @@ final class C { var d: D = D() } -func use(_ t: T) {} func useD(_ d: D) {} // CHECK-LABEL: sil hidden [ossa] @$s6borrow44lvalueBorrowShouldBeAtEndOfFormalAccessScope{{.*}} : $@convention(thin) () -> () { @@ -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, 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()) -} diff --git a/test/SILGen/lexical_lifetime.swift b/test/SILGen/lexical_lifetime.swift new file mode 100644 index 0000000000000..3ff68703ad39f --- /dev/null +++ b/test/SILGen/lexical_lifetime.swift @@ -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) {} + +//////////////////////////////////////////////////////////////////////////////// +// 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, 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]]([[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 }} +//////////////////////////////////////////////////////////////////////////////// +