From 49d7e041de77eb79d429b8dd1b1851438f8b3356 Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Tue, 9 May 2023 15:54:16 -0700 Subject: [PATCH 01/41] [cxx-interop] C++ records should have address-only layout when they can't be passed in registers This ensures that a C++ record with only ObjC ARC pointers with trivial other members is passed by value in SIL Fixes https://github.com/apple/swift/issues/61929 --- lib/ClangImporter/ImportDecl.cpp | 8 +-- lib/SIL/IR/SILFunctionType.cpp | 6 ++ .../Inputs/cxx-class-with-arc-fields-ctor.h | 31 ++++++++++ .../objc-class-with-non-trivial-cxx-record.mm | 18 ++++++ ...call-to-generated-init-with-nsstring.swift | 54 +++++++++++++--- ...ield-in-struct-type-layout-execution.swift | 62 +++++++++++++++++++ 6 files changed, 163 insertions(+), 16 deletions(-) create mode 100644 test/Interop/Cxx/objc-correctness/Inputs/objc-class-with-non-trivial-cxx-record.mm create mode 100644 test/Interop/Cxx/objc-correctness/objcxx-arc-field-in-struct-type-layout-execution.swift diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 7191a36e1f9eb..8b6f3326f771b 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -2427,15 +2427,9 @@ namespace { } if (cxxRecordDecl) { - auto isNonTrivialForPurposeOfCalls = - [](const clang::CXXRecordDecl *decl) -> bool { - return decl->hasNonTrivialCopyConstructor() || - decl->hasNonTrivialMoveConstructor() || - !decl->hasTrivialDestructor(); - }; if (auto structResult = dyn_cast(result)) structResult->setIsCxxNonTrivial( - isNonTrivialForPurposeOfCalls(cxxRecordDecl)); + !cxxRecordDecl->canPassInRegisters()); for (auto &getterAndSetter : Impl.GetterSetterMap[result]) { auto getter = getterAndSetter.second.first; diff --git a/lib/SIL/IR/SILFunctionType.cpp b/lib/SIL/IR/SILFunctionType.cpp index a68131c781a48..44e7c2a0acf34 100644 --- a/lib/SIL/IR/SILFunctionType.cpp +++ b/lib/SIL/IR/SILFunctionType.cpp @@ -3137,6 +3137,12 @@ getIndirectCParameterConvention(const clang::ParmVarDecl *param) { /// /// Generally, whether the parameter is +1 is handled before this. static ParameterConvention getDirectCParameterConvention(clang::QualType type) { + if (auto *cxxRecord = type->getAsCXXRecordDecl()) { + // Directly passed non-trivially destroyed C++ record is consumed by the + // callee. + if (!cxxRecord->hasTrivialDestructor()) + return ParameterConvention::Direct_Owned; + } return ParameterConvention::Direct_Unowned; } diff --git a/test/Interop/Cxx/objc-correctness/Inputs/cxx-class-with-arc-fields-ctor.h b/test/Interop/Cxx/objc-correctness/Inputs/cxx-class-with-arc-fields-ctor.h index bb702daa8910c..706de84cdb7d5 100644 --- a/test/Interop/Cxx/objc-correctness/Inputs/cxx-class-with-arc-fields-ctor.h +++ b/test/Interop/Cxx/objc-correctness/Inputs/cxx-class-with-arc-fields-ctor.h @@ -5,6 +5,10 @@ struct S { NSString *_Nullable B; NSString *_Nullable C; +#ifdef S_NONTRIVIAL_DESTRUCTOR + ~S() {} +#endif + void dump() const { printf("%s\n", [A UTF8String]); printf("%s\n", [B UTF8String]); @@ -12,3 +16,30 @@ struct S { } }; +inline void takeSFunc(S s) { + s.dump(); +} + +struct NonTrivialLogDestructor { + int x = 0; + + ~NonTrivialLogDestructor() { + printf("~NonTrivialLogDestructor %d\n", x); + } +}; + +@interface ClassWithNonTrivialDestructorIvar: NSObject + +- (ClassWithNonTrivialDestructorIvar * _Nonnull)init; + +- (void)takesS:(S)s; + +@end + +struct ReferenceStructToClassWithNonTrivialLogDestructorIvar { + ClassWithNonTrivialDestructorIvar *_Nonnull x; + +#ifdef S_NONTRIVIAL_DESTRUCTOR + ~ReferenceStructToClassWithNonTrivialLogDestructorIvar() {} +#endif +}; diff --git a/test/Interop/Cxx/objc-correctness/Inputs/objc-class-with-non-trivial-cxx-record.mm b/test/Interop/Cxx/objc-correctness/Inputs/objc-class-with-non-trivial-cxx-record.mm new file mode 100644 index 0000000000000..c274eeba63c8b --- /dev/null +++ b/test/Interop/Cxx/objc-correctness/Inputs/objc-class-with-non-trivial-cxx-record.mm @@ -0,0 +1,18 @@ +#import +#import "cxx-class-with-arc-fields-ctor.h" + +@implementation ClassWithNonTrivialDestructorIvar { + NonTrivialLogDestructor value; +}; + +- (ClassWithNonTrivialDestructorIvar *)init { + self->value.x = 21; + return self; +} + +- (void)takesS:(S)s { + printf("takesS!\n"); + s.dump(); +} + +@end diff --git a/test/Interop/Cxx/objc-correctness/call-to-generated-init-with-nsstring.swift b/test/Interop/Cxx/objc-correctness/call-to-generated-init-with-nsstring.swift index eb4abc01ed32e..3d39ec2d35b0f 100644 --- a/test/Interop/Cxx/objc-correctness/call-to-generated-init-with-nsstring.swift +++ b/test/Interop/Cxx/objc-correctness/call-to-generated-init-with-nsstring.swift @@ -1,6 +1,8 @@ // RUN: %target-swift-ide-test -print-module -module-to-print=CxxClassWithNSStringInit -I %S/Inputs -source-filename=x -enable-experimental-cxx-interop -enable-objc-interop | %FileCheck -check-prefix=CHECK-IDE-TEST %s -// RUN: %target-swift-frontend -I %S/Inputs -enable-experimental-cxx-interop -emit-ir %s -Xcc -fignore-exceptions | %FileCheck %s - +// RUN: %target-swift-frontend -I %S/Inputs -enable-experimental-cxx-interop -emit-sil %s -Xcc -fignore-exceptions | %FileCheck --check-prefix=SIL-TRIVIAL %s +// RUN: %target-swift-frontend -I %S/Inputs -enable-experimental-cxx-interop -emit-sil %s -Xcc -fignore-exceptions -Xcc -DS_NONTRIVIAL_DESTRUCTOR | %FileCheck --check-prefix=SIL-NONTRIVIAL %s +// RUN: %target-swift-frontend -I %S/Inputs -enable-experimental-cxx-interop -emit-ir %s -Xcc -fignore-exceptions | %FileCheck --check-prefix=IR-TRIVIAL %s +// RUN: %target-swift-frontend -I %S/Inputs -enable-experimental-cxx-interop -emit-ir %s -Xcc -fignore-exceptions -Xcc -DS_NONTRIVIAL_DESTRUCTOR | %FileCheck --check-prefix=IR-NONTRIVIAL %s // REQUIRES: objc_interop @@ -15,11 +17,45 @@ import CxxClassWithNSStringInit // CHECK-IDE-TEST: var C: NSString? // CHECK-IDE-TEST: } -var foo: NSString? = "foo" -var bar: NSString? = "bar" -var baz: NSString? = "baz" -var s = S(A: foo, B: bar, C: baz) -s.dump() +func testSdump() { + var foo: NSString? = "foo" + var bar: NSString? = "bar" + var baz: NSString? = "baz" + var s = S(A: foo, B: bar, C: baz) + s.dump() + ClassWithNonTrivialDestructorIvar().takesS(s) + takeSFunc(s) +} + +testSdump() + +// SIL-TRIVIAL: function_ref @_ZNK1S4dumpEv : $@convention(cxx_method) (@in_guaranteed S) -> () +// SIL-TRIVIAL-NEXT: apply %{{.*}}(%{{.*}}) : $@convention(cxx_method) (@in_guaranteed S) -> () +// SIL-TRIVIAL: $@convention(objc_method) (@owned S, ClassWithNonTrivialDestructorIvar) -> () +// SIL-TRIVIAL-NEXT: apply %{{.*}}(%{{.*}}) : $@convention(objc_method) (@owned S, ClassWithNonTrivialDestructorIvar) -> () +// SIL-TRIVIAL: function_ref @_Z9takeSFunc : $@convention(c) (@owned S) -> () +// SIL-TRIVIAL-NEXT: apply %{{.*}}(%{{.*}}) : $@convention(c) (@owned S) -> () + +// SIL-NONTRIVIAL: function_ref @_ZNK1S4dumpEv : $@convention(cxx_method) (@in_guaranteed S) -> () +// SIL-NONTRIVIAL-NEXT: apply %{{.*}}(%{{.*}}) : $@convention(cxx_method) (@in_guaranteed S) -> () +// SIL-NONTRIVIAL: $@convention(objc_method) (@in S, ClassWithNonTrivialDestructorIvar) -> () +// SIL-NONTRIVIAL-NEXT: apply %{{.*}}(%{{.*}}) : $@convention(objc_method) (@in S, ClassWithNonTrivialDestructorIvar) -> () +// SIL-NONTRIVIAL: function_ref @_Z9takeSFunc : $@convention(c) (@in S) -> () +// SIL-NONTRIVIAL-NEXT: apply %{{.*}}(%{{.*}}) : $@convention(c) (@in S) -> () + + +// IR-TRIVIAL-LABEL: define {{.*}} swiftcc void @"$s4main9testSdumpyyF"() +// IR-TRIVIAL-NOT: @_ZN1SC1ERKS_ +// IR-TRIVIAL: call {{.*}} @_ZNK1S4dumpEv +// IR-TRIVIAL: call {{.*}} @"$sSo1SVWOh" + +// IR-TRIVIAL-LABEL: define linkonce_odr {{.*}} @"$sSo1SVWOh"( +// IR-TRIVIAL: @llvm.objc.release +// IR-TRIVIAL: @llvm.objc.release +// IR-TRIVIAL: @llvm.objc.release +// IR-TRIVIAL: } -// CHECK: call {{.*}} @_ZN1SC1ERKS_ -// CHECK: call {{.*}} @_ZNK1S4dumpEv +// IR-NONTRIVIAL-LABEL: define {{.*}} swiftcc void @"$s4main9testSdumpyyF"() +// IR-NONTRIVIAL: call {{.*}} @_ZN1SC1ERKS_ +// IR-NONTRIVIAL: call {{.*}} @_ZNK1S4dumpEv +// IR-NONTRIVIAL: call {{.*}} @_ZN1SD1Ev diff --git a/test/Interop/Cxx/objc-correctness/objcxx-arc-field-in-struct-type-layout-execution.swift b/test/Interop/Cxx/objc-correctness/objcxx-arc-field-in-struct-type-layout-execution.swift new file mode 100644 index 0000000000000..ba411725564da --- /dev/null +++ b/test/Interop/Cxx/objc-correctness/objcxx-arc-field-in-struct-type-layout-execution.swift @@ -0,0 +1,62 @@ +// RUN: %empty-directory(%t2) + +// RUN: %target-interop-build-clangxx -c %S/Inputs/objc-class-with-non-trivial-cxx-record.mm -o %t2/objc-class-impl.o -fobjc-arc + +// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-experimental-cxx-interop -Xcc -fignore-exceptions -Xlinker %t2/objc-class-impl.o) | %FileCheck %s +// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-experimental-cxx-interop -Xcc -fignore-exceptions -O -Xlinker %t2/objc-class-impl.o) | %FileCheck %s +// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-experimental-cxx-interop -Xcc -fignore-exceptions -Xcc -DS_NONTRIVIAL_DESTRUCTOR -Xlinker %t2/objc-class-impl.o) | %FileCheck %s +// +// REQUIRES: executable_test +// REQUIRES: objc_interop + +import Foundation +import CxxClassWithNSStringInit + +func testS() { + let copy: S + do { + let foo: NSString? = "super long string actually allocated" + let bar: NSString? = "bar" + let baz: NSString? = "baz" + var s = S(A: foo, B: bar, C: baz) + s.dump() + copy = s + } + print("after scope") + copy.dump() + print("takeSFunc") + takeSFunc(copy) +} + +@inline(never) +func blackHole(_ x: T) { + +} + +func testReferenceStructToClassWithNonTrivialLogDestructorIvar() { + print("testReferenceStructToClassWithNonTrivialLogDestructorIvar") + let m = ReferenceStructToClassWithNonTrivialLogDestructorIvar(x: ClassWithNonTrivialDestructorIvar()) + m.x.takesS(S(A: "hello world two", B: "bar", C: "baz")) + blackHole(m) +} + +testS() +testReferenceStructToClassWithNonTrivialLogDestructorIvar() + +// CHECK: super long string actually allocated +// CHECK-NEXT: bar +// CHECK-NEXT: baz +// CHECK-NEXT: after scope +// CHECK-NEXT: super long string actually allocated +// CHECK-NEXT: bar +// CHECK-NEXT: baz +// CHECK-NEXT: takeSFunc +// CHECK-NEXT: super long string actually allocated +// CHECK-NEXT: bar +// CHECK-NEXT: baz +// CHECK-NEXT: testReferenceStructToClassWithNonTrivialLogDestructorIvar +// CHECK-NEXT: takesS! +// CHECK-NEXT: hello world two +// CHECK-NEXT: bar +// CHECK-NEXT: baz +// CHECK-NEXT: ~NonTrivialLogDestructor 21 From 2c4188b8f4f41faabe7c0b3d6dd220c86c967c62 Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Tue, 9 May 2023 16:22:59 -0700 Subject: [PATCH 02/41] [cxx-interop] mark C++ classes with trivial_abi attribute as unavailable in Swift --- lib/ClangImporter/ImportDecl.cpp | 11 +++++++ .../Interop/Cxx/class/clang-trivial-abi.swift | 33 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 test/Interop/Cxx/class/clang-trivial-abi.swift diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 8b6f3326f771b..c15268fd5bcbd 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -2680,6 +2680,17 @@ namespace { if (!result) return nullptr; + if (decl->hasAttr()) { + // We cannot yet represent trivial_abi C++ records in Swift. + // Clang tells us such type can be passed in registers, so + // we avoid using AddressOnly type-layout for such type, which means + // that it then does not use C++'s copy and destroy semantics from + // Swift. + Impl.markUnavailable(cast(result), + "C++ classes with `trivial_abi` Clang attribute " + "are not yet available in Swift"); + } + if (auto classDecl = dyn_cast(result)) { validateForeignReferenceType(decl, classDecl); diff --git a/test/Interop/Cxx/class/clang-trivial-abi.swift b/test/Interop/Cxx/class/clang-trivial-abi.swift new file mode 100644 index 0000000000000..f9415365b4a41 --- /dev/null +++ b/test/Interop/Cxx/class/clang-trivial-abi.swift @@ -0,0 +1,33 @@ +// RUN: rm -rf %t +// RUN: split-file %s %t + +// RUN: %target-swift-ide-test -print-module -module-to-print=Test -I %t/Inputs -source-filename=x -enable-experimental-cxx-interop | %FileCheck %s +// RUN: %target-swift-frontend -typecheck -I %t/Inputs %t/test.swift -enable-experimental-cxx-interop -verify + +//--- Inputs/module.modulemap +module Test { + header "test.h" + requires cplusplus +} + +//--- Inputs/test.h + +class TrivialABIRecord { + int x = 0; +public: + TrivialABIRecord() {} + ~TrivialABIRecord() { + } +} +__attribute__((trivial_abi)); + +// CHECK: @available(*, unavailable, message: "C++ classes with `trivial_abi` Clang attribute are not yet available in Swift") +// CHECK-NEXT: struct TrivialABIRecord { + +//--- test.swift + +import Test + +func test() { + let _ = TrivialABIRecord() // expected-error{{'TrivialABIRecord' is unavailable: C++ classes with `trivial_abi` Clang attribute are not yet available in Swift}} +} From 84b212cc23372609c92e8492f6905884a0437d4f Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Thu, 18 May 2023 17:02:59 -0700 Subject: [PATCH 03/41] [ConstraintSytem] NFC: Remove unnecessary checking/counting from `countDistinctOverloads` --- lib/Sema/ConstraintSystem.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index ea05b94ee1999..f93d4787d3975 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -5302,12 +5302,10 @@ bool ConstraintSystem::diagnoseAmbiguityWithFixes( /// provided set. static unsigned countDistinctOverloads(ArrayRef choices) { llvm::SmallPtrSet uniqueChoices; - unsigned result = 0; for (auto choice : choices) { - if (uniqueChoices.insert(choice.getOpaqueChoiceSimple()).second) - ++result; + uniqueChoices.insert(choice.getOpaqueChoiceSimple()); } - return result; + return uniqueChoices.size(); } /// Determine the name of the overload in a set of overload choices. From f12e24e85c5932052e5cfaf16363335831b18b83 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Fri, 19 May 2023 09:35:48 -0700 Subject: [PATCH 04/41] [Diagnostics] Skip overloaded locations where all solutions have the same type If there are multiple overloads, let's skip locations that produce the same type across all of the solutions, such location is most likely a consequence of ambiguity and not its source. Resolves: rdar://109245375 --- lib/Sema/ConstraintSystem.cpp | 27 +++++++++++ test/Constraints/ambiguity_diagnostics.swift | 50 ++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 test/Constraints/ambiguity_diagnostics.swift diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index f93d4787d3975..f0090d1b4230a 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -5308,6 +5308,14 @@ static unsigned countDistinctOverloads(ArrayRef choices) { return uniqueChoices.size(); } +static Type getOverloadChoiceType(ConstraintLocator *overloadLoc, + const Solution &solution) { + auto selectedOverload = solution.overloadChoices.find(overloadLoc); + if (selectedOverload == solution.overloadChoices.end()) + return Type(); + return solution.simplifyType(selectedOverload->second.adjustedOpenedType); +} + /// Determine the name of the overload in a set of overload choices. static DeclName getOverloadChoiceName(ArrayRef choices) { DeclName name; @@ -5387,6 +5395,25 @@ bool ConstraintSystem::diagnoseAmbiguity(ArrayRef solutions) { auto &overload = diff.overloads[i]; auto *locator = overload.locator; + // If there is only one overload difference, it's the best. + if (n == 1) { + bestOverload = i; + break; + } + + // If there are multiple overload sets involved, let's pick the + // one that has choices with different types, because that is + // most likely the source of ambiguity. + { + auto overloadTy = getOverloadChoiceType(locator, solutions.front()); + if (std::all_of(solutions.begin() + 1, solutions.end(), + [&](const Solution &solution) { + return overloadTy->isEqual( + getOverloadChoiceType(locator, solution)); + })) + continue; + } + ASTNode anchor; // Simplification of member locator would produce a base expression, diff --git a/test/Constraints/ambiguity_diagnostics.swift b/test/Constraints/ambiguity_diagnostics.swift new file mode 100644 index 0000000000000..b8d991529bc0e --- /dev/null +++ b/test/Constraints/ambiguity_diagnostics.swift @@ -0,0 +1,50 @@ +// RUN: %target-typecheck-verify-swift -swift-version 5 -disable-availability-checking + +protocol View { +} + +extension View { + func title(_ title: S) -> some View where S : StringProtocol { + EmptyView() + } + + func title(_ titleKey: LocalizedString) -> some View { + EmptyView() + } +} + +extension View { + func background(_: T) -> some View { + EmptyView() + } +} + +struct EmptyView : View {} + +struct Text : View { + init(_: String) {} +} + +protocol ShapeStyle { +} + +struct AnyShapeStyle : ShapeStyle {} +struct AnyGradient : ShapeStyle {} + +struct LocalizedString : ExpressibleByStringLiteral, ExpressibleByExtendedGraphemeClusterLiteral { + init(extendedGraphemeClusterLiteral value: String) {} + init(stringLiteral: String) {} +} + +func test() { + func __findValue(_: String, fallback: LocalizedString) -> LocalizedString { fatalError() } + func __findValue(_: String, fallback: T) -> T { fatalError() } + func __findValue(_: String, fallback: T) -> T { fatalError() } + + func ambiguitySource() -> AnyShapeStyle { fatalError() } // expected-note {{found this candidate}} + func ambiguitySource() -> AnyGradient { fatalError() } // expected-note {{found this candidate}} + + Text("Test") + .title(__findValue("someKey", fallback: "")) + .background(ambiguitySource()) // expected-error {{ambiguous use of 'ambiguitySource()'}} +} From 47a08e3cfa0d647f9f46552a0454b2ad654a15be Mon Sep 17 00:00:00 2001 From: Karl <5254025+karwa@users.noreply.github.com> Date: Fri, 9 Jun 2023 16:36:43 +0200 Subject: [PATCH 05/41] Enable IRGen/protocol_metadata test on Apple Silicon --- test/IRGen/protocol_metadata.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/IRGen/protocol_metadata.swift b/test/IRGen/protocol_metadata.swift index 3685b93313661..7ddc6abc1880d 100644 --- a/test/IRGen/protocol_metadata.swift +++ b/test/IRGen/protocol_metadata.swift @@ -1,6 +1,6 @@ // RUN: %target-swift-frontend -primary-file %s -emit-ir -disable-objc-attr-requires-foundation-module -enable-objc-interop | %FileCheck %s -DINT=i%target-ptrsize -// REQUIRES: CPU=x86_64 +// REQUIRES: PTRSIZE=64 protocol A { func a() } protocol B { func b() } From c6dd3ad8393d4bf205789856aad1b39b89e3fb65 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Tue, 13 Jun 2023 12:14:25 +0100 Subject: [PATCH 06/41] [CS] Diagnose UnresolvedPatternExprs as part of constraint solving Instead of diagnosing in CSApply, let's create a fix and diagnose in the solver instead. Additionally, make sure we assign ErrorTypes to any VarDecls bound by the invalid pattern, which fixes a crash. rdar://110638279 --- include/swift/Sema/CSFix.h | 30 ++++++++++++++++++++++++++++ lib/Sema/CSApply.cpp | 19 +++--------------- lib/Sema/CSDiagnostics.cpp | 26 ++++++++++++++++++++++++ lib/Sema/CSDiagnostics.h | 16 +++++++++++++++ lib/Sema/CSFix.cpp | 13 ++++++++++++ lib/Sema/CSGen.cpp | 22 ++++++++++---------- lib/Sema/CSSimplify.cpp | 1 + test/Constraints/issue-66553.swift | 12 +++++++++++ test/Constraints/rdar105782480.swift | 1 + test/Constraints/rdar106598067.swift | 7 ++++--- 10 files changed, 118 insertions(+), 29 deletions(-) create mode 100644 test/Constraints/issue-66553.swift diff --git a/include/swift/Sema/CSFix.h b/include/swift/Sema/CSFix.h index 55d9349726ec3..e44ea8ef4249d 100644 --- a/include/swift/Sema/CSFix.h +++ b/include/swift/Sema/CSFix.h @@ -306,6 +306,9 @@ enum class FixKind : uint8_t { /// This issue should already have been diagnosed elsewhere. IgnoreUnresolvedPatternVar, + /// Ignore a nested UnresolvedPatternExpr in an ExprPattern, which is invalid. + IgnoreInvalidPatternInExpr, + /// Resolve type of `nil` by providing a contextual type. SpecifyContextualTypeForNil, @@ -2959,6 +2962,33 @@ class IgnoreUnresolvedPatternVar final : public ConstraintFix { } }; +class IgnoreInvalidPatternInExpr final : public ConstraintFix { + Pattern *P; + + IgnoreInvalidPatternInExpr(ConstraintSystem &cs, Pattern *pattern, + ConstraintLocator *locator) + : ConstraintFix(cs, FixKind::IgnoreInvalidPatternInExpr, locator), + P(pattern) {} + +public: + std::string getName() const override { + return "ignore invalid Pattern nested in Expr"; + } + + bool diagnose(const Solution &solution, bool asNote = false) const override; + + bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { + return diagnose(*commonFixes.front().first); + } + + static IgnoreInvalidPatternInExpr * + create(ConstraintSystem &cs, Pattern *pattern, ConstraintLocator *locator); + + static bool classof(const ConstraintFix *fix) { + return fix->getKind() == FixKind::IgnoreInvalidPatternInExpr; + } +}; + class SpecifyContextualTypeForNil final : public ConstraintFix { SpecifyContextualTypeForNil(ConstraintSystem &cs, ConstraintLocator *locator) diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 6b246afdc5071..0958196cdfcad 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -4604,24 +4604,11 @@ namespace { Expr *visitDiscardAssignmentExpr(DiscardAssignmentExpr *expr) { return simplifyExprType(expr); } - + Expr *visitUnresolvedPatternExpr(UnresolvedPatternExpr *expr) { - // If we end up here, we should have diagnosed somewhere else - // already. - Expr *simplified = simplifyExprType(expr); - // Invalidate 'VarDecl's inside the pattern. - expr->getSubPattern()->forEachVariable([](VarDecl *VD) { - VD->setInvalid(); - }); - if (!SuppressDiagnostics - && !cs.getType(simplified)->is()) { - auto &de = cs.getASTContext().Diags; - de.diagnose(simplified->getLoc(), diag::pattern_in_expr, - expr->getSubPattern()->getDescriptiveKind()); - } - return simplified; + llvm_unreachable("Should have diagnosed"); } - + Expr *visitBindOptionalExpr(BindOptionalExpr *expr) { return simplifyExprType(expr); } diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 196217cb62aac..490b50a901813 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -8303,6 +8303,32 @@ bool InvalidEmptyKeyPathFailure::diagnoseAsError() { return true; } +bool InvalidPatternInExprFailure::diagnoseAsError() { + // Check to see if we have something like 'case (let foo)', where + // has a fix associated with it. In such a case, it's more likely than not + // that the user is trying to write an EnumElementPattern, but has made some + // kind of mistake in the function expr that causes it to be treated as an + // ExprPattern. Emitting an additional error for the out of place 'let foo' is + // just noise in that case, so let's avoid diagnosing. + llvm::SmallPtrSet fixAnchors; + for (auto *fix : getSolution().Fixes) { + if (auto *anchor = getAsExpr(fix->getAnchor())) + fixAnchors.insert(anchor); + } + { + auto *E = castToExpr(getLocator()->getAnchor()); + while (auto *parent = findParentExpr(E)) { + if (auto *CE = dyn_cast(parent)) { + if (fixAnchors.contains(CE->getFn())) + return false; + } + E = parent; + } + } + emitDiagnostic(diag::pattern_in_expr, P->getDescriptiveKind()); + return true; +} + bool MissingContextualTypeForNil::diagnoseAsError() { auto *expr = castToExpr(getAnchor()); diff --git a/lib/Sema/CSDiagnostics.h b/lib/Sema/CSDiagnostics.h index 446d5e2dfe6b8..abdcfe05aa3ed 100644 --- a/lib/Sema/CSDiagnostics.h +++ b/lib/Sema/CSDiagnostics.h @@ -2531,6 +2531,22 @@ class InvalidEmptyKeyPathFailure final : public FailureDiagnostic { bool diagnoseAsError() override; }; +/// Diagnose an invalid Pattern node in an ExprPattern. +/// +/// \code +/// if case foo(let x) = y {} +/// \endcode +class InvalidPatternInExprFailure final : public FailureDiagnostic { + Pattern *P; + +public: + InvalidPatternInExprFailure(const Solution &solution, Pattern *pattern, + ConstraintLocator *locator) + : FailureDiagnostic(solution, locator), P(pattern) {} + + bool diagnoseAsError() override; +}; + /// Diagnose situations where there is no context to determine a /// type of `nil` literal e.g. /// diff --git a/lib/Sema/CSFix.cpp b/lib/Sema/CSFix.cpp index 9b9373bd993c2..7ad3bef280b1f 100644 --- a/lib/Sema/CSFix.cpp +++ b/lib/Sema/CSFix.cpp @@ -2080,6 +2080,19 @@ IgnoreInvalidASTNode *IgnoreInvalidASTNode::create(ConstraintSystem &cs, return new (cs.getAllocator()) IgnoreInvalidASTNode(cs, locator); } +bool IgnoreInvalidPatternInExpr::diagnose(const Solution &solution, + bool asNote) const { + InvalidPatternInExprFailure failure(solution, P, getLocator()); + return failure.diagnose(asNote); +} + +IgnoreInvalidPatternInExpr * +IgnoreInvalidPatternInExpr::create(ConstraintSystem &cs, Pattern *pattern, + ConstraintLocator *locator) { + return new (cs.getAllocator()) + IgnoreInvalidPatternInExpr(cs, pattern, locator); +} + bool SpecifyContextualTypeForNil::diagnose(const Solution &solution, bool asNote) const { MissingContextualTypeForNil failure(solution, getLocator()); diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 085d178ae2de3..069ec6a202315 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -3478,16 +3478,18 @@ namespace { } Type visitUnresolvedPatternExpr(UnresolvedPatternExpr *expr) { - // If there are UnresolvedPatterns floating around after pattern type - // checking, they are definitely invalid. However, we will - // diagnose that condition elsewhere; to avoid unnecessary noise errors, - // just plop an open type variable here. - - auto locator = CS.getConstraintLocator(expr); - auto typeVar = CS.createTypeVariable(locator, - TVO_CanBindToLValue | - TVO_CanBindToNoEscape); - return typeVar; + // Encountering an UnresolvedPatternExpr here means we have an invalid + // ExprPattern with a Pattern node like 'let x' nested in it. Record a + // fix, and assign ErrorTypes to any VarDecls bound. + auto *locator = CS.getConstraintLocator(expr); + auto *P = expr->getSubPattern(); + CS.recordFix(IgnoreInvalidPatternInExpr::create(CS, P, locator)); + + P->forEachVariable([&](VarDecl *VD) { + CS.setType(VD, ErrorType::get(CS.getASTContext())); + }); + + return CS.createTypeVariable(locator, TVO_CanBindToHole); } /// Get the type T? diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 77d02761259a9..b836392bf9487 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -14871,6 +14871,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint( case FixKind::AddExplicitExistentialCoercion: case FixKind::DestructureTupleToMatchPackExpansionParameter: case FixKind::AllowValueExpansionWithoutPackReferences: + case FixKind::IgnoreInvalidPatternInExpr: case FixKind::IgnoreMissingEachKeyword: llvm_unreachable("handled elsewhere"); } diff --git a/test/Constraints/issue-66553.swift b/test/Constraints/issue-66553.swift new file mode 100644 index 0000000000000..983aca34aa61d --- /dev/null +++ b/test/Constraints/issue-66553.swift @@ -0,0 +1,12 @@ +// RUN: %target-typecheck-verify-swift + +// https://github.com/apple/swift/issues/66553 + +func baz(y: [Int], z: Int) -> Int { + switch z { + case y[let z]: // expected-error {{'let' binding pattern cannot appear in an expression}} + z + default: + z + } +} diff --git a/test/Constraints/rdar105782480.swift b/test/Constraints/rdar105782480.swift index 581f7b3d0db3b..aefb548622e95 100644 --- a/test/Constraints/rdar105782480.swift +++ b/test/Constraints/rdar105782480.swift @@ -12,6 +12,7 @@ func foo(value: MyEnum) { switch value { case .second(let drag).invalid: // expected-error@-1 {{value of type 'MyEnum' has no member 'invalid'}} + // expected-error@-2 {{'let' binding pattern cannot appear in an expression}} break } } diff --git a/test/Constraints/rdar106598067.swift b/test/Constraints/rdar106598067.swift index 0cacec43cf8b2..1579dc002216a 100644 --- a/test/Constraints/rdar106598067.swift +++ b/test/Constraints/rdar106598067.swift @@ -3,9 +3,10 @@ enum E: Error { case e } // rdar://106598067 – Make sure we don't crash. -// FIXME: Bad diagnostic (the issue is that it should be written 'as', not 'as?') +// FIXME: We ought to have a tailored diagnostic to change to 'as' instead of 'as?' let fn = { - // expected-error@-1 {{unable to infer closure type without a type annotation}} do {} catch let x as? E {} - // expected-warning@-1 {{'catch' block is unreachable because no errors are thrown in 'do' block}} + // expected-error@-1 {{pattern variable binding cannot appear in an expression}} + // expected-error@-2 {{expression pattern of type 'E?' cannot match values of type 'any Error'}} + // expected-warning@-3 {{'catch' block is unreachable because no errors are thrown in 'do' block}} } From fbbbd0d08ad661b0ca5a78d16a46d97c3cb988be Mon Sep 17 00:00:00 2001 From: Alex Hoppen Date: Wed, 14 Jun 2023 13:40:28 -0700 Subject: [PATCH 07/41] [Macros] Allow keywords after `#` in freestanding macro expansions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow keywords after `#` in freestanding macro expansions There is no reason why we shouldn’t allow keywords here. I also thought about allowing keywords after `@` but things become tricky here for two reasons: - In the parser, we parse a type after the `@`, which could start with a keyword itself (e.g. `any`). If we want to keep the parser logic to parse a type after `@` (which I think we should), then it becomes unclear what `@any T` should parse as. - We allow a space between `@` and the type name. This makes it very hard for recovery to tell whether `@ struct` refers to an attribute with name `struct` or if the user forgot to write the attribute name after `@`. Since almost all keywords are lowercase and attached member macros are usually spelled with an uppercase name, there are a lot fewer chances for clashes here, so I don’t think it’s worth allowing keywords after `@`. https://github.com/apple/swift/issues/66444 rdar://110472060 --- lib/Parse/ParseExpr.cpp | 11 +---------- test/Macros/macro_keywordname.swift | 2 +- test/Macros/macro_self.swift | 4 ++-- test/Parse/macro_decl.swift | 2 +- test/Parse/macro_expr.swift | 2 +- test/decl/import/import.swift | 6 +++--- 6 files changed, 9 insertions(+), 18 deletions(-) diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 0091424812568..426c96b09c094 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -2301,16 +2301,7 @@ ParserStatus Parser::parseFreestandingMacroExpansion( bool hasWhitespaceBeforeName = poundEndLoc != Tok.getLoc(); - // Diagnose and parse keyword right after `#`. - if (Tok.isKeyword() && !hasWhitespaceBeforeName) { - diagnose(Tok, diag::keyword_cant_be_identifier, Tok.getText()); - diagnose(Tok, diag::backticks_to_escape) - .fixItReplace(Tok.getLoc(), "`" + Tok.getText().str() + "`"); - - // Let 'parseDeclNameRef' to parse this as an identifier. - Tok.setKind(tok::identifier); - } - macroNameRef = parseDeclNameRef(macroNameLoc, diag, DeclNameOptions()); + macroNameRef = parseDeclNameRef(macroNameLoc, diag, DeclNameFlag::AllowKeywords); if (!macroNameRef) return makeParserError(); diff --git a/test/Macros/macro_keywordname.swift b/test/Macros/macro_keywordname.swift index 3a302538b312e..2e8b94b8d33a8 100644 --- a/test/Macros/macro_keywordname.swift +++ b/test/Macros/macro_keywordname.swift @@ -53,7 +53,7 @@ import MacroLib @freestanding(expression) public macro `class`() -> Int = #externalMacro(module: "MacroDefinition", type: "OneMacro") func test() { - let _: Int = #public() // expected-error {{keyword 'public' cannot be used as an identifier here}} expected-note {{if this name is unavoidable, use backticks to escape it}} + let _: Int = #public() let _: Int = #`public`() let _: Int = #escaped() let _: Int = #`class`() diff --git a/test/Macros/macro_self.swift b/test/Macros/macro_self.swift index 4e8b39b0fc173..47b278568314c 100644 --- a/test/Macros/macro_self.swift +++ b/test/Macros/macro_self.swift @@ -9,11 +9,11 @@ func sync() {} macro Self() = #externalMacro(module: "MacroDefinition", type: "InvalidMacro") func testSelfAsFreestandingMacro() { - _ = #self // expected-error {{keyword 'self' cannot be used as an identifier here}} expected-note {{use backticks to escape it}} + _ = #self } func testCapitalSelfAsFreestandingMacro() { - _ = #Self // expected-error {{keyword 'Self' cannot be used as an identifier here}} expected-note {{use backticks to escape it}} + _ = #Self } func testSelfAsAttachedMacro() { diff --git a/test/Parse/macro_decl.swift b/test/Parse/macro_decl.swift index 3fc66878c1f8d..53f4afd5e5b66 100644 --- a/test/Parse/macro_decl.swift +++ b/test/Parse/macro_decl.swift @@ -51,6 +51,6 @@ public # someFunc // expected-error {{extraneous whitespace between '#' and macr struct S { # someFunc // expected-error {{extraneous whitespace between '#' and macro name is not permitted}} {{4-5=}} - #class // expected-error {{keyword 'class' cannot be used as an identifier here}} expected-note {{if this name is unavoidable, use backticks to escape it}} {{4-9=`class`}} + #class # struct Inner {} // expected-error {{expected a macro identifier for a pound literal declaration}} expected-error {{consecutive declarations on a line}} } diff --git a/test/Parse/macro_expr.swift b/test/Parse/macro_expr.swift index 3e9a6d061931a..16928aaa5d478 100644 --- a/test/Parse/macro_expr.swift +++ b/test/Parse/macro_expr.swift @@ -44,7 +44,7 @@ do { _ = # macro() // expected-error {{extraneous whitespace between '#' and macro name is not permitted}} {{8-9=}} } do { - _ = #public() // expected-error {{keyword 'public' cannot be used as an identifier here}} expected-note {{if this name is unavoidable, use backticks to escape it}} {{8-14=`public`}} + _ = #public() } do { _ = # public() // expected-error {{expected a macro identifier for a pound literal expression}} diff --git a/test/decl/import/import.swift b/test/decl/import/import.swift index 6f7c10f537fcf..dc39bc85b6c80 100644 --- a/test/decl/import/import.swift +++ b/test/decl/import/import.swift @@ -35,9 +35,9 @@ import func Swift.print // rdar://14418336 #import something_nonexistent -// expected-error@-1 {{keyword 'import' cannot be used as an identifier here}} expected-note@-1 {{use backticks to escape it}} -// expected-error@-2 {{no macro named 'import'}} -// expected-error@-3 {{consecutive statements on a line}} expected-error@-3 {{cannot find 'something_nonexistent' in scope}} +// expected-error@-1 {{no macro named 'import'}} +// expected-error@-2 {{consecutive statements on a line}} +// expected-error@-3 {{cannot find 'something_nonexistent' in scope}} // Import specific decls import typealias Swift.Int From 8b1c9c9be85e8c0bf8bdd6cbca80b370137fe584 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Thu, 15 Jun 2023 11:38:06 -0700 Subject: [PATCH 08/41] [Parse] InitAccessors: Parse initializer exprs associated with computed properties that have `init` accessor Initialization expressions are not allowed on computed properties but if a property has `init` accessor it should be allowed because it could be used by a memberwise initializer. --- lib/Parse/ParseExpr.cpp | 10 +++++----- test/decl/var/init_accessors.swift | 21 +++++++++++++++++++++ 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 0091424812568..5eee0d05ecb5a 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -1059,14 +1059,14 @@ bool Parser::isStartOfGetSetAccessor() { // The only case this can happen is if the accessor label is immediately after // a brace (possibly preceded by attributes). "get" is implicit, so it can't // be checked for. Conveniently however, get/set properties are not allowed - // to have initializers, so we don't have an ambiguity, we just have to check - // for observing accessors. + // to have initializers unless they have `init` accessor, so we don't have an + // ambiguity, we just have to check for observing accessors and init accessor. // // If we have a 'didSet' or a 'willSet' label, disambiguate immediately as // an accessor block. Token NextToken = peekToken(); if (NextToken.isContextualKeyword("didSet") || - NextToken.isContextualKeyword("willSet")) + NextToken.isContextualKeyword("willSet") || NextToken.is(tok::kw_init)) return true; // If we don't have attributes, then it cannot be an accessor block. @@ -1087,9 +1087,9 @@ bool Parser::isStartOfGetSetAccessor() { skipSingle(); } - // Check if we have 'didSet'/'willSet' after attributes. + // Check if we have 'didSet'/'willSet' or 'init' after attributes. return Tok.isContextualKeyword("didSet") || - Tok.isContextualKeyword("willSet"); + Tok.isContextualKeyword("willSet") || Tok.is(tok::kw_init); } /// Recover invalid uses of trailing closures in a situation diff --git a/test/decl/var/init_accessors.swift b/test/decl/var/init_accessors.swift index 6d8633bac190f..3105ae28c478b 100644 --- a/test/decl/var/init_accessors.swift +++ b/test/decl/var/init_accessors.swift @@ -444,3 +444,24 @@ func test_memberwise_ordering() { _ = Test5(_a: 0, _b: 1, c: 2) // Ok } + +func test_default_arguments_are_analyzed() { + struct Test { + var pair: (Int, Int) = (0, 1) { // Ok + init {} + } + + var other: (Int, String) = ("", 42) { + // expected-error@-1 {{cannot convert value of type '(String, Int)' to specified type '(Int, String)'}} + init(initialValue) {} + } + + var otherPair = (0, 1) { + // expected-error@-1 {{computed property must have an explicit type}} + init(initalValue) {} + + get { 42 } + // expected-error@-1 {{cannot convert return expression of type 'Int' to return type '(Int, Int)'}} + } + } +} From 290970a8c479e8e607e38614b291b9a3ed344645 Mon Sep 17 00:00:00 2001 From: Mike Ash Date: Thu, 15 Jun 2023 15:42:07 -0400 Subject: [PATCH 09/41] [Build] Set swift-stdlib-tracing=0 for minimal stdlib builds. --- utils/build-presets.ini | 1 + utils/build-script-impl | 1 + 2 files changed, 2 insertions(+) diff --git a/utils/build-presets.ini b/utils/build-presets.ini index c0c5ed5262643..a41f554a172d2 100644 --- a/utils/build-presets.ini +++ b/utils/build-presets.ini @@ -2625,6 +2625,7 @@ swift-stdlib-has-stdin=0 swift-stdlib-has-environ=0 swift-stdlib-has-locale=0 swift-runtime-static-image-inspection=1 +swift-stdlib-tracing=0 swift-stdlib-concurrency-tracing=0 swift-stdlib-os-versioning=0 swift-stdlib-has-commandline=0 diff --git a/utils/build-script-impl b/utils/build-script-impl index 21712a923143b..b08ee527e3b0e 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -211,6 +211,7 @@ KNOWN_SETTINGS=( swift-runtime-static-image-inspection "0" "whether to build stdlib assuming the runtime environment only supports a single runtime image with Swift code" swift-threading-package "" "override the threading package for the host build; this is either a single package or a semicolon-separated list of sdk:package pairs. Valid packages are empty string (no override), 'pthreads', 'darwin', 'linux', 'win32', 'c11', 'none'" swift-stdlib-single-threaded-concurrency "0" "build Swift concurrency in single-threaded mode" + swift-stdlib-tracing "" "whether to enable tracing signposts for the stdlib; default is 1 on Darwin platforms, 0 otherwise" swift-stdlib-concurrency-tracing "" "whether to enable tracing signposts for concurrency; default is 1 on Darwin platforms, 0 otherwise" swift-stdlib-use-relative-protocol-witness-tables "0" "whether to use relative protocol witness table" swift-enable-runtime-function-counters "" "whether to enable runtime function counters" From 988f373055c6658cd365db598cf82b5482d78272 Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Thu, 15 Jun 2023 12:47:01 -0700 Subject: [PATCH 10/41] [test] fix objcxx-arc-field-in-struct-type-layout-execution.swift test failure on macOS --- .../objcxx-arc-field-in-struct-type-layout-execution.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/Interop/Cxx/objc-correctness/objcxx-arc-field-in-struct-type-layout-execution.swift b/test/Interop/Cxx/objc-correctness/objcxx-arc-field-in-struct-type-layout-execution.swift index ba411725564da..572fe16bad4d8 100644 --- a/test/Interop/Cxx/objc-correctness/objcxx-arc-field-in-struct-type-layout-execution.swift +++ b/test/Interop/Cxx/objc-correctness/objcxx-arc-field-in-struct-type-layout-execution.swift @@ -4,7 +4,9 @@ // RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-experimental-cxx-interop -Xcc -fignore-exceptions -Xlinker %t2/objc-class-impl.o) | %FileCheck %s // RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-experimental-cxx-interop -Xcc -fignore-exceptions -O -Xlinker %t2/objc-class-impl.o) | %FileCheck %s -// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-experimental-cxx-interop -Xcc -fignore-exceptions -Xcc -DS_NONTRIVIAL_DESTRUCTOR -Xlinker %t2/objc-class-impl.o) | %FileCheck %s + +// RUN: %target-interop-build-clangxx -c %S/Inputs/objc-class-with-non-trivial-cxx-record.mm -o %t2/objc-class-impl-non-trivial.o -fobjc-arc -DS_NONTRIVIAL_DESTRUCTOR +// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-experimental-cxx-interop -Xcc -fignore-exceptions -Xcc -DS_NONTRIVIAL_DESTRUCTOR -Xlinker %t2/objc-class-impl-non-trivial.o) | %FileCheck %s // // REQUIRES: executable_test // REQUIRES: objc_interop From 57e226d470d72356ff4175a2b975116ae2d300c4 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Thu, 15 Jun 2023 13:03:15 -0700 Subject: [PATCH 11/41] [CanOSSALifetime] Bail early in lifetime extension While collecting originalLiveBlocks, walking backward from consuming blocks, if a visited block is already in originalLiveBlocks, don't visit its predecessors. Continuing the backwards walk is wasteful. rdar://110854874 --- lib/SILOptimizer/Utils/CanonicalizeOSSALifetime.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/SILOptimizer/Utils/CanonicalizeOSSALifetime.cpp b/lib/SILOptimizer/Utils/CanonicalizeOSSALifetime.cpp index 9d119841216cb..bf616345185cb 100644 --- a/lib/SILOptimizer/Utils/CanonicalizeOSSALifetime.cpp +++ b/lib/SILOptimizer/Utils/CanonicalizeOSSALifetime.cpp @@ -558,7 +558,8 @@ void CanonicalizeOSSALifetime::extendUnconsumedLiveness( // Walk backwards from consuming blocks. while (auto *block = worklist.pop()) { - originalLiveBlocks.insert(block); + if (!originalLiveBlocks.insert(block)) + continue; for (auto *predecessor : block->getPredecessorBlocks()) { // If the block was discovered by liveness, we already added it to the // set. From d1554f2f59d418389fd08f7dc4cca2f4101a89b6 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Thu, 15 Jun 2023 13:05:25 -0700 Subject: [PATCH 12/41] [AST] InitAccessors: Requestify a "has init accessor" check --- include/swift/AST/Decl.h | 4 ++++ include/swift/AST/TypeCheckRequests.h | 16 ++++++++++++++++ include/swift/AST/TypeCheckerTypeIDZone.def | 3 +++ lib/AST/Decl.cpp | 6 ++++++ lib/Sema/TypeCheckStorage.cpp | 10 +++++++--- 5 files changed, 36 insertions(+), 3 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 891f8c1a46427..7942d1c163f92 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -5317,6 +5317,10 @@ class AbstractStorageDecl : public ValueDecl { /// it. bool hasStorage() const; + /// Return true if this is a VarDecl that has init accessor associated + /// with it. + bool hasInitAccessor() const; + /// Return true if this storage has the basic accessors/capability /// to be mutated. This is generally constant after the accessors are /// installed by the parser/importer/whatever. diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index 0dd81a6b654cf..80fcb212739e1 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -4312,6 +4312,22 @@ class IsNonUserModuleRequest bool isCached() const { return true; } }; +class HasInitAccessorRequest + : public SimpleRequest { +public: + using SimpleRequest::SimpleRequest; + +private: + friend SimpleRequest; + + // Evaluation. + bool evaluate(Evaluator &evaluator, AbstractStorageDecl *decl) const; + +public: + bool isCached() const { return true; } +}; + class InitAccessorReferencedVariablesRequest : public SimpleRequest(DeclAttribute *, AccessorDecl *, diff --git a/include/swift/AST/TypeCheckerTypeIDZone.def b/include/swift/AST/TypeCheckerTypeIDZone.def index e13aced855628..a7ae070b5aa99 100644 --- a/include/swift/AST/TypeCheckerTypeIDZone.def +++ b/include/swift/AST/TypeCheckerTypeIDZone.def @@ -487,6 +487,9 @@ SWIFT_REQUEST(TypeChecker, IsNonUserModuleRequest, SWIFT_REQUEST(TypeChecker, TypeCheckObjCImplementationRequest, unsigned(ExtensionDecl *), Cached, NoLocationInfo) +SWIFT_REQUEST(TypeChecker, HasInitAccessorRequest, + bool(AbstractStorageDecl *), Cached, + NoLocationInfo) SWIFT_REQUEST(TypeChecker, InitAccessorReferencedVariablesRequest, ArrayRef(DeclAttribute *, AccessorDecl *, ArrayRef), diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 065fd1e6e352a..dd55ebe4529a1 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -6720,6 +6720,12 @@ Type AbstractStorageDecl::getValueInterfaceType() const { return cast(this)->getElementInterfaceType(); } +bool AbstractStorageDecl::hasInitAccessor() const { + return evaluateOrDefault( + getASTContext().evaluator, + HasInitAccessorRequest{const_cast(this)}, false); +} + VarDecl::VarDecl(DeclKind kind, bool isStatic, VarDecl::Introducer introducer, SourceLoc nameLoc, Identifier name, DeclContext *dc, StorageIsMutable_t supportsMutation) diff --git a/lib/Sema/TypeCheckStorage.cpp b/lib/Sema/TypeCheckStorage.cpp index 979654b18cc1b..f0e2b5e1cfc31 100644 --- a/lib/Sema/TypeCheckStorage.cpp +++ b/lib/Sema/TypeCheckStorage.cpp @@ -301,8 +301,12 @@ StoredPropertiesAndMissingMembersRequest::evaluate(Evaluator &evaluator, return decl->getASTContext().AllocateCopy(results); } -/// Determine whether the given variable has an init accessor. -static bool hasInitAccessor(VarDecl *var) { +bool HasInitAccessorRequest::evaluate(Evaluator &evaluator, + AbstractStorageDecl *decl) const { + auto *var = dyn_cast(decl); + if (!var) + return false; + if (var->getAccessor(AccessorKind::Init)) return true; @@ -340,7 +344,7 @@ InitAccessorPropertiesRequest::evaluate(Evaluator &evaluator, SmallVector results; for (auto *member : decl->getMembers()) { auto *var = dyn_cast(member); - if (!var || var->isStatic() || !hasInitAccessor(var)) { + if (!var || var->isStatic() || !var->hasInitAccessor()) { continue; } From fc895b4ac32a5559f922ce2d319338a57f3e6a7b Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Thu, 15 Jun 2023 13:08:14 -0700 Subject: [PATCH 13/41] [Sema] Formalize a way to check whether storage is initializable Previously only stored properties could be initializable but with introduction of init accessors computed properties gained an ability to specify initialzer expression and participation in memberwise initialization for structs. --- include/swift/AST/Decl.h | 6 ++++++ lib/Sema/TypeCheckDeclPrimary.cpp | 2 +- lib/Sema/TypeCheckMacros.cpp | 6 ++++-- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 7942d1c163f92..556ee0f456948 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -5321,6 +5321,12 @@ class AbstractStorageDecl : public ValueDecl { /// with it. bool hasInitAccessor() const; + /// Return true if this is a property that either has storage + /// or init accessor associated with it. + bool supportsInitialization() const { + return hasStorage() || hasInitAccessor(); + } + /// Return true if this storage has the basic accessors/capability /// to be mutated. This is generally constant after the accessors are /// installed by the parser/importer/whatever. diff --git a/lib/Sema/TypeCheckDeclPrimary.cpp b/lib/Sema/TypeCheckDeclPrimary.cpp index 7b3283e5b959c..84b642e2d470f 100644 --- a/lib/Sema/TypeCheckDeclPrimary.cpp +++ b/lib/Sema/TypeCheckDeclPrimary.cpp @@ -2289,7 +2289,7 @@ class DeclChecker : public DeclVisitor { if (PBD->isInitialized(i)) { // Add the attribute that preserves the "has an initializer" value // across module generation, as required for TBDGen. - if (var->hasStorage() && + if (var->supportsInitialization() && !var->getAttrs().hasAttribute()) { var->getAttrs().add(new (Ctx) HasInitialValueAttr(/*IsImplicit=*/true)); diff --git a/lib/Sema/TypeCheckMacros.cpp b/lib/Sema/TypeCheckMacros.cpp index c7b0f454aca02..dafceccd3fe1d 100644 --- a/lib/Sema/TypeCheckMacros.cpp +++ b/lib/Sema/TypeCheckMacros.cpp @@ -1319,9 +1319,11 @@ Optional swift::expandAccessors( !accessorMacroOnlyIntroducesObservers(macro, roleAttr); if (foundNonObservingAccessor) { // If any non-observing accessor was added, mark the initializer as - // subsumed. + // subsumed unless it has init accessor, because the initializer in + // such cases could be used for memberwise initialization. if (auto var = dyn_cast(storage)) { - if (auto binding = var->getParentPatternBinding()) { + if (auto binding = var->getParentPatternBinding(); + !var->getAccessor(AccessorKind::Init)) { unsigned index = binding->getPatternEntryIndexForVarDecl(var); binding->setInitializerSubsumed(index); } From f58d4077c489dc5e0728eca36b4111e32a3c186e Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Thu, 15 Jun 2023 13:12:11 -0700 Subject: [PATCH 14/41] [Sema/SILGen] Consider init exprs associated with init accessor properties for memberwise init --- lib/SILGen/SILGenConstructor.cpp | 7 +++ lib/Sema/CodeSynthesis.cpp | 6 --- lib/Sema/TypeCheckStorage.cpp | 2 +- test/Interpreter/init_accessors.swift | 69 +++++++++++++++++++++++++++ 4 files changed, 77 insertions(+), 7 deletions(-) diff --git a/lib/SILGen/SILGenConstructor.cpp b/lib/SILGen/SILGenConstructor.cpp index 4879d186e36a5..07add74e1b6ba 100644 --- a/lib/SILGen/SILGenConstructor.cpp +++ b/lib/SILGen/SILGenConstructor.cpp @@ -1474,6 +1474,13 @@ void SILGenFunction::emitMemberInitializers(DeclContext *dc, if (auto pbd = dyn_cast(member)) { if (pbd->isStatic()) continue; + // Skip properties with init accessors, they could only be used + // explicitly and in memberwise initializers. + if (auto *var = pbd->getSingleVar()) { + if (var->hasInitAccessor()) + continue; + } + for (auto i : range(pbd->getNumPatternEntries())) { auto init = pbd->getExecutableInit(i); if (!init) continue; diff --git a/lib/Sema/CodeSynthesis.cpp b/lib/Sema/CodeSynthesis.cpp index c7cc86d589497..53f73bbe6354f 100644 --- a/lib/Sema/CodeSynthesis.cpp +++ b/lib/Sema/CodeSynthesis.cpp @@ -144,12 +144,6 @@ static void maybeAddMemberwiseDefaultArg(ParamDecl *arg, VarDecl *var, if (!var->getParentPattern()->getSingleVar()) return; - // FIXME: Don't attempt to synthesize default arguments for init - // accessor properties because there could be multiple properties - // with default values they are going to initialize. - if (var->getAccessor(AccessorKind::Init)) - return; - // Whether we have explicit initialization. bool isExplicitlyInitialized = false; if (auto pbd = var->getParentPatternBinding()) { diff --git a/lib/Sema/TypeCheckStorage.cpp b/lib/Sema/TypeCheckStorage.cpp index f0e2b5e1cfc31..7560c305665b4 100644 --- a/lib/Sema/TypeCheckStorage.cpp +++ b/lib/Sema/TypeCheckStorage.cpp @@ -3359,7 +3359,7 @@ static void finishStorageImplInfo(AbstractStorageDecl *storage, auto dc = storage->getDeclContext(); if (auto var = dyn_cast(storage)) { - if (!info.hasStorage()) { + if (!info.hasStorage() && !var->hasInitAccessor()) { if (auto *init = var->getParentExecutableInitializer()) { auto &Diags = var->getASTContext().Diags; Diags.diagnose(init->getLoc(), diag::getset_init) diff --git a/test/Interpreter/init_accessors.swift b/test/Interpreter/init_accessors.swift index df8be55a75d2f..ff8ba32daa435 100644 --- a/test/Interpreter/init_accessors.swift +++ b/test/Interpreter/init_accessors.swift @@ -393,3 +393,72 @@ test_memberwise_ordering() // CHECK: test-memberwise-ordering-1: Test1(_a: 0, _b: 42) // CHECK-NEXT: test-memberwise-ordering-2: Test2(_a: -1, _b: -2) // CHECK-NEXT: test-memberwise-ordering-3: Test3(_a: 1, _b: 2, _c: 3) + +func test_memberwise_with_default_args() { + struct TestWithoutDefault { + var _a: Int + var _b: Int + + var pair: (Int, Int) = (-1, 42) { + init(initialValue) initializes(_a, _b) { + _a = initialValue.0 + _b = initialValue.1 + } + + get { (0, 42) } + set { } + } + } + + let test1 = TestWithoutDefault() + print("test-memberwise_with_default-1: \(test1)") + + let test2 = TestWithoutDefault(pair: (42, -1)) + print("test-memberwise_with_default-2: \(test2)") + + struct TestDefaulted { + var _a: Int = 0 + var _b: Int = 0 + + var pair: (Int, Int) = (1, 2) { + init(initialValue) initializes(_a, _b) { + _a = initialValue.0 + _b = initialValue.1 + } + + get { (_a, _b) } + set { } + } + } + + let test3 = TestDefaulted() + print("test-defaulted-1: \(test3)") + + let test4 = TestDefaulted(pair: (3, 4)) + print("test-defaulted-2: \(test4)") + + class TestClass { + var _q: String = "<>" + var _a: Int = 1 + + var pair: (String, Int) = ("", 42) { + init(initialValue) initializes(_q, _a) { + _q = initialValue.0 + _a = initialValue.1 + } + + get { (_q, _a) } + set { } + } + } + + let test5 = TestClass() + print("test-defaulted-class: \(test5.pair)") +} + +test_memberwise_with_default_args() +// CHECK: test-memberwise_with_default-1: TestWithoutDefault(_a: -1, _b: 42) +// CHECK-NEXT: test-memberwise_with_default-2: TestWithoutDefault(_a: 42, _b: -1) +// CHECK-NEXT: test-defaulted-1: TestDefaulted(_a: 0, _b: 0) +// CHECK-NEXT: test-defaulted-2: TestDefaulted(_a: 3, _b: 4) +// CHECK-NEXT: test-defaulted-class: ("<>", 1) From 7abd2653d90664b9595b17d92947416c91094bd3 Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Thu, 15 Jun 2023 13:16:48 -0700 Subject: [PATCH 15/41] [cxx-interop] revert back to old address-only heuristic for MSVC --- lib/ClangImporter/ImportDecl.cpp | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index c15268fd5bcbd..2b211dcce603b 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -2427,9 +2427,39 @@ namespace { } if (cxxRecordDecl) { + // FIXME: Swift right now uses AddressOnly type layout + // in a way that conflates C++ types + // that need to be destroyed or copied explicitly with C++ + // types that have to be passed indirectly, because + // only AddressOnly types can be copied or destroyed using C++ + // semantics. However, in actuality these two concepts are + // separate and don't map to one notion of AddressOnly type + // layout cleanly. We should reserve the use of AddressOnly + // type layout when types have to use C++ copy/move/destroy + // operations, but allow AddressOnly types to be passed + // directly as well. This will help unify the MSVC and + // Itanium difference here, and will allow us to support + // trivial_abi C++ types as well. + auto isNonTrivialForPurposeOfCalls = + [](const clang::CXXRecordDecl *decl) -> bool { + return decl->hasNonTrivialCopyConstructor() || + decl->hasNonTrivialMoveConstructor() || + !decl->hasTrivialDestructor(); + }; + auto isAddressOnlySwiftStruct = + [&](const clang::CXXRecordDecl *decl) -> bool { + // MSVC ABI allows non-trivially destroyed C++ types + // to be passed in register. This is not supported, as such + // type wouldn't be destroyed in Swift correctly. Therefore, + // force AddressOnly type layout using the old heuristic. + // FIXME: Support can pass in registers for MSVC correctly. + if (Impl.SwiftContext.LangOpts.Target.isWindowsMSVCEnvironment()) + return isNonTrivialForPurposeOfCalls(decl); + return !decl->canPassInRegisters(); + }; if (auto structResult = dyn_cast(result)) structResult->setIsCxxNonTrivial( - !cxxRecordDecl->canPassInRegisters()); + isAddressOnlySwiftStruct(cxxRecordDecl)); for (auto &getterAndSetter : Impl.GetterSetterMap[result]) { auto getter = getterAndSetter.second.first; From a9f9bd13946f40dd3469fd5bf6ca3d26d3536373 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Thu, 15 Jun 2023 23:55:07 +0100 Subject: [PATCH 16/41] [SourceKit] Record module loading errors when generating interfaces Record up to two errors emitted when we fail to load a module for interface generation, and include these errors in the message we pass back to the editor. This should help us better pin down the reason why interface generation failed. rdar://109511099 --- include/swift/AST/DiagnosticEngine.h | 16 ++++ .../InterfaceGen/error_clang_module.swift | 43 ++++++++++ .../InterfaceGen/error_swift_module.swift | 58 +++++++++++++ .../lib/SwiftLang/SwiftEditorInterfaceGen.cpp | 84 +++++++++++++++---- 4 files changed, 186 insertions(+), 15 deletions(-) create mode 100644 test/SourceKit/InterfaceGen/error_clang_module.swift create mode 100644 test/SourceKit/InterfaceGen/error_swift_module.swift diff --git a/include/swift/AST/DiagnosticEngine.h b/include/swift/AST/DiagnosticEngine.h index df9130b971694..083713d10af43 100644 --- a/include/swift/AST/DiagnosticEngine.h +++ b/include/swift/AST/DiagnosticEngine.h @@ -1449,6 +1449,22 @@ namespace swift { } }; + /// A RAII object that adds and removes a diagnostic consumer from an engine. + class DiagnosticConsumerRAII final { + DiagnosticEngine &Diags; + DiagnosticConsumer &Consumer; + + public: + DiagnosticConsumerRAII(DiagnosticEngine &diags, + DiagnosticConsumer &consumer) + : Diags(diags), Consumer(consumer) { + Diags.addConsumer(Consumer); + } + ~DiagnosticConsumerRAII() { + Diags.removeConsumer(Consumer); + } + }; + inline void DiagnosticEngine::diagnoseWithNotes(InFlightDiagnostic parentDiag, llvm::function_ref builder) { diff --git a/test/SourceKit/InterfaceGen/error_clang_module.swift b/test/SourceKit/InterfaceGen/error_clang_module.swift new file mode 100644 index 0000000000000..b31501ab1a6c7 --- /dev/null +++ b/test/SourceKit/InterfaceGen/error_clang_module.swift @@ -0,0 +1,43 @@ +// RUN: %empty-directory(%t/Inputs) +// RUN: %empty-directory(%t/Inputs/objcfail) +// RUN: split-file %s %t/Inputs + +//--- objcfail/objcfail.h + +#ifdef FAIL +#error some error from Clang module + +// We only record the first error emitted, so we ignore this one. +#error another error from Clang module +#endif + +void foo(void); + +//--- objcfail/module.modulemap + +module ObjCFail { + header "objcfail.h" + export * +} + +//--- Library.swift + +import ObjCFail + +// First try printing the interface of the Clang module directly. + +// RUN: %sourcekitd-test -req=interface-gen -module ObjCFail -- -I %t/Inputs/objcfail -target %target-triple %s | %FileCheck --check-prefix DIRECT-SUCCESS %s +// DIRECT-SUCCESS: public func foo() + +// RUN: not %sourcekitd-test -req=interface-gen -module ObjCFail -- -Xcc -DFAIL -I %t/Inputs/objcfail -target %target-triple %s 2>&1 | %FileCheck --check-prefix DIRECT-FAIL %s +// DIRECT-FAIL: Could not load module: ObjCFail (could not build {{Objective-C|C}} module 'ObjCFail', some error from Clang module) + +// Now try doing it transitively + +// RUN: %target-swift-frontend -emit-module %t/Inputs/Library.swift -I %t/Inputs/objcfail -module-name Library -o %t + +// RUN: %sourcekitd-test -req=interface-gen -module Library -- -I %t -target %target-triple %s | %FileCheck --check-prefix TRANSITIVE-SUCCESS %s +// TRANSITIVE-SUCCESS: import ObjCFail + +// RUN: not %sourcekitd-test -req=interface-gen -module Library -- -Xcc -DFAIL -I %t -target %target-triple %s 2>&1 | %FileCheck --check-prefix TRANSITIVE-FAIL %s +// TRANSITIVE-FAIL: Could not load module: Library (could not build {{Objective-C|C}} module 'ObjCFail', some error from Clang module) diff --git a/test/SourceKit/InterfaceGen/error_swift_module.swift b/test/SourceKit/InterfaceGen/error_swift_module.swift new file mode 100644 index 0000000000000..61ab865b16d58 --- /dev/null +++ b/test/SourceKit/InterfaceGen/error_swift_module.swift @@ -0,0 +1,58 @@ +// RUN: %empty-directory(%t/Inputs) +// RUN: split-file %s %t/Inputs + +//--- Transitive.swift + +public func foo() {} + +//--- Library.swift + +import Transitive + +//--- LibraryWrong.swift + +import WrongName + +//--- LibraryNonExistant.swift + +import NonExistant + +// RUN: %target-swift-frontend -emit-module %t/Inputs/Transitive.swift -module-name Transitive -o %t/WrongName.swiftmodule +// RUN: %target-swift-frontend -emit-module %t/Inputs/Transitive.swift -module-name Transitive -o %t/Transitive.swiftmodule + +// First try printing the interface of the Transitive module directly. + +// RUN: %sourcekitd-test -req=interface-gen -module Transitive -- -I %t -target %target-triple %s | %FileCheck --check-prefix DIRECT-SUCCESS %s +// DIRECT-SUCCESS: public func foo() + +// RUN: not %sourcekitd-test -req=interface-gen -module WrongName -- -I %t -target %target-triple %s 2>&1 | %FileCheck --check-prefix DIRECT-FAIL %s +// DIRECT-FAIL: Could not load module: WrongName (cannot load module 'Transitive' as 'WrongName') + +// Now try doing it transitively + +// First undo the WrongName module +// RUN: %target-swift-frontend -emit-module %t/Inputs/Transitive.swift -module-name WrongName -o %t/WrongName.swiftmodule + +// RUN: %target-swift-frontend -emit-module %t/Inputs/Library.swift -I %t -module-name Library -o %t +// RUN: %target-swift-frontend -emit-module %t/Inputs/LibraryWrong.swift -I %t -module-name LibraryWrong -o %t + +// Then redo the WrongName module +// RUN: %target-swift-frontend -emit-module %t/Inputs/Transitive.swift -module-name Transitive -o %t/WrongName.swiftmodule + +// RUN: %sourcekitd-test -req=interface-gen -module Library -- -I %t -target %target-triple %s | %FileCheck --check-prefix TRANSITIVE-SUCCESS %s +// TRANSITIVE-SUCCESS: import Transitive + +// RUN: not %sourcekitd-test -req=interface-gen -module LibraryWrong -- -I %t -target %target-triple %s 2>&1 | %FileCheck --check-prefix TRANSITIVE-FAIL %s +// TRANSITIVE-FAIL: Could not load module: LibraryWrong (cannot load module 'Transitive' as 'WrongName') + +// Try a non-existant module + +// RUN: not %sourcekitd-test -req=interface-gen -module NonExistant -- -I %t -target %target-triple %s 2>&1 | %FileCheck --check-prefix DIRECT-NONEXISTANT %s +// DIRECT-NONEXISTANT: Could not load module: NonExistant + +// RUN: %target-swift-frontend -emit-module %t/Inputs/Transitive.swift -module-name NonExistant -o %t +// RUN: %target-swift-frontend -emit-module %t/Inputs/LibraryNonExistant.swift -module-name LibraryNonExistant -I %t -o %t +// RUN: rm -rf %t/NonExistant.swiftmodule + +// RUN: not %sourcekitd-test -req=interface-gen -module LibraryNonExistant -- -I %t -target %target-triple %s 2>&1 | %FileCheck --check-prefix TRANSITIVE-NONEXISTANT %s +// TRANSITIVE-NONEXISTANT: Could not load module: LibraryNonExistant (missing required module 'NonExistant') diff --git a/tools/SourceKit/lib/SwiftLang/SwiftEditorInterfaceGen.cpp b/tools/SourceKit/lib/SwiftLang/SwiftEditorInterfaceGen.cpp index 993506166af39..80f7f1b17b556 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftEditorInterfaceGen.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftEditorInterfaceGen.cpp @@ -265,6 +265,46 @@ static void reportSemanticAnnotations(const SourceTextInfo &IFaceInfo, } } +namespace { +/// A diagnostic consumer that picks up module loading errors. +class ModuleLoadingErrorConsumer final : public DiagnosticConsumer { + llvm::SmallVector DiagMessages; + + void handleDiagnostic(SourceManager &SM, + const DiagnosticInfo &Info) override { + // Only record errors for now. In the future it might be useful to pick up + // some notes, but some notes are just noise. + if (Info.Kind != DiagnosticKind::Error) + return; + + std::string Message; + { + llvm::raw_string_ostream Out(Message); + DiagnosticEngine::formatDiagnosticText(Out, Info.FormatString, + Info.FormatArgs); + } + // We're only interested in the first and last errors. For a clang module + // failure, the first error will be the reason why the module failed to + // load, and the last error will be a generic "could not build Obj-C module" + // error. For a Swift module, we'll typically only emit one error. + // + // NOTE: Currently when loading transitive dependencies for a Swift module, + // we'll only diagnose the root failure, and not record the error for the + // top-level module failure, as we stop emitting errors after a fatal error + // has been recorded. This is currently fine for our use case though, as + // we already include the top-level module name in the error we hand back. + if (DiagMessages.size() < 2) { + DiagMessages.emplace_back(std::move(Message)); + } else { + DiagMessages.back() = std::move(Message); + } + } + +public: + ArrayRef getDiagMessages() { return DiagMessages; } +}; +} // end anonymous namespace + static bool getModuleInterfaceInfo(ASTContext &Ctx, StringRef ModuleName, Optional Group, @@ -280,21 +320,35 @@ static bool getModuleInterfaceInfo(ASTContext &Ctx, return true; } - // Get the (sub)module to generate. - Mod = Ctx.getModuleByName(ModuleName); - if (!Mod) { - ErrMsg = "Could not load module: "; - ErrMsg += ModuleName; - return true; - } - if (Mod->failedToLoad()) { - // We might fail to load the underlying Clang module - // for a Swift overlay module like 'CxxStdlib', or a mixed-language - // framework. Make sure an error is reported in this case, so that we can - // either retry to load with C++ interoperability enabled, and if that - // fails, we can report this to the user. - ErrMsg = "Could not load underlying module for: "; - ErrMsg += ModuleName; + // Get the (sub)module to generate, recording the errors emitted. + ModuleLoadingErrorConsumer DiagConsumer; + { + DiagnosticConsumerRAII R(Ctx.Diags, DiagConsumer); + Mod = Ctx.getModuleByName(ModuleName); + } + + // Check to see if we either couldn't find the module, or we failed to load + // it, and report an error message back that includes the diagnostics we + // collected, which should help pinpoint what the issue was. Note we do this + // even if `Mod` is null, as the clang importer currently returns nullptr + // when a module fails to load, and there may be interesting errors to + // collect there. + // Note that us failing here also means the caller may retry with e.g C++ + // interoperability enabled. + if (!Mod || Mod->failedToLoad()) { + llvm::raw_string_ostream OS(ErrMsg); + + OS << "Could not load module: "; + OS << ModuleName; + auto ModuleErrs = DiagConsumer.getDiagMessages(); + if (!ModuleErrs.empty()) { + // We print the errors in reverse, as they are typically emitted in + // a bottom-up manner by module loading, and a top-down presentation + // makes more sense. + OS << " ("; + llvm::interleaveComma(llvm::reverse(ModuleErrs), OS); + OS << ")"; + } return true; } From 706985df8239c2a9ecf1f63ed69216de83fd11eb Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Thu, 15 Jun 2023 16:32:05 -0700 Subject: [PATCH 17/41] [Macros] Update plugin search options serialization Previously plugin search options were serialized for each option kind. Instead serialize them in the order specified. --- .../Serialization/SerializationOptions.h | 6 +- include/swift/Serialization/Validation.h | 34 ++--------- lib/Frontend/Frontend.cpp | 32 +--------- lib/Serialization/ModuleFileSharedCore.cpp | 31 ++++++---- lib/Serialization/ModuleFormat.h | 39 +++++------- lib/Serialization/Serialization.cpp | 61 +++++++++++-------- .../serialize_plugin_search_paths.swift | 14 ++--- .../lldb-moduleimport-test.cpp | 13 ++-- 8 files changed, 92 insertions(+), 138 deletions(-) diff --git a/include/swift/Serialization/SerializationOptions.h b/include/swift/Serialization/SerializationOptions.h index d3e4f49f2441d..d14c6a1d4d6b9 100644 --- a/include/swift/Serialization/SerializationOptions.h +++ b/include/swift/Serialization/SerializationOptions.h @@ -13,6 +13,7 @@ #ifndef SWIFT_SERIALIZATION_SERIALIZATIONOPTIONS_H #define SWIFT_SERIALIZATION_SERIALIZATIONOPTIONS_H +#include "swift/AST/SearchPathOptions.h" #include "swift/Basic/LLVM.h" #include "swift/Basic/PathRemapper.h" #include "llvm/Support/VersionTuple.h" @@ -43,10 +44,7 @@ namespace swift { StringRef ModuleLinkName; StringRef ModuleInterface; std::vector ExtraClangOptions; - std::vector PluginSearchPaths; - std::vector ExternalPluginSearchPaths; - std::vector CompilerPluginLibraryPaths; - std::vector CompilerPluginExecutablePaths; + std::vector PluginSearchOptions; /// Path prefixes that should be rewritten in debug info. PathRemapper DebuggingOptionsPrefixMap; diff --git a/include/swift/Serialization/Validation.h b/include/swift/Serialization/Validation.h index a82380e74963a..98e96a4bb9cc4 100644 --- a/include/swift/Serialization/Validation.h +++ b/include/swift/Serialization/Validation.h @@ -111,10 +111,7 @@ struct ValidationInfo { class ExtendedValidationInfo { SmallVector ExtraClangImporterOpts; - SmallVector PluginSearchPaths; - SmallVector ExternalPluginSearchPaths; - SmallVector CompilerPluginLibraryPaths; - SmallVector CompilerPluginExecutablePaths; + SmallVector, 2> PluginSearchOptions; std::string SDKPath; StringRef ModuleABIName; @@ -149,32 +146,11 @@ class ExtendedValidationInfo { ExtraClangImporterOpts.push_back(option); } - ArrayRef getPluginSearchPaths() const { - return PluginSearchPaths; + ArrayRef> getPluginSearchOptions() const { + return PluginSearchOptions; } - void addPluginSearchPath(StringRef path) { - PluginSearchPaths.push_back(path); - } - - ArrayRef getExternalPluginSearchPaths() const { - return ExternalPluginSearchPaths; - } - void addExternalPluginSearchPath(StringRef path) { - ExternalPluginSearchPaths.push_back(path); - } - - ArrayRef getCompilerPluginLibraryPaths() const { - return CompilerPluginLibraryPaths; - } - void addCompilerPluginLibraryPath(StringRef path) { - CompilerPluginLibraryPaths.push_back(path); - } - - ArrayRef getCompilerPluginExecutablePaths() const { - return CompilerPluginExecutablePaths; - } - void addCompilerPluginExecutablePath(StringRef path) { - CompilerPluginExecutablePaths.push_back(path); + void addPluginSearchOption(const std::pair &opt) { + PluginSearchOptions.push_back(opt); } bool isSIB() const { return Bits.IsSIB; } diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp index f96f80fc9647e..a1cfd21092870 100644 --- a/lib/Frontend/Frontend.cpp +++ b/lib/Frontend/Frontend.cpp @@ -209,36 +209,8 @@ SerializationOptions CompilerInvocation::computeSerializationOptions( serializationOpts.ExtraClangOptions = getClangImporterOptions().ExtraArgs; } - // FIXME: Preserve the order of these options. - for (auto &elem : getSearchPathOptions().PluginSearchOpts) { - // '-plugin-path' options. - if (auto *arg = elem.dyn_cast()) { - serializationOpts.PluginSearchPaths.push_back(arg->SearchPath); - continue; - } - - // '-external-plugin-path' options. - if (auto *arg = elem.dyn_cast()) { - serializationOpts.ExternalPluginSearchPaths.push_back( - arg->SearchPath + "#" + arg->ServerPath); - continue; - } - - // '-load-plugin-library' options. - if (auto *arg = elem.dyn_cast()) { - serializationOpts.CompilerPluginLibraryPaths.push_back(arg->LibraryPath); - continue; - } - - // '-load-plugin-executable' options. - if (auto *arg = elem.dyn_cast()) { - std::string optStr = arg->ExecutablePath + "#"; - llvm::interleave( - arg->ModuleNames, [&](auto &name) { optStr += name; }, - [&]() { optStr += ","; }); - serializationOpts.CompilerPluginExecutablePaths.push_back(optStr); - } - } + serializationOpts.PluginSearchOptions = + getSearchPathOptions().PluginSearchOpts; serializationOpts.DisableCrossModuleIncrementalInfo = opts.DisableCrossModuleIncrementalBuild; diff --git a/lib/Serialization/ModuleFileSharedCore.cpp b/lib/Serialization/ModuleFileSharedCore.cpp index d4c325e22c6ea..25a07a36f2288 100644 --- a/lib/Serialization/ModuleFileSharedCore.cpp +++ b/lib/Serialization/ModuleFileSharedCore.cpp @@ -126,18 +126,27 @@ static bool readOptionsBlock(llvm::BitstreamCursor &cursor, case options_block::XCC: extendedInfo.addExtraClangImporterOption(blobData); break; - case options_block::PLUGIN_SEARCH_PATH: - extendedInfo.addPluginSearchPath(blobData); - break; - case options_block::EXTERNAL_SEARCH_PLUGIN_PATH: - extendedInfo.addExternalPluginSearchPath(blobData); - break; - case options_block::COMPILER_PLUGIN_LIBRARY_PATH: - extendedInfo.addCompilerPluginLibraryPath(blobData); - break; - case options_block::COMPILER_PLUGIN_EXECUTABLE_PATH: - extendedInfo.addCompilerPluginExecutablePath(blobData); + case options_block::PLUGIN_SEARCH_OPTION: { + unsigned optKind; + StringRef optStr; + options_block::ResilienceStrategyLayout::readRecord(scratch, optKind); + switch (PluginSearchOptionKind(optKind)) { + case PluginSearchOptionKind::PluginPath: + optStr = "-plugin-path"; + break; + case PluginSearchOptionKind::ExternalPluginPath: + optStr = "-external-plugin-path"; + break; + case PluginSearchOptionKind::LoadPluginLibrary: + optStr = "-load-plugin-library"; + break; + case PluginSearchOptionKind::LoadPluginExecutable: + optStr = "-load-plugin-executable"; + break; + } + extendedInfo.addPluginSearchOption({optStr, blobData}); break; + } case options_block::IS_SIB: bool IsSIB; options_block::IsSIBLayout::readRecord(scratch, IsSIB); diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index 12beebdf5f15a..b8ec1c1c180e9 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -58,7 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0; /// describe what change you made. The content of this comment isn't important; /// it just ensures a conflict if two people change the module format. /// Don't worry about adhering to the 80-column limit for this line. -const uint16_t SWIFTMODULE_VERSION_MINOR = 792; // removed select_value +const uint16_t SWIFTMODULE_VERSION_MINOR = 793; // PluginSearchOption /// A standard hash seed used for all string hashes in a serialized module. /// @@ -651,6 +651,16 @@ enum class MacroIntroducedDeclNameKind : uint8_t { }; using MacroIntroducedDeclNameKindField = BCFixed<4>; +// These IDs must \em not be renumbered or reordered without incrementing +// the module version. +enum class PluginSearchOptionKind : uint8_t { + PluginPath, + ExternalPluginPath, + LoadPluginLibrary, + LoadPluginExecutable, +}; +using PluginSearchOptionKindField = BCFixed<3>; + // Encodes a VersionTuple: // // Major @@ -884,10 +894,7 @@ namespace options_block { IS_CONCURRENCY_CHECKED, MODULE_PACKAGE_NAME, MODULE_EXPORT_AS_NAME, - PLUGIN_SEARCH_PATH, - EXTERNAL_SEARCH_PLUGIN_PATH, - COMPILER_PLUGIN_LIBRARY_PATH, - COMPILER_PLUGIN_EXECUTABLE_PATH, + PLUGIN_SEARCH_OPTION, HAS_CXX_INTEROPERABILITY_ENABLED, }; @@ -901,24 +908,10 @@ namespace options_block { BCBlob // -Xcc flag, as string >; - using PluginSearchPathLayout = BCRecordLayout< - PLUGIN_SEARCH_PATH, - BCBlob // -plugin-path value - >; - - using ExternalPluginSearchPathLayout = BCRecordLayout< - EXTERNAL_SEARCH_PLUGIN_PATH, - BCBlob // -external-plugin-path value - >; - - using CompilerPluginLibraryPathLayout = BCRecordLayout< - COMPILER_PLUGIN_LIBRARY_PATH, - BCBlob // -load-plugin-library value - >; - - using CompilerPluginExecutablePathLayout = BCRecordLayout< - COMPILER_PLUGIN_EXECUTABLE_PATH, - BCBlob // -load-plugin-executable value + using PluginSearchOptionLayout = BCRecordLayout< + PLUGIN_SEARCH_OPTION, + PluginSearchOptionKindField, // kind + BCBlob // option value string >; using IsSIBLayout = BCRecordLayout< diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 8f1758049b6cb..4966a59b39e4f 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -846,10 +846,7 @@ void Serializer::writeBlockInfoBlock() { BLOCK_RECORD(options_block, HAS_CXX_INTEROPERABILITY_ENABLED); BLOCK_RECORD(options_block, MODULE_PACKAGE_NAME); BLOCK_RECORD(options_block, MODULE_EXPORT_AS_NAME); - BLOCK_RECORD(options_block, PLUGIN_SEARCH_PATH); - BLOCK_RECORD(options_block, EXTERNAL_SEARCH_PLUGIN_PATH); - BLOCK_RECORD(options_block, COMPILER_PLUGIN_LIBRARY_PATH); - BLOCK_RECORD(options_block, COMPILER_PLUGIN_EXECUTABLE_PATH); + BLOCK_RECORD(options_block, PLUGIN_SEARCH_OPTION); BLOCK(INPUT_BLOCK); BLOCK_RECORD(input_block, IMPORTED_MODULE); @@ -1138,27 +1135,41 @@ void Serializer::writeHeader(const SerializationOptions &options) { } // Macro plugins - options_block::PluginSearchPathLayout PluginSearchPath(Out); - for (auto Arg : options.PluginSearchPaths) { - PluginSearchPath.emit(ScratchRecord, Arg); - } - - options_block::ExternalPluginSearchPathLayout - ExternalPluginSearchPath(Out); - for (auto Arg : options.ExternalPluginSearchPaths) { - ExternalPluginSearchPath.emit(ScratchRecord, Arg); - } - - options_block::CompilerPluginLibraryPathLayout - CompilerPluginLibraryPath(Out); - for (auto Arg : options.CompilerPluginLibraryPaths) { - CompilerPluginLibraryPath.emit(ScratchRecord, Arg); - } - - options_block::CompilerPluginExecutablePathLayout - CompilerPluginExecutablePath(Out); - for (auto Arg : options.CompilerPluginExecutablePaths) { - CompilerPluginExecutablePath.emit(ScratchRecord, Arg); + options_block::PluginSearchOptionLayout PluginSearchOpt(Out); + for (auto &elem : options.PluginSearchOptions) { + if (auto *opt = elem.dyn_cast()) { + PluginSearchOpt.emit(ScratchRecord, + uint8_t(PluginSearchOptionKind::PluginPath), + opt->SearchPath); + continue; + } + if (auto *opt = + elem.dyn_cast()) { + PluginSearchOpt.emit( + ScratchRecord, + uint8_t(PluginSearchOptionKind::ExternalPluginPath), + opt->SearchPath + "#" + opt->ServerPath); + continue; + } + if (auto *opt = + elem.dyn_cast()) { + PluginSearchOpt.emit( + ScratchRecord, + uint8_t(PluginSearchOptionKind::LoadPluginLibrary), + opt->LibraryPath); + continue; + } + if (auto *opt = + elem.dyn_cast()) { + std::string optStr = opt->ExecutablePath + "#"; + llvm::interleave( + opt->ModuleNames, [&](auto &name) { optStr += name; }, + [&]() { optStr += ","; }); + PluginSearchOpt.emit( + ScratchRecord, + uint8_t(PluginSearchOptionKind::LoadPluginExecutable), optStr); + continue; + } } } } diff --git a/test/Macros/serialize_plugin_search_paths.swift b/test/Macros/serialize_plugin_search_paths.swift index ef9c5c8d7ee88..cd4b53fc4725f 100644 --- a/test/Macros/serialize_plugin_search_paths.swift +++ b/test/Macros/serialize_plugin_search_paths.swift @@ -11,10 +11,10 @@ // RUN: -load-plugin-executable %t/mock-plugin#TestPlugin // RUN: %lldb-moduleimport-test -verbose -dump-module %t/a.out | %FileCheck %s -// CHECK: - Macro Search Paths: -// CHECK: -plugin-path: {{.*}}plugins -// CHECK: -plugin-path: {{.*}}plugins -// CHECK: -plugin-path: {{.*}}plugins -// CHECK: -external-plugin-path: {{.*}}plugins#{{.*}}swift-plugin-server -// CHECK: -load-plugin-library: {{.*}}MacroDefinition.{{dylib|so|dll}} -// CHECK: -load-plugin-executable: {{.*}}mock-plugin#TestPlugin +// CHECK: - Plugin Search Options: +// CHECK: -plugin-path {{.*}}plugins +// CHECK: -external-plugin-path {{.*}}plugins#{{.*}}swift-plugin-server +// CHECK: -load-plugin-library {{.*}}MacroDefinition.{{dylib|so|dll}} +// CHECK: -load-plugin-executable {{.*}}mock-plugin#TestPlugin +// CHECK: -plugin-path {{.*}}plugins +// CHECK: -plugin-path {{.*}}plugins diff --git a/tools/lldb-moduleimport-test/lldb-moduleimport-test.cpp b/tools/lldb-moduleimport-test/lldb-moduleimport-test.cpp index 6d9314b3ecd3a..648d2fb52ad80 100644 --- a/tools/lldb-moduleimport-test/lldb-moduleimport-test.cpp +++ b/tools/lldb-moduleimport-test/lldb-moduleimport-test.cpp @@ -89,15 +89,10 @@ static bool validateModule( llvm::outs() << ", system=" << (searchPath.IsSystem ? "true" : "false") << "\n"; } - llvm::outs() << "- Macro Search Paths:\n"; - for (auto path : extendedInfo.getPluginSearchPaths()) - llvm::outs() << " -plugin-path: " << path << "\n"; - for (auto path : extendedInfo.getExternalPluginSearchPaths()) - llvm::outs() << " -external-plugin-path: " << path << "\n"; - for (auto path : extendedInfo.getCompilerPluginLibraryPaths()) - llvm::outs() << " -load-plugin-library: " << path << "\n"; - for (auto path : extendedInfo.getCompilerPluginExecutablePaths()) - llvm::outs() << " -load-plugin-executable: " << path << "\n"; + llvm::outs() << "- Plugin Search Options:\n"; + for (auto opt : extendedInfo.getPluginSearchOptions()) { + llvm::outs() << " " << opt.first << " " << opt.second << "\n"; + } } return true; From fc7ecc8f6734870c368701f7830e8c439ab9a018 Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Fri, 16 Jun 2023 11:54:51 +0900 Subject: [PATCH 18/41] [Distributed] Harden typechecker against completely empty DAS types --- lib/AST/ASTContext.cpp | 18 ++++++++++++++++++ ...tributed_imcomplete_system_dont_crash.swift | 8 ++++++++ 2 files changed, 26 insertions(+) diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 93c8f0f0959e4..2f1c6e4e624f3 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -1397,6 +1397,9 @@ FuncDecl *ASTContext::getMakeInvocationEncoderOnDistributedActorSystem( FuncDecl * ASTContext::getRecordGenericSubstitutionOnDistributedInvocationEncoder( NominalTypeDecl *nominal) const { + if (!nominal) + return nullptr; + for (auto result : nominal->lookupDirect(Id_recordGenericSubstitution)) { auto *func = dyn_cast(result); if (func && @@ -1410,6 +1413,9 @@ ASTContext::getRecordGenericSubstitutionOnDistributedInvocationEncoder( AbstractFunctionDecl *ASTContext::getRecordArgumentOnDistributedInvocationEncoder( NominalTypeDecl *nominal) const { + if (!nominal) + return nullptr; + return evaluateOrDefault( nominal->getASTContext().evaluator, GetDistributedTargetInvocationEncoderRecordArgumentFunctionRequest{nominal}, @@ -1418,6 +1424,9 @@ AbstractFunctionDecl *ASTContext::getRecordArgumentOnDistributedInvocationEncode AbstractFunctionDecl *ASTContext::getRecordReturnTypeOnDistributedInvocationEncoder( NominalTypeDecl *nominal) const { + if (!nominal) + return nullptr; + return evaluateOrDefault( nominal->getASTContext().evaluator, GetDistributedTargetInvocationEncoderRecordReturnTypeFunctionRequest{nominal}, @@ -1426,6 +1435,9 @@ AbstractFunctionDecl *ASTContext::getRecordReturnTypeOnDistributedInvocationEnco AbstractFunctionDecl *ASTContext::getRecordErrorTypeOnDistributedInvocationEncoder( NominalTypeDecl *nominal) const { + if (!nominal) + return nullptr; + return evaluateOrDefault( nominal->getASTContext().evaluator, GetDistributedTargetInvocationEncoderRecordErrorTypeFunctionRequest{nominal}, @@ -1434,6 +1446,9 @@ AbstractFunctionDecl *ASTContext::getRecordErrorTypeOnDistributedInvocationEncod AbstractFunctionDecl *ASTContext::getDecodeNextArgumentOnDistributedInvocationDecoder( NominalTypeDecl *nominal) const { + if (!nominal) + return nullptr; + return evaluateOrDefault( nominal->getASTContext().evaluator, GetDistributedTargetInvocationDecoderDecodeNextArgumentFunctionRequest{nominal}, @@ -1442,6 +1457,9 @@ AbstractFunctionDecl *ASTContext::getDecodeNextArgumentOnDistributedInvocationDe AbstractFunctionDecl *ASTContext::getOnReturnOnDistributedTargetInvocationResultHandler( NominalTypeDecl *nominal) const { + if (!nominal) + return nullptr; + return evaluateOrDefault( nominal->getASTContext().evaluator, GetDistributedTargetInvocationResultHandlerOnReturnFunctionRequest{nominal}, diff --git a/test/Distributed/distributed_imcomplete_system_dont_crash.swift b/test/Distributed/distributed_imcomplete_system_dont_crash.swift index a2cc7d2ca3772..e4f5d3e7f9dce 100644 --- a/test/Distributed/distributed_imcomplete_system_dont_crash.swift +++ b/test/Distributed/distributed_imcomplete_system_dont_crash.swift @@ -36,4 +36,12 @@ public final class CompletelyHollowActorSystem: DistributedActorSystem { // expected-error@-1{{type 'CompletelyHollowActorSystem.ResultHandler' does not conform to protocol 'DistributedTargetInvocationResultHandler'}} } +} + +public final class CompletelyHollowActorSystem_NotEvenTypes: DistributedActorSystem { + // expected-error@-1{{type 'CompletelyHollowActorSystem_NotEvenTypes' does not conform to protocol 'DistributedActorSystem'}} + // expected-error@-2{{class 'CompletelyHollowActorSystem_NotEvenTypes' is missing witness for protocol requirement 'remoteCallVoid'}} + // expected-error@-3{{class 'CompletelyHollowActorSystem_NotEvenTypes' is missing witness for protocol requirement 'remoteCall'}} + // expected-note@-4{{protocol 'DistributedActorSystem' requires function 'remoteCall' with signature:}} + // expected-note@-5{{protocol 'DistributedActorSystem' requires function 'remoteCallVoid' with signature:}} } \ No newline at end of file From 874ba0868bd99b7d90b370660eb911389c9430ac Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Thu, 15 Jun 2023 18:13:33 -0700 Subject: [PATCH 19/41] SILDebugScopes: Don't ignore ConditionalClauseInitializerScope. ConditionalClauseInitializerScope often create redundant scopes, however, they are needed to correctly represent the scopes in an expression such as: if case .something(let foo), let foo = foo. This patch changes SILGen to lower them 1:1 from ASTScopes. rdar://110841130 --- include/swift/AST/ASTScope.h | 1 - test/DebugInfo/case-scope3.swift | 22 ++++++++++++++++++++++ test/DebugInfo/guard-let-scope.swift | 8 +++++--- test/DebugInfo/guard-let-scope3.swift | 15 +++++++++------ test/DebugInfo/if-let-scope.swift | 8 +++++--- 5 files changed, 41 insertions(+), 13 deletions(-) create mode 100644 test/DebugInfo/case-scope3.swift diff --git a/include/swift/AST/ASTScope.h b/include/swift/AST/ASTScope.h index 3411bed70fbf9..1b9e0dcdc8313 100644 --- a/include/swift/AST/ASTScope.h +++ b/include/swift/AST/ASTScope.h @@ -990,7 +990,6 @@ class ConditionalClauseInitializerScope final : public ASTScopeImpl { SourceRange getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; std::string getClassName() const override; - bool ignoreInDebugInfo() const override { return true; } private: void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); diff --git a/test/DebugInfo/case-scope3.swift b/test/DebugInfo/case-scope3.swift new file mode 100644 index 0000000000000..0055f1089e3db --- /dev/null +++ b/test/DebugInfo/case-scope3.swift @@ -0,0 +1,22 @@ +// RUN: %target-swift-frontend -module-name a -parse-as-library -emit-sil -g %s | %FileCheck %s + +enum E { +case integerValue(Int?) +} + +func getE() -> E? { return .integerValue(0) } + +func f() -> Int { + if case .integerValue(let nextValue) = getE(), let nextValue = nextValue { +// CHECK: sil_scope [[F:[0-9]+]] { loc "{{.*}}":9:6 parent @$s1a1fSiyF +// CHECK: sil_scope [[S0:[0-9]+]] { loc "{{.*}}":10:5 parent [[F]] } +// CHECK: sil_scope [[S1:[0-9]+]] { loc "{{.*}}":10:44 parent [[S0]] } +// CHECK: sil_scope [[S2:[0-9]+]] { loc "{{.*}}":10:44 parent [[S0]] } +// CHECK: sil_scope [[S3:[0-9]+]] { loc "{{.*}}":10:68 parent [[S2]] } +// CHECK: sil_scope [[S4:[0-9]+]] { loc "{{.*}}":10:78 parent [[S3]] } +// CHECK: debug_value {{.*}}: $Optional, let, name "nextValue", {{.*}}:10:31, scope [[S0]] +// CHECK: debug_value {{.*}}: $Int, let, name "nextValue", {{.*}}:10:56, scope [[S2]] + return nextValue + } + return 0 +} diff --git a/test/DebugInfo/guard-let-scope.swift b/test/DebugInfo/guard-let-scope.swift index 797f08f0b97f6..646568f4c56db 100644 --- a/test/DebugInfo/guard-let-scope.swift +++ b/test/DebugInfo/guard-let-scope.swift @@ -10,12 +10,14 @@ func f(c: AnyObject??) { // CHECK: sil_scope [[S5:[0-9]+]] { {{.*}} parent [[S3]] } // CHECK: sil_scope [[S6:[0-9]+]] { loc "{{.*}}":7:3 parent [[S5]] } // CHECK: sil_scope [[S7:[0-9]+]] { loc "{{.*}}":7:17 parent [[S6]] } - // CHECK: sil_scope [[S8:[0-9]+]] { loc "{{.*}}":7:28 parent [[S7]] } + // CHECK: sil_scope [[S8:[0-9]+]] { loc "{{.*}}":7:17 parent [[S6]] } + // CHECK: sil_scope [[S9:[0-9]+]] { loc "{{.*}}":7:28 parent [[S8]] } + // CHECK: sil_scope [[S10:[0-9]+]] { loc "{{.*}}":7:28 parent [[S8]] } // CHECK: debug_value %{{.*}} : $Optional>, let, name "x"{{.*}} scope [[S5]] - // CHECK: debug_value %{{.*}} : $Optional, let, name "x", {{.*}} scope [[S7]] + // CHECK: debug_value %{{.*}} : $Optional, let, name "x", {{.*}} scope [[S6]] // CHECK: debug_value %{{.*}} : $AnyObject, let, name "x", {{.*}} scope [[S8]] fatalError() } - // CHECK: function_ref {{.*3use.*}} scope [[S8]] + // CHECK: function_ref {{.*3use.*}} scope [[S10]] use(x) } diff --git a/test/DebugInfo/guard-let-scope3.swift b/test/DebugInfo/guard-let-scope3.swift index f023a3901c069..d5af36b1d9898 100644 --- a/test/DebugInfo/guard-let-scope3.swift +++ b/test/DebugInfo/guard-let-scope3.swift @@ -7,13 +7,16 @@ public class S { private var c = [Int : C?]() public func f(_ i: Int) throws -> C { guard let x = c[i], let x else { - // CHECK: sil_scope [[P:[0-9]+]] { loc "{{.*}}":[[@LINE-1]]:5 - // CHECK: sil_scope [[X1:[0-9]+]] { loc "{{.*}}":[[@LINE-2]]:19 parent [[P]] - // CHECK: sil_scope [[X2:[0-9]+]] { loc "{{.*}}":[[@LINE-3]]:29 parent [[X1]] - // CHECK: sil_scope [[GUARD:[0-9]+]] { loc "{{.*}}":[[@LINE-4]]:36 parent [[P]] - // CHECK: debug_value {{.*}} : $Optional, let, name "x", {{.*}}, scope [[X1]] + // CHECK: sil_scope [[P:[0-9]+]] { loc "{{.*}}":9:5 + // CHECK: sil_scope [[X1_:[0-9]+]] { loc "{{.*}}":9:19 parent [[P]] + // CHECK: sil_scope [[X1:[0-9]+]] { loc "{{.*}}":9:19 parent [[P]] + // CHECK: sil_scope [[X2:[0-9]+]] { loc "{{.*}}":9:29 parent [[X1]] + // CHECK: sil_scope [[X2_:[0-9]+]] { loc "{{.*}}":9:29 parent [[X1]] + // CHECK: sil_scope [[GUARD:[0-9]+]] { loc "{{.*}}":9:36 parent [[P]] + // CHECK: debug_value {{.*}} : $Optional, let, name "x", {{.*}}, scope [[P]] // CHECK: debug_value {{.*}} : $C, let, name "x", {{.*}}, scope [[X2]] - // CHECK-NEXT: scope [[X2]] + // FIXME: This source location & scope are a little wild. + // CHECK-NEXT: strong_retain{{.*}}:[[@LINE+4]]:12, scope [[X2_]] throw MyError() // CHECK: function_ref {{.*}}MyError{{.*}}:[[@LINE-1]]:13, scope [[GUARD]] } diff --git a/test/DebugInfo/if-let-scope.swift b/test/DebugInfo/if-let-scope.swift index 452464b1a9f18..0672fc49e6b5e 100644 --- a/test/DebugInfo/if-let-scope.swift +++ b/test/DebugInfo/if-let-scope.swift @@ -1,10 +1,12 @@ // RUN: %target-swift-frontend -g -emit-sil %s -parse-as-library -module-name a | %FileCheck %s func use(_ t: T) {} public func f(value: String?) { - // CHECK: sil_scope [[S0:[0-9]+]] { loc "{{.*}}":[[@LINE-1]]:13 + // CHECK: sil_scope [[S0:[0-9]+]] { loc "{{.*}}":3:13 if let value, let value = Int(value) { - // CHECK: sil_scope [[S1:[0-9]+]] { loc "{{.*}}":[[@LINE-1]]:10 - // CHECK: sil_scope [[S2:[0-9]+]] { loc "{{.*}}":[[@LINE-2]]:29 parent [[S1]] } + // CHECK: sil_scope [[S1:[0-9]+]] { loc "{{.*}}":5:10 + // CHECK: sil_scope [[S2:[0-9]+]] { loc "{{.*}}":5:10 + // CHECK: sil_scope [[S3:[0-9]+]] { loc "{{.*}}":5:29 parent [[S2]] } + // CHECK: sil_scope [[S4:[0-9]+]] { loc "{{.*}}":5:29 parent [[S2]] } // CHECK: debug_value {{.*}} : $Optional, let, name "value", {{.*}}, scope [[S0]] // CHECK: debug_value {{.*}} : $String, let, name "value", {{.*}}, scope [[S1]] // CHECK: debug_value {{.*}} : $Int, let, name "value", {{.*}}, scope [[S2]] From 9b6904498e7ecf9dfd4587bede514dd5c39f8147 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Fri, 16 Jun 2023 07:36:01 -0700 Subject: [PATCH 20/41] [TypeLowering] Move-only types are lexical. Vars of such types should be given lexical `alloc_stack`s by `AllocBoxToStack` which requires that the `alloc_box` insts formed for them have an associated borrow scope which in turn requires that type lowering for move only structs and enums have their lexical bits set. rdar://110901430 --- lib/SIL/IR/TypeLowering.cpp | 2 + .../UtilityPasses/UnitTestRunner.cpp | 15 ++++ test/SIL/type_lowering_unit.sil | 18 +++++ test/SILGen/discard.swift | 4 +- test/SILGen/moveonly.swift | 63 ++++++++++------ test/SILGen/moveonly_deinits.swift | 12 ++-- test/SILGen/moveonly_enum_literal.swift | 3 +- test/SILGen/moveonly_escaping_closure.swift | 72 +++++++++++-------- 8 files changed, 133 insertions(+), 56 deletions(-) create mode 100644 test/SIL/type_lowering_unit.sil diff --git a/lib/SIL/IR/TypeLowering.cpp b/lib/SIL/IR/TypeLowering.cpp index 8ea1c2000ef79..2697129bbfa57 100644 --- a/lib/SIL/IR/TypeLowering.cpp +++ b/lib/SIL/IR/TypeLowering.cpp @@ -2394,6 +2394,7 @@ namespace { if (D->isMoveOnly()) { properties.setNonTrivial(); + properties.setLexical(IsLexical); if (properties.isAddressOnly()) return handleMoveOnlyAddressOnly(structType, properties); return new (TC) MoveOnlyLoadableStructTypeLowering( @@ -2475,6 +2476,7 @@ namespace { if (D->isMoveOnly()) { properties.setNonTrivial(); + properties.setLexical(IsLexical); if (properties.isAddressOnly()) return handleMoveOnlyAddressOnly(enumType, properties); return new (TC) diff --git a/lib/SILOptimizer/UtilityPasses/UnitTestRunner.cpp b/lib/SILOptimizer/UtilityPasses/UnitTestRunner.cpp index d3a2808d11379..ebf9a35bdd8e6 100644 --- a/lib/SILOptimizer/UtilityPasses/UnitTestRunner.cpp +++ b/lib/SILOptimizer/UtilityPasses/UnitTestRunner.cpp @@ -89,6 +89,7 @@ #include "swift/SILOptimizer/Utils/InstructionDeleter.h" #include "swift/SILOptimizer/Utils/ParseTestSpecification.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" #include #include @@ -287,6 +288,19 @@ struct OwnershipUtilsHasPointerEscape : UnitTest { } }; +// Arguments: +// - value: whose type will be printed +// Dumps: +// - the type lowering of the type +struct PrintTypeLowering : UnitTest { + PrintTypeLowering(UnitTestRunner *pass) : UnitTest(pass) {} + void invoke(Arguments &arguments) override { + auto value = arguments.takeValue(); + auto ty = value->getType(); + getFunction()->getTypeLowering(ty).print(llvm::dbgs()); + } +}; + //===----------------------------------------------------------------------===// // MARK: OSSA Lifetime Unit Tests //===----------------------------------------------------------------------===// @@ -899,6 +913,7 @@ void UnitTestRunner::withTest(StringRef name, Doit doit) { ADD_UNIT_TEST_SUBCLASS("find-enclosing-defs", FindEnclosingDefsTest) ADD_UNIT_TEST_SUBCLASS("function-get-self-argument-index", FunctionGetSelfArgumentIndex) ADD_UNIT_TEST_SUBCLASS("has-pointer-escape", OwnershipUtilsHasPointerEscape) + ADD_UNIT_TEST_SUBCLASS("print-type-lowering", PrintTypeLowering) ADD_UNIT_TEST_SUBCLASS("interior-liveness", InteriorLivenessTest) ADD_UNIT_TEST_SUBCLASS("is-deinit-barrier", IsDeinitBarrierTest) ADD_UNIT_TEST_SUBCLASS("is-lexical", IsLexicalTest) diff --git a/test/SIL/type_lowering_unit.sil b/test/SIL/type_lowering_unit.sil new file mode 100644 index 0000000000000..23e1ba35bbf64 --- /dev/null +++ b/test/SIL/type_lowering_unit.sil @@ -0,0 +1,18 @@ +// RUN: %target-sil-opt -unit-test-runner %s -o /dev/null 2>&1 | %FileCheck %s + +sil_stage raw + +import Builtin + +struct S : ~Copyable {} + +// CHECK-LABEL: begin {{.*}} print-type-lowering with: @argument[0] +// CHECK: isLexical: true +// CHECK-LABEL: end {{.*}} print-type-lowering with: @argument[0] +sil [ossa] @move_only_argument : $@convention(thin) (@owned S) -> () { +bb0(%0 : @owned $S): + test_specification "print-type-lowering @argument[0]" + destroy_value %0 : $S + %retval = tuple () + return %retval : $() +} diff --git a/test/SILGen/discard.swift b/test/SILGen/discard.swift index abb4ba5d8a5ad..17a2e5a17360a 100644 --- a/test/SILGen/discard.swift +++ b/test/SILGen/discard.swift @@ -89,7 +89,8 @@ func invokedDeinit() {} // CHECK-LABEL: sil hidden [ossa] @$s4test11PointerTreeV10tryDestroy9doDiscardySb_tKF : $@convention(method) (Bool, @owned PointerTree) -> @error any Error { // CHECK: bb0{{.*}}: // CHECK: [[SELF_BOX:%.*]] = alloc_box ${ var PointerTree }, var, name "self" -// CHECK: [[SELF_PTR:%.*]] = project_box [[SELF_BOX]] : ${ var PointerTree }, 0 +// CHECK: [[SELF_BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[SELF_BOX]] +// CHECK: [[SELF_PTR:%.*]] = project_box [[SELF_BOX_LIFETIME]] : ${ var PointerTree }, 0 // .. skip to the conditional test .. // CHECK: [[SHOULD_FORGET:%.*]] = struct_extract {{.*}} : $Bool, #Bool._value // CHECK: cond_br [[SHOULD_FORGET]], bb1, bb2 @@ -107,6 +108,7 @@ func invokedDeinit() {} // CHECK: br bb3 // // CHECK: bb3: +// CHECK: end_borrow [[SELF_BOX_LIFETIME]] // CHECK: destroy_value [[SELF_BOX]] : ${ var PointerTree } // CHECK: throw // CHECK: } // end sil function diff --git a/test/SILGen/moveonly.swift b/test/SILGen/moveonly.swift index e25375482eb4e..a68c83106e85a 100644 --- a/test/SILGen/moveonly.swift +++ b/test/SILGen/moveonly.swift @@ -933,7 +933,8 @@ struct EmptyStruct { // CHECK-LABEL: sil hidden [ossa] @$s8moveonly11EmptyStructVACycfC : $@convention(method) (@thin EmptyStruct.Type) -> @owned EmptyStruct { // CHECK: [[BOX:%.*]] = alloc_box ${ var EmptyStruct }, var, name "self" // CHECK: [[MARKED_UNINIT:%.*]] = mark_uninitialized [rootself] [[BOX]] - // CHECK: [[PROJECT:%.*]] = project_box [[MARKED_UNINIT]] + // CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[MARKED_UNINIT]] + // CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // CHECK: [[STRUCT:%.*]] = struct $EmptyStruct () // CHECK: store [[STRUCT]] to [init] [[PROJECT]] // CHECK: [[MV_CHECK:%.*]] = mark_must_check [assignable_but_not_consumable] [[PROJECT]] @@ -1039,7 +1040,8 @@ public struct LoadableSubscriptGetOnlyTester : ~Copyable { // CHECK-LABEL: sil [ossa] @$s8moveonly047testSubscriptGetOnly_BaseLoadable_ResultAddressE4_VaryyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box $ -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // // The get call // CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJECT]] @@ -1077,7 +1079,8 @@ public func testSubscriptGetOnly_BaseLoadable_ResultAddressOnly_Var() { // CHECK-LABEL: sil [ossa] @$s8moveonly047testSubscriptGetOnly_BaseLoadable_ResultAddressE4_LetyyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box $ -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // // The get call // CHECK: [[MARK:%.*]] = mark_must_check [no_consume_or_assign] [[PROJECT]] @@ -1140,7 +1143,8 @@ public struct LoadableSubscriptGetOnlyTesterNonCopyableStructParent : ~Copyable // CHECK-LABEL: sil [ossa] @$s8moveonly077testSubscriptGetOnlyThroughNonCopyableParentStruct_BaseLoadable_ResultAddressE4_VaryyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box $ -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // // The first get call // CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJECT]] @@ -1181,7 +1185,8 @@ public func testSubscriptGetOnlyThroughNonCopyableParentStruct_BaseLoadable_Resu // CHECK-LABEL: sil [ossa] @$s8moveonly077testSubscriptGetOnlyThroughNonCopyableParentStruct_BaseLoadable_ResultAddressE4_LetyyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box ${ let L -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // // CHECK: [[MARK:%.*]] = mark_must_check [no_consume_or_assign] [[PROJECT]] // CHECK: [[LOAD:%.*]] = load_borrow [[MARK]] @@ -1350,7 +1355,8 @@ public struct LoadableSubscriptGetSetTester : ~Copyable { // CHECK-LABEL: sil [ossa] @$s8moveonly54testSubscriptGetSet_BaseLoadable_ResultAddressOnly_VaryyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box $ -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // // The get call // CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJECT]] @@ -1396,7 +1402,8 @@ public func testSubscriptGetSet_BaseLoadable_ResultAddressOnly_Var() { // CHECK-LABEL: sil [ossa] @$s8moveonly54testSubscriptGetSet_BaseLoadable_ResultAddressOnly_LetyyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box $ -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // // The get call // CHECK: [[MARK:%.*]] = mark_must_check [no_consume_or_assign] [[PROJECT]] @@ -1507,7 +1514,8 @@ public struct LoadableSubscriptGetSetTesterNonCopyableStructParent : ~Copyable { // CHECK-LABEL: sil [ossa] @$s8moveonly84testSubscriptGetSetThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_VaryyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box $ -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // // The first get call // CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJECT]] @@ -1561,7 +1569,8 @@ public func testSubscriptGetSetThroughNonCopyableParentStruct_BaseLoadable_Resul // CHECK-LABEL: sil [ossa] @$s8moveonly84testSubscriptGetSetThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_LetyyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box ${ let L -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // // CHECK: [[MARK:%.*]] = mark_must_check [no_consume_or_assign] [[PROJECT]] // CHECK: [[LOAD:%.*]] = load_borrow [[MARK]] @@ -1819,7 +1828,8 @@ public struct LoadableSubscriptReadSetTester : ~Copyable { // CHECK-LABEL: sil [ossa] @$s8moveonly55testSubscriptReadSet_BaseLoadable_ResultAddressOnly_VaryyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box $ -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // // The read call // CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJECT]] @@ -1865,7 +1875,8 @@ public func testSubscriptReadSet_BaseLoadable_ResultAddressOnly_Var() { // CHECK-LABEL: sil [ossa] @$s8moveonly55testSubscriptReadSet_BaseLoadable_ResultAddressOnly_LetyyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box $ -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // // The get call // CHECK: [[MARK:%.*]] = mark_must_check [no_consume_or_assign] [[PROJECT]] @@ -1979,7 +1990,8 @@ public struct LoadableSubscriptReadSetTesterNonCopyableStructParent : ~Copyable // CHECK-LABEL: sil [ossa] @$s8moveonly85testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_VaryyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box $ -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // // The first get call // CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJECT]] @@ -2031,7 +2043,8 @@ public func testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_Resu // CHECK-LABEL: sil [ossa] @$s8moveonly85testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_LetyyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box ${ let L -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // // CHECK: [[MARK:%.*]] = mark_must_check [no_consume_or_assign] [[PROJECT]] // CHECK: [[LOAD:%.*]] = load_borrow [[MARK]] @@ -2285,7 +2298,8 @@ public struct LoadableSubscriptReadModifyTester : ~Copyable { // CHECK-LABEL: sil [ossa] @$s8moveonly58testSubscriptReadModify_BaseLoadable_ResultAddressOnly_VaryyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box $ -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // // The read call // CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJECT]] @@ -2328,7 +2342,8 @@ public func testSubscriptReadModify_BaseLoadable_ResultAddressOnly_Var() { // CHECK-LABEL: sil [ossa] @$s8moveonly58testSubscriptReadModify_BaseLoadable_ResultAddressOnly_LetyyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box $ -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // // The get call // CHECK: [[MARK:%.*]] = mark_must_check [no_consume_or_assign] [[PROJECT]] @@ -2431,7 +2446,8 @@ public struct LoadableSubscriptReadModifyTesterNonCopyableStructParent : ~Copyab // CHECK-LABEL: sil [ossa] @$s8moveonly88testSubscriptReadModifyThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_VaryyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box $ -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // // The first get call // CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJECT]] @@ -2477,7 +2493,8 @@ public func testSubscriptReadModifyThroughNonCopyableParentStruct_BaseLoadable_R // CHECK-LABEL: sil [ossa] @$s8moveonly88testSubscriptReadModifyThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_LetyyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box ${ let L -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // // CHECK: [[MARK:%.*]] = mark_must_check [no_consume_or_assign] [[PROJECT]] // CHECK: [[LOAD:%.*]] = load_borrow [[MARK]] @@ -2699,7 +2716,8 @@ public struct LoadableSubscriptGetModifyTester : ~Copyable { // CHECK-LABEL: sil [ossa] @$s8moveonly57testSubscriptGetModify_BaseLoadable_ResultAddressOnly_VaryyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box $ -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // // The get call // CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJECT]] @@ -2743,7 +2761,8 @@ public func testSubscriptGetModify_BaseLoadable_ResultAddressOnly_Var() { // CHECK-LABEL: sil [ossa] @$s8moveonly57testSubscriptGetModify_BaseLoadable_ResultAddressOnly_LetyyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box $ -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // // The get call // CHECK: [[MARK:%.*]] = mark_must_check [no_consume_or_assign] [[PROJECT]] @@ -2850,7 +2869,8 @@ public struct LoadableSubscriptGetModifyTesterNonCopyableStructParent : ~Copyabl // CHECK-LABEL: sil [ossa] @$s8moveonly87testSubscriptGetModifyThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_VaryyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box $ -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // // The first get call // CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJECT]] @@ -2900,7 +2920,8 @@ public func testSubscriptGetModifyThroughNonCopyableParentStruct_BaseLoadable_Re // CHECK-LABEL: sil [ossa] @$s8moveonly87testSubscriptGetModifyThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_LetyyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box ${ let L -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // // CHECK: [[MARK:%.*]] = mark_must_check [no_consume_or_assign] [[PROJECT]] // CHECK: [[LOAD:%.*]] = load_borrow [[MARK]] diff --git a/test/SILGen/moveonly_deinits.swift b/test/SILGen/moveonly_deinits.swift index 73a7353966af0..88a6fd778ef20 100644 --- a/test/SILGen/moveonly_deinits.swift +++ b/test/SILGen/moveonly_deinits.swift @@ -83,7 +83,8 @@ var value: Bool { false } // SILGEN-LABEL: sil [ossa] @$s16moveonly_deinits24testIntPairWithoutDeinityyF : $@convention(thin) () -> () { // SILGEN: [[BOX:%.*]] = alloc_box -// SILGEN: [[PROJECT:%.*]] = project_box [[BOX]] +// SILGEN: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// SILGEN: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // SILGEN: cond_br {{%.*}}, bb1, bb2 // // SILGEN: bb1: @@ -132,7 +133,8 @@ public func testIntPairWithoutDeinit() { // SILGEN-LABEL: sil [ossa] @$s16moveonly_deinits21testIntPairWithDeinityyF : $@convention(thin) () -> () { // SILGEN: [[BOX:%.*]] = alloc_box -// SILGEN: [[PROJECT:%.*]] = project_box [[BOX]] +// SILGEN: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// SILGEN: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // SILGEN: cond_br {{%.*}}, bb1, bb2 // // SILGEN: bb1: @@ -343,7 +345,8 @@ func consumeKlassEnumPairWithDeinit(_ x: __owned KlassEnumPairWithDeinit) { } // SILGEN-LABEL: sil [ossa] @$s16moveonly_deinits28testIntEnumPairWithoutDeinityyF : $@convention(thin) () -> () { // SILGEN: [[BOX:%.*]] = alloc_box -// SILGEN: [[PROJECT:%.*]] = project_box [[BOX]] +// SILGEN: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// SILGEN: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // SILGEN: cond_br {{%.*}}, bb1, bb2 // // SILGEN: bb1: @@ -391,7 +394,8 @@ public func testIntEnumPairWithoutDeinit() { // SILGEN-LABEL: sil [ossa] @$s16moveonly_deinits25testIntEnumPairWithDeinityyF : $@convention(thin) () -> () { // SILGEN: [[BOX:%.*]] = alloc_box -// SILGEN: [[PROJECT:%.*]] = project_box [[BOX]] +// SILGEN: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// SILGEN: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // SILGEN: cond_br {{%.*}}, bb1, bb2 // // SILGEN: bb1: diff --git a/test/SILGen/moveonly_enum_literal.swift b/test/SILGen/moveonly_enum_literal.swift index 4d566835f4b83..13555bce43a40 100644 --- a/test/SILGen/moveonly_enum_literal.swift +++ b/test/SILGen/moveonly_enum_literal.swift @@ -16,7 +16,8 @@ var value: Bool { false } // CHECK-LABEL: sil hidden [ossa] @$s21moveonly_enum_literal4testyyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // CHECK: [[VALUE:%.*]] = enum $MoveOnlyIntPair, #MoveOnlyIntPair.lhs!enumelt, // CHECK: store [[VALUE]] to [init] [[PROJECT]] // diff --git a/test/SILGen/moveonly_escaping_closure.swift b/test/SILGen/moveonly_escaping_closure.swift index 1b20481e0147e..3977658feebb9 100644 --- a/test/SILGen/moveonly_escaping_closure.swift +++ b/test/SILGen/moveonly_escaping_closure.swift @@ -24,9 +24,10 @@ func borrowConsumeVal(_ x: borrowing SingleElt, _ y: consuming SingleElt) {} // CHECK-LABEL: sil hidden [ossa] @$s16moveonly_closure27testGlobalClosureCaptureVaryyF : $@convention(thin) () -> () { // CHECK: [[GLOBAL:%.*]] = global_addr @$s16moveonly_closure23globalClosureCaptureVaryycvp // CHECK: [[BOX:%.*]] = alloc_box ${ var SingleElt } -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // CHECK: [[CLOSURE:%.*]] = function_ref @$s16moveonly_closure27testGlobalClosureCaptureVaryyFyycfU_ : $@convention(thin) (@guaranteed { var SingleElt }) -> () -// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX]] +// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX_LIFETIME]] // CHECK: [[PAI:%.*]] = partial_apply [callee_guaranteed] [[CLOSURE]]([[BOX_COPY]]) // CHECK: [[ACCESS:%.*]] = begin_access [modify] [dynamic] [[GLOBAL]] // CHECK: assign [[PAI]] to [[ACCESS]] @@ -84,8 +85,9 @@ func testGlobalClosureCaptureVar() { // CHECK-LABEL: sil hidden [ossa] @$s16moveonly_closure29testLocalLetClosureCaptureVaryyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] -// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] +// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX_LIFETIME]] // CHECK: mark_function_escape [[PROJECT]] // CHECK: [[PAI:%.*]] = partial_apply [callee_guaranteed] {{%.*}}([[BOX_COPY]]) // CHECK: [[BORROW_PAI:%.*]] = begin_borrow [lexical] [[PAI]] @@ -151,8 +153,9 @@ func testLocalLetClosureCaptureVar() { // CHECK-LABEL: sil hidden [ossa] @$s16moveonly_closure026testLocalVarClosureCaptureE0yyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] -// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] +// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX_LIFETIME]] // CHECK: mark_function_escape [[PROJECT]] // CHECK: [[PAI:%.*]] = partial_apply [callee_guaranteed] {{%.*}}([[BOX_COPY]]) // CHECK: } // end sil function '$s16moveonly_closure026testLocalVarClosureCaptureE0yyF' @@ -209,9 +212,10 @@ func testLocalVarClosureCaptureVar() { // CHECK-LABEL: sil hidden [ossa] @$s16moveonly_closure026testInOutVarClosureCaptureF0yyyyczF : $@convention(thin) (@inout @callee_guaranteed () -> ()) -> () { // CHECK: bb0([[F:%.*]] : $*@callee_guaranteed () -> ()): // CHECK: [[BOX:%.*]] = alloc_box ${ var SingleElt } -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // CHECK: [[CLOSURE:%.*]] = function_ref @$s16moveonly_closure026testInOutVarClosureCaptureF0yyyyczFyycfU_ : $@convention(thin) (@guaranteed { var SingleElt }) -> () -// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX]] +// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX_LIFETIME]] // CHECK: [[PAI:%.*]] = partial_apply [callee_guaranteed] [[CLOSURE]]([[BOX_COPY]]) // CHECK: [[ACCESS:%.*]] = begin_access [modify] [unknown] [[F]] // CHECK: assign [[PAI]] to [[ACCESS]] @@ -275,9 +279,10 @@ func testInOutVarClosureCaptureVar(_ f: inout () -> ()) { // CHECK: store [[ARG]] to [init] [[UNWRAP]] // // CHECK: [[BOX:%.*]] = alloc_box ${ var SingleElt } -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // CHECK: [[CLOSURE:%.*]] = function_ref @$s16moveonly_closure36testConsumingEscapeClosureCaptureVaryyyycnFyycfU_ : $@convention(thin) (@guaranteed { var SingleElt }) -// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX]] +// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX_LIFETIME]] // CHECK: mark_function_escape [[PROJECT]] // CHECK: [[PAI:%.*]] = partial_apply [callee_guaranteed] [[CLOSURE]]([[BOX_COPY]]) // CHECK: [[ACCESS:%.*]] = begin_access [modify] [unknown] [[FUNC_PROJECT]] @@ -342,9 +347,10 @@ func testConsumingEscapeClosureCaptureVar(_ f: consuming @escaping () -> ()) { // CHECK-LABEL: sil hidden [ossa] @$s16moveonly_closure27testGlobalClosureCaptureLetyyF : $@convention(thin) () -> () { // CHECK: [[GLOBAL:%.*]] = global_addr @$s16moveonly_closure23globalClosureCaptureLetyycvp // CHECK: [[BOX:%.*]] = alloc_box ${ let SingleElt } -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // CHECK: [[CLOSURE:%.*]] = function_ref @$s16moveonly_closure27testGlobalClosureCaptureLetyyFyycfU_ : $@convention(thin) (@guaranteed { let SingleElt }) -> () -// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX]] +// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX_LIFETIME]] // CHECK: [[PAI:%.*]] = partial_apply [callee_guaranteed] [[CLOSURE]]([[BOX_COPY]]) // CHECK: [[ACCESS:%.*]] = begin_access [modify] [dynamic] [[GLOBAL]] // CHECK: assign [[PAI]] to [[ACCESS]] @@ -388,8 +394,9 @@ func testGlobalClosureCaptureLet() { // CHECK-LABEL: sil hidden [ossa] @$s16moveonly_closure026testLocalLetClosureCaptureE0yyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] -// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] +// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX_LIFETIME]] // CHECK: mark_function_escape [[PROJECT]] // CHECK: [[PAI:%.*]] = partial_apply [callee_guaranteed] {{%.*}}([[BOX_COPY]]) // CHECK: [[BORROW_PAI:%.*]] = begin_borrow [lexical] [[PAI]] @@ -437,8 +444,9 @@ func testLocalLetClosureCaptureLet() { // CHECK-LABEL: sil hidden [ossa] @$s16moveonly_closure29testLocalVarClosureCaptureLetyyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] -// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] +// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX_LIFETIME]] // CHECK: mark_function_escape [[PROJECT]] // CHECK: [[PAI:%.*]] = partial_apply [callee_guaranteed] {{%.*}}([[BOX_COPY]]) // CHECK: } // end sil function '$s16moveonly_closure29testLocalVarClosureCaptureLetyyF' @@ -482,9 +490,10 @@ func testLocalVarClosureCaptureLet() { // CHECK-LABEL: sil hidden [ossa] @$s16moveonly_closure29testInOutVarClosureCaptureLetyyyyczF : $@convention(thin) (@inout @callee_guaranteed () -> ()) -> () { // CHECK: bb0([[F:%.*]] : $*@callee_guaranteed () -> ()): // CHECK: [[BOX:%.*]] = alloc_box ${ let SingleElt } -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // CHECK: [[CLOSURE:%.*]] = function_ref @$s16moveonly_closure29testInOutVarClosureCaptureLetyyyyczFyycfU_ : $@convention(thin) (@guaranteed { let SingleElt }) -> () -// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX]] +// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX_LIFETIME]] // CHECK: [[PAI:%.*]] = partial_apply [callee_guaranteed] [[CLOSURE]]([[BOX_COPY]]) // CHECK: [[ACCESS:%.*]] = begin_access [modify] [unknown] [[F]] // CHECK: assign [[PAI]] to [[ACCESS]] @@ -530,14 +539,15 @@ func testInOutVarClosureCaptureLet(_ f: inout () -> ()) { // CHECK-LABEL: sil hidden [ossa] @$s16moveonly_closure36testConsumingEscapeClosureCaptureLetyyyycnF : $@convention(thin) (@owned @callee_guaranteed () -> ()) -> () { // CHECK: bb0([[ARG:%.*]] : @noImplicitCopy @_eagerMove @owned // CHECK: [[FUNC_BOX:%.*]] = alloc_box ${ var @moveOnly @callee_guaranteed () -> () } -// CHECK: [[FUNC_PROJECT:%.*]] = project_box [[FUNC_BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[FUNC_BOX]] // CHECK: [[UNWRAP:%.*]] = moveonlywrapper_to_copyable_addr [[FUNC_PROJECT]] // CHECK: store [[ARG]] to [init] [[UNWRAP]] // // CHECK: [[BOX:%.*]] = alloc_box ${ let SingleElt } -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // CHECK: [[CLOSURE:%.*]] = function_ref @$s16moveonly_closure36testConsumingEscapeClosureCaptureLetyyyycnFyycfU_ : $@convention(thin) (@guaranteed { let SingleElt }) -// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX]] +// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX_LIFETIME]] // CHECK: mark_function_escape [[PROJECT]] // CHECK: [[PAI:%.*]] = partial_apply [callee_guaranteed] [[CLOSURE]]([[BOX_COPY]]) // CHECK: [[ACCESS:%.*]] = begin_access [modify] [unknown] [[FUNC_PROJECT]] @@ -840,9 +850,10 @@ func testConsumingEscapeClosureCaptureInOut(_ f: consuming @escaping () -> (), _ // CHECK-LABEL: sil hidden [ossa] @$s16moveonly_closure33testGlobalClosureCaptureConsumingyyAA9SingleEltVnF : $@convention(thin) (@owned SingleElt) -> () { // CHECK: [[GLOBAL:%.*]] = global_addr @$s16moveonly_closure29globalClosureCaptureConsumingyycvp // CHECK: [[BOX:%.*]] = alloc_box ${ var SingleElt } -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // CHECK: [[CLOSURE:%.*]] = function_ref @$s16moveonly_closure33testGlobalClosureCaptureConsumingyyAA9SingleEltVnFyycfU_ : $@convention(thin) (@guaranteed { var SingleElt }) -> () -// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX]] +// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX_LIFETIME]] // CHECK: [[PAI:%.*]] = partial_apply [callee_guaranteed] [[CLOSURE]]([[BOX_COPY]]) // CHECK: [[ACCESS:%.*]] = begin_access [modify] [dynamic] [[GLOBAL]] // CHECK: assign [[PAI]] to [[ACCESS]] @@ -898,8 +909,9 @@ func testGlobalClosureCaptureConsuming(_ x: consuming SingleElt) { // CHECK-LABEL: sil hidden [ossa] @$s16moveonly_closure35testLocalLetClosureCaptureConsumingyyAA9SingleEltVnF : $@convention(thin) (@owned SingleElt) -> () { // CHECK: [[BOX:%.*]] = alloc_box -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] -// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] +// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX_LIFETIME]] // CHECK: mark_function_escape [[PROJECT]] // CHECK: [[PAI:%.*]] = partial_apply [callee_guaranteed] {{%.*}}([[BOX_COPY]]) // CHECK: [[BORROW_PAI:%.*]] = begin_borrow [lexical] [[PAI]] @@ -976,8 +988,9 @@ func testLocalLetClosureCaptureConsuming2(_ x: consuming SingleElt) -> (() -> () // CHECK-LABEL: sil hidden [ossa] @$s16moveonly_closure35testLocalVarClosureCaptureConsumingyyAA9SingleEltVnF : $@convention(thin) (@owned SingleElt) -> () { // CHECK: [[BOX:%.*]] = alloc_box -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] -// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] +// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX_LIFETIME]] // CHECK: mark_function_escape [[PROJECT]] // CHECK: [[PAI:%.*]] = partial_apply [callee_guaranteed] {{%.*}}([[BOX_COPY]]) // CHECK: } // end sil function '$s16moveonly_closure35testLocalVarClosureCaptureConsumingyyAA9SingleEltVnF' @@ -1038,9 +1051,10 @@ func testLocalVarClosureCaptureConsuming(_ x: consuming SingleElt) { // CHECK: store [[ARG]] to [init] [[UNWRAP]] // // CHECK: [[BOX:%.*]] = alloc_box ${ var SingleElt } -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // CHECK: [[CLOSURE:%.*]] = function_ref @$s16moveonly_closure033testConsumingEscapeClosureCaptureD0yyyycn_AA9SingleEltVntFyycfU_ : $@convention(thin) (@guaranteed { var SingleElt }) -> () -// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX]] +// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX_LIFETIME]] // CHECK: mark_function_escape [[PROJECT]] // CHECK: [[PAI:%.*]] = partial_apply [callee_guaranteed] [[CLOSURE]]([[BOX_COPY]]) // CHECK: [[ACCESS:%.*]] = begin_access [modify] [unknown] [[FUNC_PROJECT]] From f1a9e8b374bdea640e369bf5f863bbf6ae32c74b Mon Sep 17 00:00:00 2001 From: Arnold Schwaighofer Date: Fri, 16 Jun 2023 07:52:52 -0700 Subject: [PATCH 21/41] Fix tests on arm64e Fix the failures on the oss-swift_tools-RA_stdlib-DA_test-device-non_executable bot. --- test/IRGen/ptrauth-blocks.sil | 3 ++- test/IRGen/ptrauth-class-methods.sil | 3 ++- test/IRGen/ptrauth-classes.sil | 3 ++- test/IRGen/ptrauth-dynamic_replaceable.sil | 3 ++- test/IRGen/ptrauth-dynamic_replaceable_opaque_return.swift | 3 ++- test/IRGen/ptrauth-functions.sil | 3 ++- test/IRGen/ptrauth-global.swift | 6 ++++-- test/IRGen/ptrauth-objc-partial-apply.sil | 3 ++- test/IRGen/ptrauth-objc.swift | 3 ++- test/IRGen/ptrauth-partial-apply.sil | 3 ++- test/IRGen/ptrauth-protocols.sil | 3 ++- test/IRGen/ptrauth-runtime.sil | 3 ++- test/IRGen/ptrauth-value-witnesses.sil | 3 ++- test/IRGen/ptrauth_field_fptr_import.swift | 3 ++- 14 files changed, 30 insertions(+), 15 deletions(-) diff --git a/test/IRGen/ptrauth-blocks.sil b/test/IRGen/ptrauth-blocks.sil index a95d3f372db15..85ac4231e05b0 100644 --- a/test/IRGen/ptrauth-blocks.sil +++ b/test/IRGen/ptrauth-blocks.sil @@ -1,4 +1,5 @@ -// RUN: %swift -swift-version 4 -target arm64e-apple-ios12.0 -parse-stdlib -parse-as-library %s -emit-ir -module-name test -Xcc -Xclang -Xcc -fptrauth-calls | %FileCheck %s --check-prefix=CHECK +// RUN: %swift %use_no_opaque_pointers -swift-version 4 -target arm64e-apple-ios12.0 -parse-stdlib -parse-as-library %s -emit-ir -module-name test -Xcc -Xclang -Xcc -fptrauth-calls | %FileCheck %s --check-prefix=CHECK +// RUN: %swift -swift-version 4 -target arm64e-apple-ios12.0 -parse-stdlib -parse-as-library %s -emit-ir -module-name test -Xcc -Xclang -Xcc -fptrauth-calls // REQUIRES: CPU=arm64e // REQUIRES: OS=ios diff --git a/test/IRGen/ptrauth-class-methods.sil b/test/IRGen/ptrauth-class-methods.sil index 697e535a5050f..da61de7fb4037 100644 --- a/test/IRGen/ptrauth-class-methods.sil +++ b/test/IRGen/ptrauth-class-methods.sil @@ -1,4 +1,5 @@ -// RUN: %swift -swift-version 4 -target arm64e-apple-ios12.0 -parse-stdlib -parse-as-library %s -emit-ir -module-name test -Xcc -Xclang -Xcc -fptrauth-calls | %FileCheck %s --check-prefix=CHECK +// RUN: %swift %use_no_opaque_pointers -swift-version 4 -target arm64e-apple-ios12.0 -parse-stdlib -parse-as-library %s -emit-ir -module-name test -Xcc -Xclang -Xcc -fptrauth-calls | %FileCheck %s --check-prefix=CHECK +// RUN: %swift -swift-version 4 -target arm64e-apple-ios12.0 -parse-stdlib -parse-as-library %s -emit-ir -module-name test -Xcc -Xclang -Xcc -fptrauth-calls // REQUIRES: CPU=arm64e // REQUIRES: OS=ios diff --git a/test/IRGen/ptrauth-classes.sil b/test/IRGen/ptrauth-classes.sil index d4ce0bbeb2876..92ab0086b1135 100644 --- a/test/IRGen/ptrauth-classes.sil +++ b/test/IRGen/ptrauth-classes.sil @@ -1,4 +1,5 @@ -// RUN: %swift -swift-version 4 -target arm64e-apple-ios12.0 -parse-stdlib -parse-as-library %s -emit-ir -module-name test -Xcc -Xclang -Xcc -fptrauth-calls | %FileCheck %s --check-prefix=CHECK +// RUN: %swift %use_no_opaque_pointers -swift-version 4 -target arm64e-apple-ios12.0 -parse-stdlib -parse-as-library %s -emit-ir -module-name test -Xcc -Xclang -Xcc -fptrauth-calls | %FileCheck %s --check-prefix=CHECK +// RUN: %swift -swift-version 4 -target arm64e-apple-ios12.0 -parse-stdlib -parse-as-library %s -emit-ir -module-name test -Xcc -Xclang -Xcc -fptrauth-calls // REQUIRES: CPU=arm64e // REQUIRES: OS=ios diff --git a/test/IRGen/ptrauth-dynamic_replaceable.sil b/test/IRGen/ptrauth-dynamic_replaceable.sil index 7e21c444eb6ff..02c8d88dc9c11 100644 --- a/test/IRGen/ptrauth-dynamic_replaceable.sil +++ b/test/IRGen/ptrauth-dynamic_replaceable.sil @@ -1,4 +1,5 @@ -// RUN: %target-swift-frontend %s -emit-ir -disable-objc-interop -module-name A | %FileCheck %s +// RUN: %target-swift-frontend %use_no_opaque_pointers %s -emit-ir -disable-objc-interop -module-name A | %FileCheck %s +// RUN: %target-swift-frontend %s -emit-ir -disable-objc-interop -module-name A // REQUIRES: objc_interop // REQUIRES: CPU=arm64e diff --git a/test/IRGen/ptrauth-dynamic_replaceable_opaque_return.swift b/test/IRGen/ptrauth-dynamic_replaceable_opaque_return.swift index 1e32842cac907..9064959d589fc 100644 --- a/test/IRGen/ptrauth-dynamic_replaceable_opaque_return.swift +++ b/test/IRGen/ptrauth-dynamic_replaceable_opaque_return.swift @@ -1,4 +1,5 @@ -// RUN: %target-swift-frontend -disable-availability-checking -module-name A -swift-version 5 -primary-file %s -emit-ir | %FileCheck %s +// RUN: %target-swift-frontend %use_no_opaque_pointers -disable-availability-checking -module-name A -swift-version 5 -primary-file %s -emit-ir | %FileCheck %s +// RUN: %target-swift-frontend -disable-availability-checking -module-name A -swift-version 5 -primary-file %s -emit-ir // REQUIRES: CPU=arm64e diff --git a/test/IRGen/ptrauth-functions.sil b/test/IRGen/ptrauth-functions.sil index 80f9e43227584..91ea06859dace 100644 --- a/test/IRGen/ptrauth-functions.sil +++ b/test/IRGen/ptrauth-functions.sil @@ -1,4 +1,5 @@ -// RUN: %swift -swift-version 4 -target arm64e-apple-ios12.0 -parse-stdlib -parse-as-library %s -emit-ir -module-name test -Xcc -Xclang -Xcc -fptrauth-calls | %FileCheck %s --check-prefix=CHECK +// RUN: %swift %use_no_opaque_pointers -swift-version 4 -target arm64e-apple-ios12.0 -parse-stdlib -parse-as-library %s -emit-ir -module-name test -Xcc -Xclang -Xcc -fptrauth-calls | %FileCheck %s --check-prefix=CHECK +// RUN: %swift -swift-version 4 -target arm64e-apple-ios12.0 -parse-stdlib -parse-as-library %s -emit-ir -module-name test -Xcc -Xclang -Xcc -fptrauth-calls // REQUIRES: CPU=arm64e // REQUIRES: OS=ios diff --git a/test/IRGen/ptrauth-global.swift b/test/IRGen/ptrauth-global.swift index ad4f7a415a810..55319713e27ef 100644 --- a/test/IRGen/ptrauth-global.swift +++ b/test/IRGen/ptrauth-global.swift @@ -1,5 +1,7 @@ -// RUN: %swift-frontend -swift-version 4 -target arm64e-apple-ios12.0 -primary-file %s -emit-ir -module-name A | %FileCheck %s --check-prefix=CHECK -// RUN: %swift-frontend -swift-version 4 -target arm64e-apple-ios12.0 %s -primary-file %S/Inputs/ptrauth-global-2.swift -emit-ir -module-name A | %FileCheck %s --check-prefix=CHECK2 +// RUN: %swift-frontend %use_no_opaque_pointers -swift-version 4 -target arm64e-apple-ios12.0 -primary-file %s -emit-ir -module-name A | %FileCheck %s --check-prefix=CHECK +// RUN: %swift-frontend %use_no_opaque_pointers -swift-version 4 -target arm64e-apple-ios12.0 %s -primary-file %S/Inputs/ptrauth-global-2.swift -emit-ir -module-name A | %FileCheck %s --check-prefix=CHECK2 +// RUN: %swift-frontend -swift-version 4 -target arm64e-apple-ios12.0 -primary-file %s -emit-ir -module-name A +// RUN: %swift-frontend -swift-version 4 -target arm64e-apple-ios12.0 %s -primary-file %S/Inputs/ptrauth-global-2.swift -emit-ir -module-name A // REQUIRES: CPU=arm64e // REQUIRES: OS=ios diff --git a/test/IRGen/ptrauth-objc-partial-apply.sil b/test/IRGen/ptrauth-objc-partial-apply.sil index da742d2ffb859..4c96ef548b0e8 100644 --- a/test/IRGen/ptrauth-objc-partial-apply.sil +++ b/test/IRGen/ptrauth-objc-partial-apply.sil @@ -1,4 +1,5 @@ -// RUN: %swift -swift-version 4 -target arm64e-apple-ios12.0 -parse-stdlib -parse-as-library %s -emit-ir -module-name test -Xcc -Xclang -Xcc -fptrauth-calls | %FileCheck %s --check-prefix=CHECK +// RUN: %swift %use_no_opaque_pointers -swift-version 4 -target arm64e-apple-ios12.0 -parse-stdlib -parse-as-library %s -emit-ir -module-name test -Xcc -Xclang -Xcc -fptrauth-calls | %FileCheck %s --check-prefix=CHECK +// RUN: %swift -swift-version 4 -target arm64e-apple-ios12.0 -parse-stdlib -parse-as-library %s -emit-ir -module-name test -Xcc -Xclang -Xcc -fptrauth-calls // REQUIRES: objc_interop // REQUIRES: CPU=arm64e diff --git a/test/IRGen/ptrauth-objc.swift b/test/IRGen/ptrauth-objc.swift index 8393be7bd9fb5..573a73fa4b2e7 100644 --- a/test/IRGen/ptrauth-objc.swift +++ b/test/IRGen/ptrauth-objc.swift @@ -1,4 +1,5 @@ -// RUN: %swift -swift-version 4 -target arm64e-apple-ios12.0 -parse-stdlib -parse-as-library %s -emit-ir -module-name test -Xcc -Xclang -Xcc -fptrauth-calls | %FileCheck %s --check-prefix=CHECK +// RUN: %swift %use_no_opaque_pointers -swift-version 4 -target arm64e-apple-ios12.0 -parse-stdlib -parse-as-library %s -emit-ir -module-name test -Xcc -Xclang -Xcc -fptrauth-calls | %FileCheck %s --check-prefix=CHECK +// RUN: %swift -swift-version 4 -target arm64e-apple-ios12.0 -parse-stdlib -parse-as-library %s -emit-ir -module-name test -Xcc -Xclang -Xcc -fptrauth-calls // REQUIRES: CPU=arm64e // REQUIRES: OS=ios diff --git a/test/IRGen/ptrauth-partial-apply.sil b/test/IRGen/ptrauth-partial-apply.sil index 3f1db37f783e6..cc4ccba7dc76f 100644 --- a/test/IRGen/ptrauth-partial-apply.sil +++ b/test/IRGen/ptrauth-partial-apply.sil @@ -1,4 +1,5 @@ -// RUN: %swift -swift-version 4 -target arm64e-apple-ios12.0 -parse-stdlib -parse-as-library %s -emit-ir -module-name test -Xcc -Xclang -Xcc -fptrauth-calls | %FileCheck %s --check-prefix=CHECK +// RUN: %swift %use_no_opaque_pointers -swift-version 4 -target arm64e-apple-ios12.0 -parse-stdlib -parse-as-library %s -emit-ir -module-name test -Xcc -Xclang -Xcc -fptrauth-calls | %FileCheck %s --check-prefix=CHECK +// RUN: %swift -swift-version 4 -target arm64e-apple-ios12.0 -parse-stdlib -parse-as-library %s -emit-ir -module-name test -Xcc -Xclang -Xcc -fptrauth-calls // REQUIRES: CPU=arm64e // REQUIRES: OS=ios diff --git a/test/IRGen/ptrauth-protocols.sil b/test/IRGen/ptrauth-protocols.sil index c697dc99f5827..088cd54a98a56 100644 --- a/test/IRGen/ptrauth-protocols.sil +++ b/test/IRGen/ptrauth-protocols.sil @@ -1,4 +1,5 @@ -// RUN: %swift -swift-version 5 -target arm64e-apple-ios12.0 -parse-stdlib -parse-as-library %s -emit-ir -module-name test -Xcc -Xclang -Xcc -fptrauth-calls | %FileCheck %s --check-prefix=CHECK +// RUN: %swift %use_no_opaque_pointers -swift-version 5 -target arm64e-apple-ios12.0 -parse-stdlib -parse-as-library %s -emit-ir -module-name test -Xcc -Xclang -Xcc -fptrauth-calls | %FileCheck %s --check-prefix=CHECK +// RUN: %swift -swift-version 5 -target arm64e-apple-ios12.0 -parse-stdlib -parse-as-library %s -emit-ir -module-name test -Xcc -Xclang -Xcc -fptrauth-calls // REQUIRES: CPU=arm64e // REQUIRES: OS=ios diff --git a/test/IRGen/ptrauth-runtime.sil b/test/IRGen/ptrauth-runtime.sil index cb8faa64e5fc4..15be05ee8f683 100644 --- a/test/IRGen/ptrauth-runtime.sil +++ b/test/IRGen/ptrauth-runtime.sil @@ -1,4 +1,5 @@ -// RUN: %swift -swift-version 4 -target arm64e-apple-ios12.0 -parse-stdlib -parse-as-library %s -emit-ir -module-name test | %FileCheck %s --check-prefix=CHECK +// RUN: %swift %use_no_opaque_pointers -swift-version 4 -target arm64e-apple-ios12.0 -parse-stdlib -parse-as-library %s -emit-ir -module-name test | %FileCheck %s --check-prefix=CHECK +// RUN: %swift -swift-version 4 -target arm64e-apple-ios12.0 -parse-stdlib -parse-as-library %s -emit-ir -module-name test // REQUIRES: CPU=arm64e // REQUIRES: OS=ios diff --git a/test/IRGen/ptrauth-value-witnesses.sil b/test/IRGen/ptrauth-value-witnesses.sil index 3ad86a8793815..85f7940751274 100644 --- a/test/IRGen/ptrauth-value-witnesses.sil +++ b/test/IRGen/ptrauth-value-witnesses.sil @@ -1,4 +1,5 @@ -// RUN: %swift -swift-version 4 -target arm64e-apple-ios12.0 -parse-stdlib -parse-as-library %s -emit-ir -module-name test -Xcc -Xclang -Xcc -fptrauth-calls | %FileCheck %s --check-prefix=CHECK +// RUN: %swift %use_no_opaque_pointers -swift-version 4 -target arm64e-apple-ios12.0 -parse-stdlib -parse-as-library %s -emit-ir -module-name test -Xcc -Xclang -Xcc -fptrauth-calls | %FileCheck %s --check-prefix=CHECK +// RUN: %swift %use_no_opaque_pointers -swift-version 4 -target arm64e-apple-ios12.0 -parse-stdlib -parse-as-library %s -emit-ir -module-name test -Xcc -Xclang -Xcc -fptrauth-calls // REQUIRES: CPU=arm64e // REQUIRES: OS=ios diff --git a/test/IRGen/ptrauth_field_fptr_import.swift b/test/IRGen/ptrauth_field_fptr_import.swift index d435ce53292e6..2f8d9fdcff5ae 100644 --- a/test/IRGen/ptrauth_field_fptr_import.swift +++ b/test/IRGen/ptrauth_field_fptr_import.swift @@ -1,4 +1,5 @@ -// RUN: %swift-frontend %s -enable-import-ptrauth-field-function-pointers -emit-ir -target arm64e-apple-ios13.0 -I %S/Inputs/ -validate-tbd-against-ir=none -Xllvm -sil-disable-pass=OnoneSimplification | %FileCheck %s +// RUN: %swift-frontend %use_no_opaque_pointers %s -enable-import-ptrauth-field-function-pointers -emit-ir -target arm64e-apple-ios13.0 -I %S/Inputs/ -validate-tbd-against-ir=none -Xllvm -sil-disable-pass=OnoneSimplification | %FileCheck %s +// RUN: %swift-frontend %s -enable-import-ptrauth-field-function-pointers -emit-ir -target arm64e-apple-ios13.0 -I %S/Inputs/ -validate-tbd-against-ir=none -Xllvm -sil-disable-pass=OnoneSimplification // REQUIRES: CPU=arm64e // REQUIRES: OS=ios From c340d4751ea1702157a462599290e66ecbc92186 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Fri, 16 Jun 2023 07:36:01 -0700 Subject: [PATCH 22/41] [TypeLowering] Move-only types are lexical. Vars of such types should be given lexical `alloc_stack`s by `AllocBoxToStack` which requires that the `alloc_box` insts formed for them have an associated borrow scope which in turn requires that type lowering for move only structs and enums have their lexical bits set. rdar://110901430 --- lib/SIL/IR/TypeLowering.cpp | 2 + .../UtilityPasses/UnitTestRunner.cpp | 15 ++++ test/SIL/type_lowering_unit.sil | 18 +++++ test/SILGen/discard.swift | 4 +- test/SILGen/moveonly.swift | 63 ++++++++++------ test/SILGen/moveonly_deinits.swift | 12 ++-- test/SILGen/moveonly_enum_literal.swift | 3 +- test/SILGen/moveonly_escaping_closure.swift | 72 +++++++++++-------- 8 files changed, 133 insertions(+), 56 deletions(-) create mode 100644 test/SIL/type_lowering_unit.sil diff --git a/lib/SIL/IR/TypeLowering.cpp b/lib/SIL/IR/TypeLowering.cpp index 8ea1c2000ef79..2697129bbfa57 100644 --- a/lib/SIL/IR/TypeLowering.cpp +++ b/lib/SIL/IR/TypeLowering.cpp @@ -2394,6 +2394,7 @@ namespace { if (D->isMoveOnly()) { properties.setNonTrivial(); + properties.setLexical(IsLexical); if (properties.isAddressOnly()) return handleMoveOnlyAddressOnly(structType, properties); return new (TC) MoveOnlyLoadableStructTypeLowering( @@ -2475,6 +2476,7 @@ namespace { if (D->isMoveOnly()) { properties.setNonTrivial(); + properties.setLexical(IsLexical); if (properties.isAddressOnly()) return handleMoveOnlyAddressOnly(enumType, properties); return new (TC) diff --git a/lib/SILOptimizer/UtilityPasses/UnitTestRunner.cpp b/lib/SILOptimizer/UtilityPasses/UnitTestRunner.cpp index d3a2808d11379..ebf9a35bdd8e6 100644 --- a/lib/SILOptimizer/UtilityPasses/UnitTestRunner.cpp +++ b/lib/SILOptimizer/UtilityPasses/UnitTestRunner.cpp @@ -89,6 +89,7 @@ #include "swift/SILOptimizer/Utils/InstructionDeleter.h" #include "swift/SILOptimizer/Utils/ParseTestSpecification.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" #include #include @@ -287,6 +288,19 @@ struct OwnershipUtilsHasPointerEscape : UnitTest { } }; +// Arguments: +// - value: whose type will be printed +// Dumps: +// - the type lowering of the type +struct PrintTypeLowering : UnitTest { + PrintTypeLowering(UnitTestRunner *pass) : UnitTest(pass) {} + void invoke(Arguments &arguments) override { + auto value = arguments.takeValue(); + auto ty = value->getType(); + getFunction()->getTypeLowering(ty).print(llvm::dbgs()); + } +}; + //===----------------------------------------------------------------------===// // MARK: OSSA Lifetime Unit Tests //===----------------------------------------------------------------------===// @@ -899,6 +913,7 @@ void UnitTestRunner::withTest(StringRef name, Doit doit) { ADD_UNIT_TEST_SUBCLASS("find-enclosing-defs", FindEnclosingDefsTest) ADD_UNIT_TEST_SUBCLASS("function-get-self-argument-index", FunctionGetSelfArgumentIndex) ADD_UNIT_TEST_SUBCLASS("has-pointer-escape", OwnershipUtilsHasPointerEscape) + ADD_UNIT_TEST_SUBCLASS("print-type-lowering", PrintTypeLowering) ADD_UNIT_TEST_SUBCLASS("interior-liveness", InteriorLivenessTest) ADD_UNIT_TEST_SUBCLASS("is-deinit-barrier", IsDeinitBarrierTest) ADD_UNIT_TEST_SUBCLASS("is-lexical", IsLexicalTest) diff --git a/test/SIL/type_lowering_unit.sil b/test/SIL/type_lowering_unit.sil new file mode 100644 index 0000000000000..23e1ba35bbf64 --- /dev/null +++ b/test/SIL/type_lowering_unit.sil @@ -0,0 +1,18 @@ +// RUN: %target-sil-opt -unit-test-runner %s -o /dev/null 2>&1 | %FileCheck %s + +sil_stage raw + +import Builtin + +struct S : ~Copyable {} + +// CHECK-LABEL: begin {{.*}} print-type-lowering with: @argument[0] +// CHECK: isLexical: true +// CHECK-LABEL: end {{.*}} print-type-lowering with: @argument[0] +sil [ossa] @move_only_argument : $@convention(thin) (@owned S) -> () { +bb0(%0 : @owned $S): + test_specification "print-type-lowering @argument[0]" + destroy_value %0 : $S + %retval = tuple () + return %retval : $() +} diff --git a/test/SILGen/discard.swift b/test/SILGen/discard.swift index abb4ba5d8a5ad..17a2e5a17360a 100644 --- a/test/SILGen/discard.swift +++ b/test/SILGen/discard.swift @@ -89,7 +89,8 @@ func invokedDeinit() {} // CHECK-LABEL: sil hidden [ossa] @$s4test11PointerTreeV10tryDestroy9doDiscardySb_tKF : $@convention(method) (Bool, @owned PointerTree) -> @error any Error { // CHECK: bb0{{.*}}: // CHECK: [[SELF_BOX:%.*]] = alloc_box ${ var PointerTree }, var, name "self" -// CHECK: [[SELF_PTR:%.*]] = project_box [[SELF_BOX]] : ${ var PointerTree }, 0 +// CHECK: [[SELF_BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[SELF_BOX]] +// CHECK: [[SELF_PTR:%.*]] = project_box [[SELF_BOX_LIFETIME]] : ${ var PointerTree }, 0 // .. skip to the conditional test .. // CHECK: [[SHOULD_FORGET:%.*]] = struct_extract {{.*}} : $Bool, #Bool._value // CHECK: cond_br [[SHOULD_FORGET]], bb1, bb2 @@ -107,6 +108,7 @@ func invokedDeinit() {} // CHECK: br bb3 // // CHECK: bb3: +// CHECK: end_borrow [[SELF_BOX_LIFETIME]] // CHECK: destroy_value [[SELF_BOX]] : ${ var PointerTree } // CHECK: throw // CHECK: } // end sil function diff --git a/test/SILGen/moveonly.swift b/test/SILGen/moveonly.swift index e25375482eb4e..a68c83106e85a 100644 --- a/test/SILGen/moveonly.swift +++ b/test/SILGen/moveonly.swift @@ -933,7 +933,8 @@ struct EmptyStruct { // CHECK-LABEL: sil hidden [ossa] @$s8moveonly11EmptyStructVACycfC : $@convention(method) (@thin EmptyStruct.Type) -> @owned EmptyStruct { // CHECK: [[BOX:%.*]] = alloc_box ${ var EmptyStruct }, var, name "self" // CHECK: [[MARKED_UNINIT:%.*]] = mark_uninitialized [rootself] [[BOX]] - // CHECK: [[PROJECT:%.*]] = project_box [[MARKED_UNINIT]] + // CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[MARKED_UNINIT]] + // CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // CHECK: [[STRUCT:%.*]] = struct $EmptyStruct () // CHECK: store [[STRUCT]] to [init] [[PROJECT]] // CHECK: [[MV_CHECK:%.*]] = mark_must_check [assignable_but_not_consumable] [[PROJECT]] @@ -1039,7 +1040,8 @@ public struct LoadableSubscriptGetOnlyTester : ~Copyable { // CHECK-LABEL: sil [ossa] @$s8moveonly047testSubscriptGetOnly_BaseLoadable_ResultAddressE4_VaryyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box $ -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // // The get call // CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJECT]] @@ -1077,7 +1079,8 @@ public func testSubscriptGetOnly_BaseLoadable_ResultAddressOnly_Var() { // CHECK-LABEL: sil [ossa] @$s8moveonly047testSubscriptGetOnly_BaseLoadable_ResultAddressE4_LetyyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box $ -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // // The get call // CHECK: [[MARK:%.*]] = mark_must_check [no_consume_or_assign] [[PROJECT]] @@ -1140,7 +1143,8 @@ public struct LoadableSubscriptGetOnlyTesterNonCopyableStructParent : ~Copyable // CHECK-LABEL: sil [ossa] @$s8moveonly077testSubscriptGetOnlyThroughNonCopyableParentStruct_BaseLoadable_ResultAddressE4_VaryyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box $ -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // // The first get call // CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJECT]] @@ -1181,7 +1185,8 @@ public func testSubscriptGetOnlyThroughNonCopyableParentStruct_BaseLoadable_Resu // CHECK-LABEL: sil [ossa] @$s8moveonly077testSubscriptGetOnlyThroughNonCopyableParentStruct_BaseLoadable_ResultAddressE4_LetyyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box ${ let L -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // // CHECK: [[MARK:%.*]] = mark_must_check [no_consume_or_assign] [[PROJECT]] // CHECK: [[LOAD:%.*]] = load_borrow [[MARK]] @@ -1350,7 +1355,8 @@ public struct LoadableSubscriptGetSetTester : ~Copyable { // CHECK-LABEL: sil [ossa] @$s8moveonly54testSubscriptGetSet_BaseLoadable_ResultAddressOnly_VaryyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box $ -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // // The get call // CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJECT]] @@ -1396,7 +1402,8 @@ public func testSubscriptGetSet_BaseLoadable_ResultAddressOnly_Var() { // CHECK-LABEL: sil [ossa] @$s8moveonly54testSubscriptGetSet_BaseLoadable_ResultAddressOnly_LetyyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box $ -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // // The get call // CHECK: [[MARK:%.*]] = mark_must_check [no_consume_or_assign] [[PROJECT]] @@ -1507,7 +1514,8 @@ public struct LoadableSubscriptGetSetTesterNonCopyableStructParent : ~Copyable { // CHECK-LABEL: sil [ossa] @$s8moveonly84testSubscriptGetSetThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_VaryyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box $ -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // // The first get call // CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJECT]] @@ -1561,7 +1569,8 @@ public func testSubscriptGetSetThroughNonCopyableParentStruct_BaseLoadable_Resul // CHECK-LABEL: sil [ossa] @$s8moveonly84testSubscriptGetSetThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_LetyyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box ${ let L -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // // CHECK: [[MARK:%.*]] = mark_must_check [no_consume_or_assign] [[PROJECT]] // CHECK: [[LOAD:%.*]] = load_borrow [[MARK]] @@ -1819,7 +1828,8 @@ public struct LoadableSubscriptReadSetTester : ~Copyable { // CHECK-LABEL: sil [ossa] @$s8moveonly55testSubscriptReadSet_BaseLoadable_ResultAddressOnly_VaryyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box $ -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // // The read call // CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJECT]] @@ -1865,7 +1875,8 @@ public func testSubscriptReadSet_BaseLoadable_ResultAddressOnly_Var() { // CHECK-LABEL: sil [ossa] @$s8moveonly55testSubscriptReadSet_BaseLoadable_ResultAddressOnly_LetyyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box $ -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // // The get call // CHECK: [[MARK:%.*]] = mark_must_check [no_consume_or_assign] [[PROJECT]] @@ -1979,7 +1990,8 @@ public struct LoadableSubscriptReadSetTesterNonCopyableStructParent : ~Copyable // CHECK-LABEL: sil [ossa] @$s8moveonly85testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_VaryyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box $ -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // // The first get call // CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJECT]] @@ -2031,7 +2043,8 @@ public func testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_Resu // CHECK-LABEL: sil [ossa] @$s8moveonly85testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_LetyyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box ${ let L -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // // CHECK: [[MARK:%.*]] = mark_must_check [no_consume_or_assign] [[PROJECT]] // CHECK: [[LOAD:%.*]] = load_borrow [[MARK]] @@ -2285,7 +2298,8 @@ public struct LoadableSubscriptReadModifyTester : ~Copyable { // CHECK-LABEL: sil [ossa] @$s8moveonly58testSubscriptReadModify_BaseLoadable_ResultAddressOnly_VaryyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box $ -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // // The read call // CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJECT]] @@ -2328,7 +2342,8 @@ public func testSubscriptReadModify_BaseLoadable_ResultAddressOnly_Var() { // CHECK-LABEL: sil [ossa] @$s8moveonly58testSubscriptReadModify_BaseLoadable_ResultAddressOnly_LetyyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box $ -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // // The get call // CHECK: [[MARK:%.*]] = mark_must_check [no_consume_or_assign] [[PROJECT]] @@ -2431,7 +2446,8 @@ public struct LoadableSubscriptReadModifyTesterNonCopyableStructParent : ~Copyab // CHECK-LABEL: sil [ossa] @$s8moveonly88testSubscriptReadModifyThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_VaryyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box $ -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // // The first get call // CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJECT]] @@ -2477,7 +2493,8 @@ public func testSubscriptReadModifyThroughNonCopyableParentStruct_BaseLoadable_R // CHECK-LABEL: sil [ossa] @$s8moveonly88testSubscriptReadModifyThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_LetyyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box ${ let L -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // // CHECK: [[MARK:%.*]] = mark_must_check [no_consume_or_assign] [[PROJECT]] // CHECK: [[LOAD:%.*]] = load_borrow [[MARK]] @@ -2699,7 +2716,8 @@ public struct LoadableSubscriptGetModifyTester : ~Copyable { // CHECK-LABEL: sil [ossa] @$s8moveonly57testSubscriptGetModify_BaseLoadable_ResultAddressOnly_VaryyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box $ -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // // The get call // CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJECT]] @@ -2743,7 +2761,8 @@ public func testSubscriptGetModify_BaseLoadable_ResultAddressOnly_Var() { // CHECK-LABEL: sil [ossa] @$s8moveonly57testSubscriptGetModify_BaseLoadable_ResultAddressOnly_LetyyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box $ -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // // The get call // CHECK: [[MARK:%.*]] = mark_must_check [no_consume_or_assign] [[PROJECT]] @@ -2850,7 +2869,8 @@ public struct LoadableSubscriptGetModifyTesterNonCopyableStructParent : ~Copyabl // CHECK-LABEL: sil [ossa] @$s8moveonly87testSubscriptGetModifyThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_VaryyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box $ -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // // The first get call // CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJECT]] @@ -2900,7 +2920,8 @@ public func testSubscriptGetModifyThroughNonCopyableParentStruct_BaseLoadable_Re // CHECK-LABEL: sil [ossa] @$s8moveonly87testSubscriptGetModifyThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_LetyyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box ${ let L -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // // CHECK: [[MARK:%.*]] = mark_must_check [no_consume_or_assign] [[PROJECT]] // CHECK: [[LOAD:%.*]] = load_borrow [[MARK]] diff --git a/test/SILGen/moveonly_deinits.swift b/test/SILGen/moveonly_deinits.swift index 73a7353966af0..88a6fd778ef20 100644 --- a/test/SILGen/moveonly_deinits.swift +++ b/test/SILGen/moveonly_deinits.swift @@ -83,7 +83,8 @@ var value: Bool { false } // SILGEN-LABEL: sil [ossa] @$s16moveonly_deinits24testIntPairWithoutDeinityyF : $@convention(thin) () -> () { // SILGEN: [[BOX:%.*]] = alloc_box -// SILGEN: [[PROJECT:%.*]] = project_box [[BOX]] +// SILGEN: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// SILGEN: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // SILGEN: cond_br {{%.*}}, bb1, bb2 // // SILGEN: bb1: @@ -132,7 +133,8 @@ public func testIntPairWithoutDeinit() { // SILGEN-LABEL: sil [ossa] @$s16moveonly_deinits21testIntPairWithDeinityyF : $@convention(thin) () -> () { // SILGEN: [[BOX:%.*]] = alloc_box -// SILGEN: [[PROJECT:%.*]] = project_box [[BOX]] +// SILGEN: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// SILGEN: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // SILGEN: cond_br {{%.*}}, bb1, bb2 // // SILGEN: bb1: @@ -343,7 +345,8 @@ func consumeKlassEnumPairWithDeinit(_ x: __owned KlassEnumPairWithDeinit) { } // SILGEN-LABEL: sil [ossa] @$s16moveonly_deinits28testIntEnumPairWithoutDeinityyF : $@convention(thin) () -> () { // SILGEN: [[BOX:%.*]] = alloc_box -// SILGEN: [[PROJECT:%.*]] = project_box [[BOX]] +// SILGEN: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// SILGEN: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // SILGEN: cond_br {{%.*}}, bb1, bb2 // // SILGEN: bb1: @@ -391,7 +394,8 @@ public func testIntEnumPairWithoutDeinit() { // SILGEN-LABEL: sil [ossa] @$s16moveonly_deinits25testIntEnumPairWithDeinityyF : $@convention(thin) () -> () { // SILGEN: [[BOX:%.*]] = alloc_box -// SILGEN: [[PROJECT:%.*]] = project_box [[BOX]] +// SILGEN: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// SILGEN: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // SILGEN: cond_br {{%.*}}, bb1, bb2 // // SILGEN: bb1: diff --git a/test/SILGen/moveonly_enum_literal.swift b/test/SILGen/moveonly_enum_literal.swift index 4d566835f4b83..13555bce43a40 100644 --- a/test/SILGen/moveonly_enum_literal.swift +++ b/test/SILGen/moveonly_enum_literal.swift @@ -16,7 +16,8 @@ var value: Bool { false } // CHECK-LABEL: sil hidden [ossa] @$s21moveonly_enum_literal4testyyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // CHECK: [[VALUE:%.*]] = enum $MoveOnlyIntPair, #MoveOnlyIntPair.lhs!enumelt, // CHECK: store [[VALUE]] to [init] [[PROJECT]] // diff --git a/test/SILGen/moveonly_escaping_closure.swift b/test/SILGen/moveonly_escaping_closure.swift index 1b20481e0147e..3977658feebb9 100644 --- a/test/SILGen/moveonly_escaping_closure.swift +++ b/test/SILGen/moveonly_escaping_closure.swift @@ -24,9 +24,10 @@ func borrowConsumeVal(_ x: borrowing SingleElt, _ y: consuming SingleElt) {} // CHECK-LABEL: sil hidden [ossa] @$s16moveonly_closure27testGlobalClosureCaptureVaryyF : $@convention(thin) () -> () { // CHECK: [[GLOBAL:%.*]] = global_addr @$s16moveonly_closure23globalClosureCaptureVaryycvp // CHECK: [[BOX:%.*]] = alloc_box ${ var SingleElt } -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // CHECK: [[CLOSURE:%.*]] = function_ref @$s16moveonly_closure27testGlobalClosureCaptureVaryyFyycfU_ : $@convention(thin) (@guaranteed { var SingleElt }) -> () -// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX]] +// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX_LIFETIME]] // CHECK: [[PAI:%.*]] = partial_apply [callee_guaranteed] [[CLOSURE]]([[BOX_COPY]]) // CHECK: [[ACCESS:%.*]] = begin_access [modify] [dynamic] [[GLOBAL]] // CHECK: assign [[PAI]] to [[ACCESS]] @@ -84,8 +85,9 @@ func testGlobalClosureCaptureVar() { // CHECK-LABEL: sil hidden [ossa] @$s16moveonly_closure29testLocalLetClosureCaptureVaryyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] -// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] +// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX_LIFETIME]] // CHECK: mark_function_escape [[PROJECT]] // CHECK: [[PAI:%.*]] = partial_apply [callee_guaranteed] {{%.*}}([[BOX_COPY]]) // CHECK: [[BORROW_PAI:%.*]] = begin_borrow [lexical] [[PAI]] @@ -151,8 +153,9 @@ func testLocalLetClosureCaptureVar() { // CHECK-LABEL: sil hidden [ossa] @$s16moveonly_closure026testLocalVarClosureCaptureE0yyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] -// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] +// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX_LIFETIME]] // CHECK: mark_function_escape [[PROJECT]] // CHECK: [[PAI:%.*]] = partial_apply [callee_guaranteed] {{%.*}}([[BOX_COPY]]) // CHECK: } // end sil function '$s16moveonly_closure026testLocalVarClosureCaptureE0yyF' @@ -209,9 +212,10 @@ func testLocalVarClosureCaptureVar() { // CHECK-LABEL: sil hidden [ossa] @$s16moveonly_closure026testInOutVarClosureCaptureF0yyyyczF : $@convention(thin) (@inout @callee_guaranteed () -> ()) -> () { // CHECK: bb0([[F:%.*]] : $*@callee_guaranteed () -> ()): // CHECK: [[BOX:%.*]] = alloc_box ${ var SingleElt } -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // CHECK: [[CLOSURE:%.*]] = function_ref @$s16moveonly_closure026testInOutVarClosureCaptureF0yyyyczFyycfU_ : $@convention(thin) (@guaranteed { var SingleElt }) -> () -// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX]] +// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX_LIFETIME]] // CHECK: [[PAI:%.*]] = partial_apply [callee_guaranteed] [[CLOSURE]]([[BOX_COPY]]) // CHECK: [[ACCESS:%.*]] = begin_access [modify] [unknown] [[F]] // CHECK: assign [[PAI]] to [[ACCESS]] @@ -275,9 +279,10 @@ func testInOutVarClosureCaptureVar(_ f: inout () -> ()) { // CHECK: store [[ARG]] to [init] [[UNWRAP]] // // CHECK: [[BOX:%.*]] = alloc_box ${ var SingleElt } -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // CHECK: [[CLOSURE:%.*]] = function_ref @$s16moveonly_closure36testConsumingEscapeClosureCaptureVaryyyycnFyycfU_ : $@convention(thin) (@guaranteed { var SingleElt }) -// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX]] +// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX_LIFETIME]] // CHECK: mark_function_escape [[PROJECT]] // CHECK: [[PAI:%.*]] = partial_apply [callee_guaranteed] [[CLOSURE]]([[BOX_COPY]]) // CHECK: [[ACCESS:%.*]] = begin_access [modify] [unknown] [[FUNC_PROJECT]] @@ -342,9 +347,10 @@ func testConsumingEscapeClosureCaptureVar(_ f: consuming @escaping () -> ()) { // CHECK-LABEL: sil hidden [ossa] @$s16moveonly_closure27testGlobalClosureCaptureLetyyF : $@convention(thin) () -> () { // CHECK: [[GLOBAL:%.*]] = global_addr @$s16moveonly_closure23globalClosureCaptureLetyycvp // CHECK: [[BOX:%.*]] = alloc_box ${ let SingleElt } -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // CHECK: [[CLOSURE:%.*]] = function_ref @$s16moveonly_closure27testGlobalClosureCaptureLetyyFyycfU_ : $@convention(thin) (@guaranteed { let SingleElt }) -> () -// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX]] +// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX_LIFETIME]] // CHECK: [[PAI:%.*]] = partial_apply [callee_guaranteed] [[CLOSURE]]([[BOX_COPY]]) // CHECK: [[ACCESS:%.*]] = begin_access [modify] [dynamic] [[GLOBAL]] // CHECK: assign [[PAI]] to [[ACCESS]] @@ -388,8 +394,9 @@ func testGlobalClosureCaptureLet() { // CHECK-LABEL: sil hidden [ossa] @$s16moveonly_closure026testLocalLetClosureCaptureE0yyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] -// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] +// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX_LIFETIME]] // CHECK: mark_function_escape [[PROJECT]] // CHECK: [[PAI:%.*]] = partial_apply [callee_guaranteed] {{%.*}}([[BOX_COPY]]) // CHECK: [[BORROW_PAI:%.*]] = begin_borrow [lexical] [[PAI]] @@ -437,8 +444,9 @@ func testLocalLetClosureCaptureLet() { // CHECK-LABEL: sil hidden [ossa] @$s16moveonly_closure29testLocalVarClosureCaptureLetyyF : $@convention(thin) () -> () { // CHECK: [[BOX:%.*]] = alloc_box -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] -// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] +// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX_LIFETIME]] // CHECK: mark_function_escape [[PROJECT]] // CHECK: [[PAI:%.*]] = partial_apply [callee_guaranteed] {{%.*}}([[BOX_COPY]]) // CHECK: } // end sil function '$s16moveonly_closure29testLocalVarClosureCaptureLetyyF' @@ -482,9 +490,10 @@ func testLocalVarClosureCaptureLet() { // CHECK-LABEL: sil hidden [ossa] @$s16moveonly_closure29testInOutVarClosureCaptureLetyyyyczF : $@convention(thin) (@inout @callee_guaranteed () -> ()) -> () { // CHECK: bb0([[F:%.*]] : $*@callee_guaranteed () -> ()): // CHECK: [[BOX:%.*]] = alloc_box ${ let SingleElt } -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // CHECK: [[CLOSURE:%.*]] = function_ref @$s16moveonly_closure29testInOutVarClosureCaptureLetyyyyczFyycfU_ : $@convention(thin) (@guaranteed { let SingleElt }) -> () -// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX]] +// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX_LIFETIME]] // CHECK: [[PAI:%.*]] = partial_apply [callee_guaranteed] [[CLOSURE]]([[BOX_COPY]]) // CHECK: [[ACCESS:%.*]] = begin_access [modify] [unknown] [[F]] // CHECK: assign [[PAI]] to [[ACCESS]] @@ -530,14 +539,15 @@ func testInOutVarClosureCaptureLet(_ f: inout () -> ()) { // CHECK-LABEL: sil hidden [ossa] @$s16moveonly_closure36testConsumingEscapeClosureCaptureLetyyyycnF : $@convention(thin) (@owned @callee_guaranteed () -> ()) -> () { // CHECK: bb0([[ARG:%.*]] : @noImplicitCopy @_eagerMove @owned // CHECK: [[FUNC_BOX:%.*]] = alloc_box ${ var @moveOnly @callee_guaranteed () -> () } -// CHECK: [[FUNC_PROJECT:%.*]] = project_box [[FUNC_BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[FUNC_BOX]] // CHECK: [[UNWRAP:%.*]] = moveonlywrapper_to_copyable_addr [[FUNC_PROJECT]] // CHECK: store [[ARG]] to [init] [[UNWRAP]] // // CHECK: [[BOX:%.*]] = alloc_box ${ let SingleElt } -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // CHECK: [[CLOSURE:%.*]] = function_ref @$s16moveonly_closure36testConsumingEscapeClosureCaptureLetyyyycnFyycfU_ : $@convention(thin) (@guaranteed { let SingleElt }) -// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX]] +// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX_LIFETIME]] // CHECK: mark_function_escape [[PROJECT]] // CHECK: [[PAI:%.*]] = partial_apply [callee_guaranteed] [[CLOSURE]]([[BOX_COPY]]) // CHECK: [[ACCESS:%.*]] = begin_access [modify] [unknown] [[FUNC_PROJECT]] @@ -840,9 +850,10 @@ func testConsumingEscapeClosureCaptureInOut(_ f: consuming @escaping () -> (), _ // CHECK-LABEL: sil hidden [ossa] @$s16moveonly_closure33testGlobalClosureCaptureConsumingyyAA9SingleEltVnF : $@convention(thin) (@owned SingleElt) -> () { // CHECK: [[GLOBAL:%.*]] = global_addr @$s16moveonly_closure29globalClosureCaptureConsumingyycvp // CHECK: [[BOX:%.*]] = alloc_box ${ var SingleElt } -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // CHECK: [[CLOSURE:%.*]] = function_ref @$s16moveonly_closure33testGlobalClosureCaptureConsumingyyAA9SingleEltVnFyycfU_ : $@convention(thin) (@guaranteed { var SingleElt }) -> () -// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX]] +// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX_LIFETIME]] // CHECK: [[PAI:%.*]] = partial_apply [callee_guaranteed] [[CLOSURE]]([[BOX_COPY]]) // CHECK: [[ACCESS:%.*]] = begin_access [modify] [dynamic] [[GLOBAL]] // CHECK: assign [[PAI]] to [[ACCESS]] @@ -898,8 +909,9 @@ func testGlobalClosureCaptureConsuming(_ x: consuming SingleElt) { // CHECK-LABEL: sil hidden [ossa] @$s16moveonly_closure35testLocalLetClosureCaptureConsumingyyAA9SingleEltVnF : $@convention(thin) (@owned SingleElt) -> () { // CHECK: [[BOX:%.*]] = alloc_box -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] -// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] +// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX_LIFETIME]] // CHECK: mark_function_escape [[PROJECT]] // CHECK: [[PAI:%.*]] = partial_apply [callee_guaranteed] {{%.*}}([[BOX_COPY]]) // CHECK: [[BORROW_PAI:%.*]] = begin_borrow [lexical] [[PAI]] @@ -976,8 +988,9 @@ func testLocalLetClosureCaptureConsuming2(_ x: consuming SingleElt) -> (() -> () // CHECK-LABEL: sil hidden [ossa] @$s16moveonly_closure35testLocalVarClosureCaptureConsumingyyAA9SingleEltVnF : $@convention(thin) (@owned SingleElt) -> () { // CHECK: [[BOX:%.*]] = alloc_box -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] -// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] +// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX_LIFETIME]] // CHECK: mark_function_escape [[PROJECT]] // CHECK: [[PAI:%.*]] = partial_apply [callee_guaranteed] {{%.*}}([[BOX_COPY]]) // CHECK: } // end sil function '$s16moveonly_closure35testLocalVarClosureCaptureConsumingyyAA9SingleEltVnF' @@ -1038,9 +1051,10 @@ func testLocalVarClosureCaptureConsuming(_ x: consuming SingleElt) { // CHECK: store [[ARG]] to [init] [[UNWRAP]] // // CHECK: [[BOX:%.*]] = alloc_box ${ var SingleElt } -// CHECK: [[PROJECT:%.*]] = project_box [[BOX]] +// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]] // CHECK: [[CLOSURE:%.*]] = function_ref @$s16moveonly_closure033testConsumingEscapeClosureCaptureD0yyyycn_AA9SingleEltVntFyycfU_ : $@convention(thin) (@guaranteed { var SingleElt }) -> () -// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX]] +// CHECK: [[BOX_COPY:%.*]] = copy_value [[BOX_LIFETIME]] // CHECK: mark_function_escape [[PROJECT]] // CHECK: [[PAI:%.*]] = partial_apply [callee_guaranteed] [[CLOSURE]]([[BOX_COPY]]) // CHECK: [[ACCESS:%.*]] = begin_access [modify] [unknown] [[FUNC_PROJECT]] From 0bf643d0c64e03c5422f103f39b6288f9497414b Mon Sep 17 00:00:00 2001 From: Erik Eckstein Date: Fri, 16 Jun 2023 08:35:02 +0200 Subject: [PATCH 23/41] Optimizer: add an additional DeadObjectElimination at the end of the pipeline The last dead-store-elimination pass can expose opportunities for dead object elimination. rdar://110846405 --- lib/SILOptimizer/PassManager/PassPipeline.cpp | 3 ++ test/SILOptimizer/dead_alloc.swift | 47 +++++++++++++++++++ test/SILOptimizer/dead_alloc_stack.swift | 32 ------------- 3 files changed, 50 insertions(+), 32 deletions(-) create mode 100644 test/SILOptimizer/dead_alloc.swift delete mode 100644 test/SILOptimizer/dead_alloc_stack.swift diff --git a/lib/SILOptimizer/PassManager/PassPipeline.cpp b/lib/SILOptimizer/PassManager/PassPipeline.cpp index b46ab9c304325..a1a04e038ec06 100644 --- a/lib/SILOptimizer/PassManager/PassPipeline.cpp +++ b/lib/SILOptimizer/PassManager/PassPipeline.cpp @@ -760,6 +760,9 @@ static void addLowLevelPassPipeline(SILPassPipelinePlan &P) { P.addObjectOutliner(); P.addDeadStoreElimination(); + // dead-store-elimination can expose opportunities for dead object elimination. + P.addDeadObjectElimination(); + // We've done a lot of optimizations on this function, attempt to FSO. P.addFunctionSignatureOpts(); P.addComputeEscapeEffects(); diff --git a/test/SILOptimizer/dead_alloc.swift b/test/SILOptimizer/dead_alloc.swift new file mode 100644 index 0000000000000..3c435ec9e58b2 --- /dev/null +++ b/test/SILOptimizer/dead_alloc.swift @@ -0,0 +1,47 @@ +// RUN: %target-swift-frontend -O -emit-sil -parse-as-library %s | %FileCheck %s + +// REQUIRES: swift_stdlib_no_asserts,optimized_stdlib +// REQUIRES: swift_in_compiler + +protocol E { + func f() -> Bool +} + +protocol P { + associatedtype A = Int +} + +public struct X : P, E { + func f() -> Bool { return true } +} + +func g(_ x : T) -> Bool { + if let y = x as? E { return y.f() } + return false +} + +// Check that this function can be completely constant folded and no alloc_stack remains. + +// CHECK-LABEL: sil @$s10dead_alloc0A10AllocStackySbAA1XVF : +// CHECK: bb0({{.*}}): +// CHECK-NEXT: debug_value +// CHECK-NEXT: integer_literal +// CHECK-NEXT: struct +// CHECK-NEXT: return +// CHECK-NEXT: } // end sil function '$s10dead_alloc0A10AllocStackySbAA1XVF' +public func deadAllocStack(_ x: X) -> Bool { + return g(x) +} + +public class C { + let x: String = "123" +} + +// CHECK-LABEL: sil @$s10dead_alloc0A13ClassInstanceyyF : +// CHECK: bb0: +// CHECK-NEXT: tuple +// CHECK-NEXT: return +// CHECK-NEXT: } // end sil function '$s10dead_alloc0A13ClassInstanceyyF' +public func deadClassInstance() { + let _ = C() +} diff --git a/test/SILOptimizer/dead_alloc_stack.swift b/test/SILOptimizer/dead_alloc_stack.swift deleted file mode 100644 index 457253f8a3a34..0000000000000 --- a/test/SILOptimizer/dead_alloc_stack.swift +++ /dev/null @@ -1,32 +0,0 @@ -// RUN: %target-swift-frontend -O -emit-sil -parse-as-library %s | %FileCheck %s - -protocol E { - func f() -> Bool -} - -protocol P { - associatedtype A = Int -} - -public struct X : P, E { - func f() -> Bool { return true } -} - -func g(_ x : T) -> Bool { - if let y = x as? E { return y.f() } - return false -} - -// Check that this function can be completely constant folded and no alloc_stack remains. - -// CHECK-LABEL: sil @$s16dead_alloc_stack6testitySbAA1XVF -// CHECK: bb0({{.*}}): -// CHECK-NEXT: debug_value -// CHECK-NEXT: integer_literal -// CHECK-NEXT: struct -// CHECK-NEXT: return -// CHECK-NEXT: } // end sil function '$s16dead_alloc_stack6testitySbAA1XVF' -public func testit(_ x: X) -> Bool { - return g(x) -} - From e1d2198399f12de726b4631fa85c5fca03d215cf Mon Sep 17 00:00:00 2001 From: Sima Nerush <51447912+simanerush@users.noreply.github.com> Date: Fri, 16 Jun 2023 11:23:41 -0700 Subject: [PATCH 24/41] [TypeResolution] Ban local variable packs (#66622) * Ban explicit local variable packs * Ban inferred local variable packs --- lib/Sema/TypeCheckStorage.cpp | 7 +++++++ lib/Sema/TypeCheckType.cpp | 2 +- lib/Sema/TypeCheckType.h | 7 +------ test/Constraints/pack-expansion-expressions.swift | 3 ++- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/lib/Sema/TypeCheckStorage.cpp b/lib/Sema/TypeCheckStorage.cpp index 979654b18cc1b..7b4dba2aeb107 100644 --- a/lib/Sema/TypeCheckStorage.cpp +++ b/lib/Sema/TypeCheckStorage.cpp @@ -473,6 +473,13 @@ const PatternBindingEntry *PatternBindingEntryRequest::evaluate( return &pbe; } + // Local variable packs are not allowed. + if (binding->getDeclContext()->isLocalContext() && + binding->getInit(entryNumber)->getType()->is()) { + binding->diagnose(diag::expansion_not_allowed, + binding->getInit(entryNumber)->getType()); + } + // A pattern binding at top level is not allowed to pick up another decl's // opaque result type as its type by type inference. if (!binding->getDeclContext()->isLocalContext() && diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index ef53dab93a395..dec4881f9a800 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -4618,7 +4618,7 @@ NeverNullType TypeResolver::resolvePackExpansionType(PackExpansionTypeRepr *repr } // We might not allow variadic expansions here at all. - if (!options.isPackExpansionSupported(getDeclContext())) { + if (!options.isPackExpansionSupported()) { diagnose(repr->getLoc(), diag::expansion_not_allowed, result); return ErrorType::get(ctx); } diff --git a/lib/Sema/TypeCheckType.h b/lib/Sema/TypeCheckType.h index 621349220e058..483fd718ce23e 100644 --- a/lib/Sema/TypeCheckType.h +++ b/lib/Sema/TypeCheckType.h @@ -335,7 +335,7 @@ class TypeResolutionOptions { } /// Whether pack expansion types are supported in this context. - bool isPackExpansionSupported(DeclContext *dc) const { + bool isPackExpansionSupported() const { switch (context) { case Context::FunctionInput: case Context::VariadicFunctionInput: @@ -343,12 +343,7 @@ class TypeResolutionOptions { case Context::TupleElement: case Context::GenericArgument: return true; - - // Local variable packs are supported, but property packs - // are not. case Context::PatternBindingDecl: - return !dc->isTypeContext(); - case Context::None: case Context::ProtocolGenericArgument: case Context::Inherited: diff --git a/test/Constraints/pack-expansion-expressions.swift b/test/Constraints/pack-expansion-expressions.swift index 8c09b8e167ca5..1247a21702394 100644 --- a/test/Constraints/pack-expansion-expressions.swift +++ b/test/Constraints/pack-expansion-expressions.swift @@ -36,8 +36,9 @@ func coerceExpansion(_ value: repeat each T) { func localValuePack(_ t: repeat each T) -> (repeat each T, repeat each T) { let local = repeat each t + // expected-error@-1{{pack expansion 'repeat each T' can only appear in a function parameter list, tuple element, or generic argument list}} let localAnnotated: repeat each T = repeat each t - // expected-error@-1{{value pack expansion can only appear inside a function argument list or tuple element}} + // expected-error@-1{{pack expansion 'repeat each T' can only appear in a function parameter list, tuple element, or generic argument list}} return (repeat each local, repeat each localAnnotated) } From 6fa0c14dfb6329b8bd87ad673ddccc6ec92ba453 Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Fri, 16 Jun 2023 11:37:20 -0700 Subject: [PATCH 25/41] [Macros] Make 'PluginSearchOption' a external union Create a 'Kind' enum so that deserialization can use the kind instead of a string option name. --- include/swift/AST/SearchPathOptions.h | 96 +++++++++++++++---- .../Serialization/SerializationOptions.h | 2 +- include/swift/Serialization/Validation.h | 9 +- lib/AST/PluginLoader.cpp | 30 +++--- lib/Serialization/ModuleFileSharedCore.cpp | 18 ++-- lib/Serialization/Serialization.cpp | 27 +++--- .../lldb-moduleimport-test.cpp | 17 +++- 7 files changed, 141 insertions(+), 58 deletions(-) diff --git a/include/swift/AST/SearchPathOptions.h b/include/swift/AST/SearchPathOptions.h index be355091b29d6..12a96849ed722 100644 --- a/include/swift/AST/SearchPathOptions.h +++ b/include/swift/AST/SearchPathOptions.h @@ -14,8 +14,8 @@ #define SWIFT_AST_SEARCHPATHOPTIONS_H #include "swift/Basic/ArrayRefView.h" +#include "swift/Basic/ExternalUnion.h" #include "swift/Basic/PathRemapper.h" -#include "swift/Basic/TaggedUnion.h" #include "llvm/ADT/Hashing.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/StringMap.h" @@ -187,25 +187,81 @@ struct ExternalPluginSearchPathAndServerPath { std::string ServerPath; }; -namespace PluginSearchOption { -struct LoadPluginLibrary { - std::string LibraryPath; -}; -struct LoadPluginExecutable { - std::string ExecutablePath; - std::vector ModuleNames; -}; -struct PluginPath { - std::string SearchPath; -}; -struct ExternalPluginPath { - std::string SearchPath; - std::string ServerPath; -}; +class PluginSearchOption { +public: + struct LoadPluginLibrary { + std::string LibraryPath; + }; + struct LoadPluginExecutable { + std::string ExecutablePath; + std::vector ModuleNames; + }; + struct PluginPath { + std::string SearchPath; + }; + struct ExternalPluginPath { + std::string SearchPath; + std::string ServerPath; + }; + + enum class Kind : uint8_t { + LoadPluginLibrary, + LoadPluginExecutable, + PluginPath, + ExternalPluginPath, + }; -using Value = TaggedUnion; -} // namespace PluginSearchOption +private: + using Members = ExternalUnionMembers; + static Members::Index getIndexForKind(Kind kind) { + switch (kind) { + case Kind::LoadPluginLibrary: + return Members::indexOf(); + case Kind::LoadPluginExecutable: + return Members::indexOf(); + case Kind::PluginPath: + return Members::indexOf(); + case Kind::ExternalPluginPath: + return Members::indexOf(); + } + }; + using Storage = ExternalUnion; + + Kind kind; + Storage storage; + +public: + PluginSearchOption(const LoadPluginLibrary &v) + : kind(Kind::LoadPluginLibrary) { + storage.emplace(kind, v); + } + PluginSearchOption(const LoadPluginExecutable &v) + : kind(Kind::LoadPluginExecutable) { + storage.emplace(kind, v); + } + PluginSearchOption(const PluginPath &v) : kind(Kind::PluginPath) { + storage.emplace(kind, v); + } + PluginSearchOption(const ExternalPluginPath &v) + : kind(Kind::ExternalPluginPath) { + storage.emplace(kind, v); + } + + Kind getKind() const { return kind; } + + template + const T *dyn_cast() const { + if (Members::indexOf() != getIndexForKind(kind)) + return nullptr; + return &storage.get(kind); + } + + template + const T &get() const { + return storage.get(kind); + } +}; /// Options for controlling search path behavior. class SearchPathOptions { @@ -383,7 +439,7 @@ class SearchPathOptions { std::vector RuntimeLibraryPaths; /// Plugin search path options. - std::vector PluginSearchOpts; + std::vector PluginSearchOpts; /// Don't look in for compiler-provided modules. bool SkipRuntimeLibraryImportPaths = false; diff --git a/include/swift/Serialization/SerializationOptions.h b/include/swift/Serialization/SerializationOptions.h index d14c6a1d4d6b9..d38467eca23d8 100644 --- a/include/swift/Serialization/SerializationOptions.h +++ b/include/swift/Serialization/SerializationOptions.h @@ -44,7 +44,7 @@ namespace swift { StringRef ModuleLinkName; StringRef ModuleInterface; std::vector ExtraClangOptions; - std::vector PluginSearchOptions; + std::vector PluginSearchOptions; /// Path prefixes that should be rewritten in debug info. PathRemapper DebuggingOptionsPrefixMap; diff --git a/include/swift/Serialization/Validation.h b/include/swift/Serialization/Validation.h index 98e96a4bb9cc4..9ba02485ae973 100644 --- a/include/swift/Serialization/Validation.h +++ b/include/swift/Serialization/Validation.h @@ -111,7 +111,8 @@ struct ValidationInfo { class ExtendedValidationInfo { SmallVector ExtraClangImporterOpts; - SmallVector, 2> PluginSearchOptions; + SmallVector, 2> + PluginSearchOptions; std::string SDKPath; StringRef ModuleABIName; @@ -146,10 +147,12 @@ class ExtendedValidationInfo { ExtraClangImporterOpts.push_back(option); } - ArrayRef> getPluginSearchOptions() const { + ArrayRef> + getPluginSearchOptions() const { return PluginSearchOptions; } - void addPluginSearchOption(const std::pair &opt) { + void addPluginSearchOption( + const std::pair &opt) { PluginSearchOptions.push_back(opt); } diff --git a/lib/AST/PluginLoader.cpp b/lib/AST/PluginLoader.cpp index 1bdfc95b1e7ef..49368dd9a0fa6 100644 --- a/lib/AST/PluginLoader.cpp +++ b/lib/AST/PluginLoader.cpp @@ -61,27 +61,31 @@ PluginLoader::lookupPluginByModuleName(Identifier moduleName) { // FIXME: Should we create a lookup table keyed by module name? for (auto &entry : Ctx.SearchPathOpts.PluginSearchOpts) { - using namespace PluginSearchOption; + switch (entry.getKind()) { // Try '-load-plugin-library'. - if (auto *val = entry.dyn_cast()) { - if (llvm::sys::path::filename(val->LibraryPath) == pluginLibBasename) { - return {val->LibraryPath, ""}; + case PluginSearchOption::Kind::LoadPluginLibrary: { + auto &val = entry.get(); + if (llvm::sys::path::filename(val.LibraryPath) == pluginLibBasename) { + return {val.LibraryPath, ""}; } continue; } // Try '-load-plugin-executable'. - if (auto *v = entry.dyn_cast()) { + case PluginSearchOption::Kind::LoadPluginExecutable: { + auto &val = entry.get(); auto found = ExecutablePluginPaths.find(moduleName); - if (found != ExecutablePluginPaths.end()) { - return {"", std::string(found->second)}; + if (found != ExecutablePluginPaths.end() && + found->second == val.ExecutablePath) { + return {"", val.ExecutablePath}; } continue; } // Try '-plugin-path'. - if (auto *v = entry.dyn_cast()) { - SmallString<128> fullPath(v->SearchPath); + case PluginSearchOption::Kind::PluginPath: { + auto &val = entry.get(); + SmallString<128> fullPath(val.SearchPath); llvm::sys::path::append(fullPath, pluginLibBasename); if (fs->exists(fullPath)) { return {std::string(fullPath), ""}; @@ -90,14 +94,16 @@ PluginLoader::lookupPluginByModuleName(Identifier moduleName) { } // Try '-external-plugin-path'. - if (auto *v = entry.dyn_cast()) { - SmallString<128> fullPath(v->SearchPath); + case PluginSearchOption::Kind::ExternalPluginPath: { + auto &val = entry.get(); + SmallString<128> fullPath(val.SearchPath); llvm::sys::path::append(fullPath, pluginLibBasename); if (fs->exists(fullPath)) { - return {std::string(fullPath), v->ServerPath}; + return {std::string(fullPath), val.ServerPath}; } continue; } + } } return {}; diff --git a/lib/Serialization/ModuleFileSharedCore.cpp b/lib/Serialization/ModuleFileSharedCore.cpp index 25a07a36f2288..34bfe05c186e5 100644 --- a/lib/Serialization/ModuleFileSharedCore.cpp +++ b/lib/Serialization/ModuleFileSharedCore.cpp @@ -127,24 +127,24 @@ static bool readOptionsBlock(llvm::BitstreamCursor &cursor, extendedInfo.addExtraClangImporterOption(blobData); break; case options_block::PLUGIN_SEARCH_OPTION: { - unsigned optKind; - StringRef optStr; - options_block::ResilienceStrategyLayout::readRecord(scratch, optKind); - switch (PluginSearchOptionKind(optKind)) { + unsigned kind; + options_block::ResilienceStrategyLayout::readRecord(scratch, kind); + PluginSearchOption::Kind optKind; + switch (PluginSearchOptionKind(kind)) { case PluginSearchOptionKind::PluginPath: - optStr = "-plugin-path"; + optKind = PluginSearchOption::Kind::PluginPath; break; case PluginSearchOptionKind::ExternalPluginPath: - optStr = "-external-plugin-path"; + optKind = PluginSearchOption::Kind::ExternalPluginPath; break; case PluginSearchOptionKind::LoadPluginLibrary: - optStr = "-load-plugin-library"; + optKind = PluginSearchOption::Kind::LoadPluginLibrary; break; case PluginSearchOptionKind::LoadPluginExecutable: - optStr = "-load-plugin-executable"; + optKind = PluginSearchOption::Kind::LoadPluginExecutable; break; } - extendedInfo.addPluginSearchOption({optStr, blobData}); + extendedInfo.addPluginSearchOption({optKind, blobData}); break; } case options_block::IS_SIB: diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 4966a59b39e4f..d243dc2ad0cd8 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -1137,39 +1137,42 @@ void Serializer::writeHeader(const SerializationOptions &options) { // Macro plugins options_block::PluginSearchOptionLayout PluginSearchOpt(Out); for (auto &elem : options.PluginSearchOptions) { - if (auto *opt = elem.dyn_cast()) { + switch (elem.getKind()) { + case PluginSearchOption::Kind::PluginPath: { + auto &opt = elem.get(); PluginSearchOpt.emit(ScratchRecord, uint8_t(PluginSearchOptionKind::PluginPath), - opt->SearchPath); + opt.SearchPath); continue; } - if (auto *opt = - elem.dyn_cast()) { + case PluginSearchOption::Kind::ExternalPluginPath: { + auto &opt = elem.get(); PluginSearchOpt.emit( ScratchRecord, uint8_t(PluginSearchOptionKind::ExternalPluginPath), - opt->SearchPath + "#" + opt->ServerPath); + opt.SearchPath + "#" + opt.ServerPath); continue; } - if (auto *opt = - elem.dyn_cast()) { + case PluginSearchOption::Kind::LoadPluginLibrary: { + auto &opt = elem.get(); PluginSearchOpt.emit( ScratchRecord, uint8_t(PluginSearchOptionKind::LoadPluginLibrary), - opt->LibraryPath); + opt.LibraryPath); continue; } - if (auto *opt = - elem.dyn_cast()) { - std::string optStr = opt->ExecutablePath + "#"; + case PluginSearchOption::Kind::LoadPluginExecutable: { + auto &opt = elem.get(); + std::string optStr = opt.ExecutablePath + "#"; llvm::interleave( - opt->ModuleNames, [&](auto &name) { optStr += name; }, + opt.ModuleNames, [&](auto &name) { optStr += name; }, [&]() { optStr += ","; }); PluginSearchOpt.emit( ScratchRecord, uint8_t(PluginSearchOptionKind::LoadPluginExecutable), optStr); continue; } + } } } } diff --git a/tools/lldb-moduleimport-test/lldb-moduleimport-test.cpp b/tools/lldb-moduleimport-test/lldb-moduleimport-test.cpp index 648d2fb52ad80..4f0c4a44acd42 100644 --- a/tools/lldb-moduleimport-test/lldb-moduleimport-test.cpp +++ b/tools/lldb-moduleimport-test/lldb-moduleimport-test.cpp @@ -91,7 +91,22 @@ static bool validateModule( } llvm::outs() << "- Plugin Search Options:\n"; for (auto opt : extendedInfo.getPluginSearchOptions()) { - llvm::outs() << " " << opt.first << " " << opt.second << "\n"; + StringRef optStr; + switch (opt.first) { + case swift::PluginSearchOption::Kind::PluginPath: + optStr = "-plugin-path"; + break; + case swift::PluginSearchOption::Kind::ExternalPluginPath: + optStr = "-external-plugin-path"; + break; + case swift::PluginSearchOption::Kind::LoadPluginLibrary: + optStr = "-load-plugin-library"; + break; + case swift::PluginSearchOption::Kind::LoadPluginExecutable: + optStr = "-load-plugin-executable"; + break; + } + llvm::outs() << " " << optStr << " " << opt.second << "\n"; } } From 1ed9df0a0c25d4b5d08ac010db97544a17e00c2a Mon Sep 17 00:00:00 2001 From: Felipe de Azevedo Piovezan Date: Thu, 25 May 2023 11:21:46 -0400 Subject: [PATCH 26/41] [DebugInfo] Update tests to use opaque ptrs --- test/DebugInfo/EagerTypeMetadata.swift | 5 +- .../LoadableByAddress-allockstack.swift | 8 +- test/DebugInfo/ProtocolContainer.swift | 5 +- test/DebugInfo/WeakCapture.swift | 7 +- test/DebugInfo/any.swift | 6 +- test/DebugInfo/async-args.swift | 18 +-- test/DebugInfo/async-let-await.swift | 8 +- test/DebugInfo/async-let.swift | 14 +- test/DebugInfo/basic.swift | 20 ++- test/DebugInfo/byref-capture.swift | 5 +- test/DebugInfo/catch_let.swift | 11 +- test/DebugInfo/closure-args.swift | 15 +- test/DebugInfo/dbgvalue-insertpt.swift | 5 +- test/DebugInfo/debug_info_expression.sil | 11 +- test/DebugInfo/debug_value_addr.swift | 5 +- test/DebugInfo/debug_variable.sil | 5 +- test/DebugInfo/dynamic_layout.swift | 11 +- test/DebugInfo/generic_arg.swift | 17 ++- test/DebugInfo/generic_arg2.swift | 7 +- test/DebugInfo/generic_arg3.swift | 8 +- test/DebugInfo/generic_arg4.swift | 7 +- test/DebugInfo/generic_arg5.swift | 7 +- test/DebugInfo/generic_enum_closure.swift | 7 +- test/DebugInfo/guard-let.swift | 34 ++--- test/DebugInfo/initializer.swift | 9 +- test/DebugInfo/inlined-generics-basic.swift | 12 +- test/DebugInfo/inlined-generics.swift | 5 +- test/DebugInfo/inout.swift | 9 +- test/DebugInfo/iuo_arg.swift | 9 +- test/DebugInfo/let.swift | 5 +- test/DebugInfo/linetable-cleanups.swift | 10 +- test/DebugInfo/linetable-codeview.swift | 10 +- test/DebugInfo/move_function_dbginfo.swift | 128 +++++++++--------- .../move_function_dbginfo_async.swift | 122 ++++++++--------- test/DebugInfo/nostorage.swift | 5 +- test/DebugInfo/protocol-extension.swift | 7 +- test/DebugInfo/protocolarg.swift | 7 +- test/DebugInfo/resilient_debug_value.sil | 7 +- test/DebugInfo/return.swift | 17 ++- test/DebugInfo/self.swift | 5 +- test/DebugInfo/shadow_copies.swift | 17 +-- test/DebugInfo/shadowcopy-linetable.swift | 13 +- test/DebugInfo/sil_combine.sil | 5 +- test/DebugInfo/struct_resilience.swift | 14 +- test/DebugInfo/structs.swift | 5 +- test/DebugInfo/typearg.swift | 5 +- test/DebugInfo/uninitialized.swift | 20 ++- test/DebugInfo/variadic-generics-count.swift | 28 ++-- test/DebugInfo/variadic-generics.swift | 25 ++-- test/DebugInfo/weak-self-capture.swift | 5 +- 50 files changed, 339 insertions(+), 411 deletions(-) diff --git a/test/DebugInfo/EagerTypeMetadata.swift b/test/DebugInfo/EagerTypeMetadata.swift index d25d87b8f4918..e216d788fc7de 100644 --- a/test/DebugInfo/EagerTypeMetadata.swift +++ b/test/DebugInfo/EagerTypeMetadata.swift @@ -1,5 +1,4 @@ -// RUN: %target-swift-frontend %use_no_opaque_pointers %s -Onone -emit-ir -g -o - | %FileCheck %s -// RUN: %target-swift-frontend %s -Onone -emit-ir -g -o - +// RUN: %target-swift-frontend %s -Onone -emit-ir -g -o - | %FileCheck %s public class C { @@ -7,7 +6,7 @@ public class C { // Ensure that the type metadata for T is eagerly loaded at -Onone. // CHECK: define {{.*}} @"$s17EagerTypeMetadata1CC1cyyxF" - // CHECK: %T = load %swift.type*, %swift.type** + // CHECK: %T = load ptr, ptr // CHECK-SAME: !dbg ![[LOC:[0-9]+]], !invariant.load var x = [i] } diff --git a/test/DebugInfo/LoadableByAddress-allockstack.swift b/test/DebugInfo/LoadableByAddress-allockstack.swift index d602aaf052547..0c41e463ef1f2 100644 --- a/test/DebugInfo/LoadableByAddress-allockstack.swift +++ b/test/DebugInfo/LoadableByAddress-allockstack.swift @@ -1,13 +1,9 @@ // Check we don't crash when verifying debug info. // Ideally this should print the output after loadable by address runs // but there's no way of doing this in SIL (for IRGen passes). -// RUN: %target-swift-frontend %use_no_opaque_pointers -emit-sil %s -Onone \ -// RUN: -sil-verify-all -Xllvm -verify-di-holes -emit-ir \ -// RUN: -Xllvm -sil-print-debuginfo -g -o - | %FileCheck %s - // RUN: %target-swift-frontend -emit-sil %s -Onone \ // RUN: -sil-verify-all -Xllvm -verify-di-holes -emit-ir \ -// RUN: -Xllvm -sil-print-debuginfo -g -o - +// RUN: -Xllvm -sil-print-debuginfo -g -o - | %FileCheck %s struct m { let major: Int @@ -50,4 +46,4 @@ struct h{ } } -// CHECK: define internal %swift.opaque* @"$s4main1mVwCP" +// CHECK: define internal ptr @"$s4main1mVwCP" diff --git a/test/DebugInfo/ProtocolContainer.swift b/test/DebugInfo/ProtocolContainer.swift index 5ef5ee54ad894..1057ea8c3ed12 100644 --- a/test/DebugInfo/ProtocolContainer.swift +++ b/test/DebugInfo/ProtocolContainer.swift @@ -1,5 +1,4 @@ -// RUN: %target-swift-frontend %use_no_opaque_pointers %s -emit-ir -g -o - | %FileCheck %s -// RUN: %target-swift-frontend %s -emit-ir -g -o - +// RUN: %target-swift-frontend %s -emit-ir -g -o - | %FileCheck %s func markUsed(_ t: T) {} @@ -15,7 +14,7 @@ class AClass : AProtocol { // CHECK: define hidden {{.*}}void @"$s17ProtocolContainer3foo{{[_0-9a-zA-Z]*}}F" // CHECK-NEXT: entry: // CHECK: %[[X:.*]] = alloca %T17ProtocolContainer9AProtocolP, align {{(4|8)}} -// CHECK: call void @llvm.dbg.declare(metadata %T17ProtocolContainer9AProtocolP* %[[X]], metadata ![[XMD:.*]], metadata !DIExpression()) +// CHECK: call void @llvm.dbg.declare(metadata ptr %[[X]], metadata ![[XMD:.*]], metadata !DIExpression()) // CHECK-NOT: !DILocalVariable({{.*}} name: "x" // CHECK-NOT: !DILocalVariable({{.*}} name: "x" func foo (_ x : AProtocol) { diff --git a/test/DebugInfo/WeakCapture.swift b/test/DebugInfo/WeakCapture.swift index 1a6581c38c29a..d05c73262f9db 100644 --- a/test/DebugInfo/WeakCapture.swift +++ b/test/DebugInfo/WeakCapture.swift @@ -1,5 +1,4 @@ -// RUN: %target-swift-frontend %use_no_opaque_pointers %s -emit-ir -g -o - | %FileCheck %s -// RUN: %target-swift-frontend %s -emit-ir -g -o - +// RUN: %target-swift-frontend %s -emit-ir -g -o - | %FileCheck %s class A { init(handler: (() -> ())) { } } @@ -11,9 +10,9 @@ func function() { let b = B() // Ensure that the local b and its weak copy are distinct local variables. - // CHECK: call void @llvm.dbg.{{.*}}(metadata %T11WeakCapture1BC* + // CHECK: call void @llvm.dbg.{{.*}}(metadata ptr // CHECK-SAME: metadata [[B:.*]], metadata - // CHECK: call void @llvm.dbg.{{.*}}(metadata %swift.weak* + // CHECK: call void @llvm.dbg.{{.*}}(metadata ptr // CHECK-NOT: metadata [[B]] // CHECK: call A(handler: { [weak b] in diff --git a/test/DebugInfo/any.swift b/test/DebugInfo/any.swift index fb04492286e9a..1d9f26d251717 100644 --- a/test/DebugInfo/any.swift +++ b/test/DebugInfo/any.swift @@ -1,10 +1,10 @@ -// RUN: %target-swift-frontend %use_no_opaque_pointers %s -emit-ir -g -o - | %FileCheck %s -// RUN: %target-swift-frontend %s -emit-ir -g -o - +// RUN: %target-swift-frontend %s -emit-ir -g -o - | %FileCheck %s func markUsed(_ t: T) {} func main() { - // CHECK: call void @llvm.dbg.declare(metadata %Any* {{.*}}, metadata ![[S:.*]], metadata !DIExpression()), !dbg ![[DBG:.*]] + // CHECK: define hidden swiftcc void @"$s3any4mainyyF" + // CHECK: call void @llvm.dbg.declare(metadata ptr {{.*}}, metadata ![[S:.*]], metadata !DIExpression()), !dbg ![[DBG:.*]] // CHECK: ![[S]] = !DILocalVariable(name: "s", {{.*}}line: [[@LINE+2]] // CHECK: ![[DBG]] = !DILocation(line: [[@LINE+1]], column: 7, var s: Any = "hello world" diff --git a/test/DebugInfo/async-args.swift b/test/DebugInfo/async-args.swift index 5e98671f4bc77..080c479eb1a4f 100644 --- a/test/DebugInfo/async-args.swift +++ b/test/DebugInfo/async-args.swift @@ -1,10 +1,6 @@ -// RUN: %target-swift-frontend %use_no_opaque_pointers %s -emit-ir -g -o - \ -// RUN: -module-name M -disable-availability-checking \ -// RUN: -parse-as-library | %FileCheck %s - // RUN: %target-swift-frontend %s -emit-ir -g -o - \ // RUN: -module-name M -disable-availability-checking \ -// RUN: -parse-as-library +// RUN: -parse-as-library | %FileCheck %s // REQUIRES: concurrency @@ -14,14 +10,14 @@ func forceSplit() async { func withGenericArg(_ msg: T) async { // This odd debug info is part of a contract with CoroSplit/CoroFrame to fix // this up after coroutine splitting. - // CHECK-LABEL: {{^define .*}} @"$s1M14withGenericArgyyxYalF"(%swift.context* swiftasync %0 - // CHECK-DAG: call void @llvm.dbg.declare(metadata %swift.context* %0, metadata ![[MSG:[0-9]+]], metadata !DIExpression({{.*}}DW_OP_plus_uconst, {{.*}}DW_OP_deref)) - // CHECK-DAG: call void @llvm.dbg.declare(metadata %swift.context* %0, metadata ![[TAU:[0-9]+]], metadata !DIExpression({{.*}}DW_OP_plus_uconst, + // CHECK-LABEL: {{^define .*}} @"$s1M14withGenericArgyyxYalF"(ptr swiftasync %0 + // CHECK-DAG: call void @llvm.dbg.declare(metadata ptr %0, metadata ![[MSG:[0-9]+]], metadata !DIExpression({{.*}}DW_OP_plus_uconst, {{.*}}DW_OP_deref)) + // CHECK-DAG: call void @llvm.dbg.declare(metadata ptr %0, metadata ![[TAU:[0-9]+]], metadata !DIExpression({{.*}}DW_OP_plus_uconst, await forceSplit() - // CHECK-LABEL: {{^define .*}} @"$s1M14withGenericArgyyxYalFTQ0_"(i8* swiftasync %0) - // CHECK-DAG: call void @llvm.dbg.declare(metadata i8* %0, metadata ![[MSG_R:[0-9]+]], metadata !DIExpression({{.*}}DW_OP_plus_uconst, [[OFFSET:[0-9]+]], DW_OP_plus_uconst, {{[0-9]+}}, DW_OP_deref)) - // CHECK-DAG: call void @llvm.dbg.declare(metadata i8* %0, metadata ![[TAU_R:[0-9]+]], metadata !DIExpression({{.*}}DW_OP_deref, DW_OP_plus_uconst, [[OFFSET]], DW_OP_plus_uconst, {{[0-9]+}})) + // CHECK-LABEL: {{^define .*}} @"$s1M14withGenericArgyyxYalFTQ0_"(ptr swiftasync %0) + // CHECK-DAG: call void @llvm.dbg.declare(metadata ptr %0, metadata ![[MSG_R:[0-9]+]], metadata !DIExpression({{.*}}DW_OP_plus_uconst, [[OFFSET:[0-9]+]], DW_OP_plus_uconst, {{[0-9]+}}, DW_OP_deref)) + // CHECK-DAG: call void @llvm.dbg.declare(metadata ptr %0, metadata ![[TAU_R:[0-9]+]], metadata !DIExpression({{.*}}DW_OP_deref, DW_OP_plus_uconst, [[OFFSET]], DW_OP_plus_uconst, {{[0-9]+}})) use(msg) } // CHECK-LABEL: {{^define }} diff --git a/test/DebugInfo/async-let-await.swift b/test/DebugInfo/async-let-await.swift index fd408e439fb46..24bd90ef2244e 100644 --- a/test/DebugInfo/async-let-await.swift +++ b/test/DebugInfo/async-let-await.swift @@ -1,10 +1,6 @@ -// RUN: %target-swift-frontend %use_no_opaque_pointers %s -emit-ir -g -o - \ -// RUN: -module-name M -disable-availability-checking \ -// RUN: -parse-as-library | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize - // RUN: %target-swift-frontend %s -emit-ir -g -o - \ // RUN: -module-name M -disable-availability-checking \ -// RUN: -parse-as-library +// RUN: -parse-as-library | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize // REQUIRES: concurrency @@ -16,7 +12,7 @@ public func getVegetables() async -> [String] { public func chopVegetables() async throws -> [String] { let veggies = await getVegetables() // CHECK-NOT: {{^define }} - // CHECK: call void @llvm.dbg.declare(metadata i8* %0, metadata ![[V:[0-9]+]], metadata !DIExpression(DW_OP_deref, DW_OP_plus_uconst, {{[0-9]+}}, DW_OP_plus_uconst, {{[0-9]+}}) + // CHECK: call void @llvm.dbg.declare(metadata ptr %0, metadata ![[V:[0-9]+]], metadata !DIExpression(DW_OP_deref, DW_OP_plus_uconst, {{[0-9]+}}, DW_OP_plus_uconst, {{[0-9]+}}) // CHECK: ![[V]] = !DILocalVariable(name: "veggies" return veggies.map { "chopped \($0)" } } diff --git a/test/DebugInfo/async-let.swift b/test/DebugInfo/async-let.swift index 4c45e8ea036b2..627397b2d0259 100644 --- a/test/DebugInfo/async-let.swift +++ b/test/DebugInfo/async-let.swift @@ -1,10 +1,6 @@ -// RUN: %target-swift-frontend %use_no_opaque_pointers %s -emit-ir -g -o - \ -// RUN: -module-name M -disable-availability-checking \ -// RUN: -parse-as-library | %FileCheck %s --check-prefix=CHECK - // RUN: %target-swift-frontend %s -emit-ir -g -o - \ // RUN: -module-name M -disable-availability-checking \ -// RUN: -parse-as-library +// RUN: -parse-as-library | %FileCheck %s --check-prefix=CHECK // REQUIRES: concurrency @@ -12,16 +8,16 @@ public actor Alice { let bob = Bob() // CHECK: define {{.*}}$s1M5AliceC4callyyYaFTY0_{{.*}} !dbg ![[SCOPE0:[0-9]+]] - // CHECK: call i8* @__swift_async_resume_get_context{{.*}}!dbg ![[HOP0:[0-9]+]] + // CHECK: call ptr @__swift_async_resume_get_context{{.*}}!dbg ![[HOP0:[0-9]+]] // CHECK: define {{.*}}$s1M5AliceC4callyyYaFTY1_{{.*}} !dbg ![[SCOPE1:[0-9]+]] - // CHECK: call i8* @__swift_async_resume_get_context{{.*}}!dbg ![[HOP1:[0-9]+]] + // CHECK: call ptr @__swift_async_resume_get_context{{.*}}!dbg ![[HOP1:[0-9]+]] // CHECK: define {{.*}}$s1M5AliceC4callyyYaFSiyYaYbcfu_TY0_{{.*}} !dbg ![[LET_SCOPE0:[0-9]+]] - // CHECK: call i8* @__swift_async_resume_get_context{{.*}}!dbg ![[LET_HOP0:[0-9]+]] + // CHECK: call ptr @__swift_async_resume_get_context{{.*}}!dbg ![[LET_HOP0:[0-9]+]] // CHECK: define {{.*}}$s1M5AliceC4callyyYaFSiyYaYbcfu_TY2_{{.*}} !dbg ![[LET_SCOPE1:[0-9]+]] - // CHECK: call i8* @__swift_async_resume_get_context{{.*}}!dbg ![[LET_HOP1:[0-9]+]] + // CHECK: call ptr @__swift_async_resume_get_context{{.*}}!dbg ![[LET_HOP1:[0-9]+]] public func call() async { // CHECK: ![[SCOPE0]] = distinct !DISubprogram({{.*}}line: [[@LINE-1]] // CHECK: ![[HOP0]] = !DILocation(line: [[@LINE-2]], column: 15 diff --git a/test/DebugInfo/basic.swift b/test/DebugInfo/basic.swift index a63dee7403dd0..86aca41b4171d 100644 --- a/test/DebugInfo/basic.swift +++ b/test/DebugInfo/basic.swift @@ -20,23 +20,19 @@ // CHECK-LINETABLES-NOT: DIBasicType // -------------------------------------------------------------------- // Now check that we do generate line+scope info with -g. -// RUN: %target-swift-frontend %use_no_opaque_pointers %/s -emit-ir -g -o - \ +// RUN: %target-swift-frontend %/s -emit-ir -g -o - \ // RUN: | %FileCheck %s --check-prefixes CHECK,DWARF-CHECK -// RUN: %target-swift-frontend %/s -emit-ir -g -o - // -------------------------------------------------------------------- // Currently -gdwarf-types should give the same results as -g. -// RUN: %target-swift-frontend %use_no_opaque_pointers %/s -emit-ir -gdwarf-types -o - \ +// RUN: %target-swift-frontend %/s -emit-ir -gdwarf-types -o - \ // RUN: | %FileCheck %s --check-prefixes CHECK,DWARF-CHECK -// RUN: %target-swift-frontend %/s -emit-ir -gdwarf-types -o - // -------------------------------------------------------------------- // Verify that -g -debug-info-format=dwarf gives the same results as -g. -// RUN: %target-swift-frontend %use_no_opaque_pointers %/s -emit-ir -g -debug-info-format=dwarf -o - \ +// RUN: %target-swift-frontend %/s -emit-ir -g -debug-info-format=dwarf -o - \ // RUN: | %FileCheck %s --check-prefixes CHECK,DWARF-CHECK -// RUN: %target-swift-frontend %/s -emit-ir -g -debug-info-format=dwarf -o - // -------------------------------------------------------------------- -// RUN: %target-swift-frontend %use_no_opaque_pointers %/s -emit-ir -g -debug-info-format=codeview -o - \ +// RUN: %target-swift-frontend %/s -emit-ir -g -debug-info-format=codeview -o - \ // RUN: | %FileCheck %s --check-prefixes CHECK,CV-CHECK -// RUN: %target-swift-frontend %/s -emit-ir -g -debug-info-format=codeview -o - // -------------------------------------------------------------------- // // CHECK: foo @@ -48,12 +44,12 @@ func foo(_ a: Int64, _ b: Int64) -> Int64 { var b = b // CHECK-DAG: ![[ALOC:.*]] = !DILocation(line: [[@LINE-3]],{{.*}} scope: ![[FOO]]) // Check that a is the first and b is the second argument. - // CHECK-DAG: store i64 %0, i64* [[AADDR:.*]], align - // CHECK-DAG: store i64 %1, i64* [[BADDR:.*]], align + // CHECK-DAG: store i64 %0, ptr [[AADDR:.*]], align + // CHECK-DAG: store i64 %1, ptr [[BADDR:.*]], align // CHECK-DAG: [[AVAL:%.*]] = getelementptr inbounds {{.*}}, [[AMEM:.*]], i32 0, i32 0 // CHECK-DAG: [[BVAL:%.*]] = getelementptr inbounds {{.*}}, [[BMEM:.*]], i32 0, i32 0 - // CHECK-DAG: call void @llvm.dbg.declare(metadata i64* [[AADDR]], metadata ![[AARG:.*]], metadata !DIExpression()), !dbg ![[ALOC]] - // CHECK-DAG: call void @llvm.dbg.declare(metadata i64* [[BADDR]], metadata ![[BARG:.*]], metadata !DIExpression()) + // CHECK-DAG: call void @llvm.dbg.declare(metadata ptr [[AADDR]], metadata ![[AARG:.*]], metadata !DIExpression()), !dbg ![[ALOC]] + // CHECK-DAG: call void @llvm.dbg.declare(metadata ptr [[BADDR]], metadata ![[BARG:.*]], metadata !DIExpression()) // CHECK-DAG: ![[AARG]] = !DILocalVariable(name: "a", arg: 1 // CHECK-DAG: ![[BARG]] = !DILocalVariable(name: "b", arg: 2 if b != 0 { diff --git a/test/DebugInfo/byref-capture.swift b/test/DebugInfo/byref-capture.swift index 3816a0754ed2e..34e072719599a 100644 --- a/test/DebugInfo/byref-capture.swift +++ b/test/DebugInfo/byref-capture.swift @@ -1,12 +1,11 @@ -// RUN: %target-swift-frontend %use_no_opaque_pointers %s -emit-ir -g -o - | %FileCheck %s -// RUN: %target-swift-frontend %s -emit-ir -g -o - +// RUN: %target-swift-frontend %s -emit-ir -g -o - | %FileCheck %s func makeIncrementor(_ inc : Int64) -> () -> Int64 { var sum : Int64 = 0 // CHECK: define {{.*}}5inner func inner() -> Int64 { - // CHECK: call void @llvm.dbg.declare(metadata %Ts5Int64V** + // CHECK: call void @llvm.dbg.declare(metadata ptr // CHECK-SAME: metadata ![[SUM_CAPTURE:[0-9]+]], // CHECK-SAME: metadata !DIExpression(DW_OP_deref)) // CHECK: ![[INOUTTY:[0-9]+]] = !DICompositeType({{.*}}identifier: "$ss5Int64VD" diff --git a/test/DebugInfo/catch_let.swift b/test/DebugInfo/catch_let.swift index 4f260d767ebcb..1fc704687b56a 100644 --- a/test/DebugInfo/catch_let.swift +++ b/test/DebugInfo/catch_let.swift @@ -1,5 +1,4 @@ -// RUN: %target-swift-frontend %use_no_opaque_pointers %s -emit-ir -g -o - | %FileCheck %s -// RUN: %target-swift-frontend %s -emit-ir -g -o - +// RUN: %target-swift-frontend %s -emit-ir -g -o - | %FileCheck %s enum MyError : Error { case Yikes @@ -17,7 +16,7 @@ public func explicitBinding() { try throwing() } catch let error { - // CHECK: call void @llvm.dbg.declare(metadata %swift.error** %{{.*}}, metadata ![[EXPLICIT_ERROR:[0-9]+]], + // CHECK: call void @llvm.dbg.declare(metadata ptr %{{.*}}, metadata ![[EXPLICIT_ERROR:[0-9]+]], use(error) } } @@ -29,7 +28,7 @@ public func implicitBinding() { try throwing() } catch { - // CHECK: call void @llvm.dbg.declare(metadata %swift.error** %{{.*}}, metadata ![[IMPLICIT_ERROR:[0-9]+]], + // CHECK: call void @llvm.dbg.declare(metadata ptr %{{.*}}, metadata ![[IMPLICIT_ERROR:[0-9]+]], use(error) } } @@ -41,8 +40,8 @@ public func multiBinding() { try throwing() } catch let error as MyError, let error as MyError { - // CHECK: call void @llvm.dbg.declare(metadata %swift.error** %{{.*}}, metadata ![[MULTI_BINDING_ERROR:[0-9]+]], - // CHECK-NOT: call void @llvm.dbg.declare(metadata %swift.error** %{{.*}} + // CHECK: call void @llvm.dbg.declare(metadata ptr %{{.*}}, metadata ![[MULTI_BINDING_ERROR:[0-9]+]], + // CHECK-NOT: call void @llvm.dbg.declare(metadata ptr %{{.*}} use(error) } catch { use(error) diff --git a/test/DebugInfo/closure-args.swift b/test/DebugInfo/closure-args.swift index 19c3f837031de..cc15b45004eb7 100644 --- a/test/DebugInfo/closure-args.swift +++ b/test/DebugInfo/closure-args.swift @@ -1,5 +1,4 @@ -// RUN: %target-swift-frontend %use_no_opaque_pointers %s -emit-ir -g -o - | %FileCheck %s -// RUN: %target-swift-frontend %s -emit-ir -g -o - +// RUN: %target-swift-frontend %s -emit-ir -g -o - | %FileCheck %s import Swift @@ -12,20 +11,20 @@ func main() -> Void var backward_ptr = // CHECK: define internal {{.*}} i1 @"$s4mainAAyyFSbSS_SStcfU_"( - // CHECK: %[[RANDOM_STR_ADDR:.*]] = alloca %TSS*, align {{(4|8)}} + // CHECK: %[[RANDOM_STR_ADDR:.*]] = alloca ptr, align {{(4|8)}} // FIXME(TODO: JIRA): i386 String is temporarily larger, and that causes the // value to be by-address. When that is fixed, remove the optional // DW_OP_deref below. // - // CHECK-NEXT: call void @llvm.dbg.declare(metadata %TSS** %[[RANDOM_STR_ADDR]], metadata !{{.*}}, metadata !DIExpression({{(DW_OP_deref)?}})), !dbg + // CHECK-NEXT: call void @llvm.dbg.declare(metadata ptr %[[RANDOM_STR_ADDR]], metadata !{{.*}}, metadata !DIExpression({{(DW_OP_deref)?}})), !dbg - // CHECK: store %TSS* %{{.*}}, %TSS** %[[RANDOM_STR_ADDR]], align {{(4|8)}} + // CHECK: store ptr %{{.*}}, ptr %[[RANDOM_STR_ADDR]], align {{(4|8)}} // CHECK-DAG: !DILocalVariable(name: "lhs",{{.*}} line: [[@LINE+5]], // CHECK-DAG: !DILocalVariable(name: "rhs",{{.*}} line: [[@LINE+4]], - // CHECK-DAG: !DILocalVariable(name: "random_string",{{.*}} line: 9, - // CHECK-DAG: !DILocalVariable(name: "random_int",{{.*}} line: 10, - // CHECK-DAG: !DILocalVariable(name: "out_only",{{.*}} line: 11, + // CHECK-DAG: !DILocalVariable(name: "random_string",{{.*}} line: 8, + // CHECK-DAG: !DILocalVariable(name: "random_int",{{.*}} line: 9, + // CHECK-DAG: !DILocalVariable(name: "out_only",{{.*}} line: 10, { (lhs : String, rhs : String) -> Bool in if rhs == random_string || rhs.unicodeScalars.count == random_int diff --git a/test/DebugInfo/dbgvalue-insertpt.swift b/test/DebugInfo/dbgvalue-insertpt.swift index c5afa4bfaba0b..b5612ec8ea7c3 100644 --- a/test/DebugInfo/dbgvalue-insertpt.swift +++ b/test/DebugInfo/dbgvalue-insertpt.swift @@ -1,11 +1,10 @@ -// RUN: %target-swift-frontend %use_no_opaque_pointers -g -emit-ir -Xllvm '-sil-inline-never-functions=next' %s | %FileCheck %s -// RUN: %target-swift-frontend -g -emit-ir -Xllvm '-sil-inline-never-functions=next' %s +// RUN: %target-swift-frontend -g -emit-ir -Xllvm '-sil-inline-never-functions=next' %s | %FileCheck %s // FIXME: This test should be testing a non-shadow-copied value instead. for i in 0 ..< 3 { // CHECK: %[[ALLOCA:[0-9]+]] = alloca %TSiSg // CHECK: %i.debug = alloca i{{32|64}} - // CHECK-NEXT: call void @llvm.dbg.declare(metadata i{{32|64}}* %i.debug, + // CHECK-NEXT: call void @llvm.dbg.declare(metadata ptr %i.debug, // CHECK-SAME: metadata ![[I:[0-9]+]], // CHECK: ![[I]] = !DILocalVariable(name: "i", } diff --git a/test/DebugInfo/debug_info_expression.sil b/test/DebugInfo/debug_info_expression.sil index 185b15c2297be..3957fcda09483 100644 --- a/test/DebugInfo/debug_info_expression.sil +++ b/test/DebugInfo/debug_info_expression.sil @@ -1,6 +1,5 @@ // RUN: %target-swift-frontend %s -sil-verify-all -g -emit-sil -o - | %FileCheck --check-prefix=CHECK-SIL %s -// RUN: %target-swift-frontend %use_no_opaque_pointers -disable-debugger-shadow-copies -primary-file %s -emit-ir -g -o - | %FileCheck %s -// RUN: %target-swift-frontend -disable-debugger-shadow-copies -primary-file %s -emit-ir -g -o - +// RUN: %target-swift-frontend -disable-debugger-shadow-copies -primary-file %s -emit-ir -g -o - | %FileCheck %s import Builtin import Swift @@ -20,9 +19,9 @@ sil hidden @test_fragment : $@convention(thin) () -> () { bb0: %2 = alloc_stack $MyStruct, var, name "my_struct", loc "file.swift":8:9, scope 1 // CHECK: %[[MY_STRUCT:.+]] = alloca %{{.*}}MyStruct - // CHECK: llvm.dbg.declare(metadata {{.*}}* %[[MY_STRUCT]], metadata ![[VAR_DECL_MD:[0-9]+]] + // CHECK: llvm.dbg.declare(metadata {{.*}} %[[MY_STRUCT]], metadata ![[VAR_DECL_MD:[0-9]+]] // CHECK: %[[SMALL_STRUCT:.+]] = alloca %{{.*}}SmallStruct - // CHECK: llvm.dbg.declare(metadata {{.*}}* %[[SMALL_STRUCT]], metadata ![[SMALL_VAR_DECL_MD:[0-9]+]] + // CHECK: llvm.dbg.declare(metadata {{.*}} %[[SMALL_STRUCT]], metadata ![[SMALL_VAR_DECL_MD:[0-9]+]] %3 = struct_element_addr %2 : $*MyStruct, #MyStruct.x, loc "file.swift":9:17, scope 1 // CHECK: %[[FIELD_X:.*]] = getelementptr {{.*}} %[[MY_STRUCT]] // CHECK-SIL: debug_value %{{[0-9]+}} : $*Builtin.Int64 @@ -50,13 +49,13 @@ sil hidden @test_alloc_stack : $@convention(thin) () -> () { bb0: %my_struct = alloc_stack $MyStruct, var, name "my_struct", loc "file.swift":15:9, scope 2 // CHECK: %[[MY_STRUCT:.+]] = alloca %{{.*}}MyStruct - // CHECK: llvm.dbg.declare(metadata {{.*}}* %[[MY_STRUCT]], metadata ![[VAR_DECL_MD:[0-9]+]] + // CHECK: llvm.dbg.declare(metadata ptr %[[MY_STRUCT]], metadata ![[VAR_DECL_MD:[0-9]+]] // CHECK-SIL: alloc_stack $Int, var // CHECK-SIL-SAME: (name "my_struct", loc "file.swift":15:9, scope {{[0-9]+}}) // CHECK-SIL-SAME: type $MyStruct, expr op_fragment:#MyStruct.x %field_x = alloc_stack $Int, var, (name "my_struct", loc "file.swift":15:9, scope 2), type $MyStruct, expr op_fragment:#MyStruct.x, loc "file.swift":16:17, scope 2 // CHECK: %[[FIELD_X:.+]] = alloca %TSi - // CHECK: llvm.dbg.declare(metadata %TSi* %[[FIELD_X]], metadata ![[VAR_DECL_MD]] + // CHECK: llvm.dbg.declare(metadata ptr %[[FIELD_X]], metadata ![[VAR_DECL_MD]] // CHECK-SAME: !DIExpression(DW_OP_LLVM_fragment, 0, 64) dealloc_stack %field_x : $*Int dealloc_stack %my_struct: $*MyStruct diff --git a/test/DebugInfo/debug_value_addr.swift b/test/DebugInfo/debug_value_addr.swift index 0152b8a4d7fb4..e104dcd35a005 100644 --- a/test/DebugInfo/debug_value_addr.swift +++ b/test/DebugInfo/debug_value_addr.swift @@ -1,5 +1,4 @@ -// RUN: %target-swift-frontend %use_no_opaque_pointers -primary-file %s -emit-ir -g -o - | %FileCheck %s -// RUN: %target-swift-frontend -primary-file %s -emit-ir -g -o - +// RUN: %target-swift-frontend -primary-file %s -emit-ir -g -o - | %FileCheck %s // RUN: %target-swift-frontend %s -emit-sil -g -o - | %FileCheck -check-prefix=CHECK-SIL %s // Verify that -Onone shadow copies are emitted for debug_value_addr @@ -12,7 +11,7 @@ // CHECK: entry: // CHECK-NEXT: %[[TADDR:.*]] = alloca // CHECK-NEXT: call void @llvm.dbg.declare({{.*}}%[[TADDR]] -// CHECK: store %swift.opaque* %0, %swift.opaque** %[[TADDR:.*]], align +// CHECK: store ptr %0, ptr %[[TADDR:.*]], align struct S { var a : T diff --git a/test/DebugInfo/debug_variable.sil b/test/DebugInfo/debug_variable.sil index ca2cbc7bee896..b6070b5a810ee 100644 --- a/test/DebugInfo/debug_variable.sil +++ b/test/DebugInfo/debug_variable.sil @@ -1,5 +1,4 @@ -// RUN: %target-swiftc_driver %use_no_opaque_pointers -g -emit-ir %s | %FileCheck %s -// RUN: %target-swiftc_driver -g -emit-ir %s +// RUN: %target-swiftc_driver -g -emit-ir %s | %FileCheck %s sil_stage canonical import Builtin @@ -14,7 +13,7 @@ sil_scope 2 { loc "simple.swift":1:2 parent @test_debug_value : $@convention(thi // CHECK-SAME: !dbg ![[FUNC_DI:[0-9]+]] sil hidden @test_debug_value : $@convention(thin) (Int) -> () { bb0(%0 : $Int): - // CHECK: @llvm.dbg.declare(metadata i{{[0-9]+}}* + // CHECK: @llvm.dbg.declare(metadata ptr // CHECK-SAME: metadata ![[VAR_DI:[0-9]+]] // CHECK-SAME: ), !dbg ![[LOC_DI:[0-9]+]] debug_value %0 : $Int, let, name "x", argno 1, loc "simple.swift":3:4, scope 2 diff --git a/test/DebugInfo/dynamic_layout.swift b/test/DebugInfo/dynamic_layout.swift index ff37b293b4acb..dafd0bce55cde 100644 --- a/test/DebugInfo/dynamic_layout.swift +++ b/test/DebugInfo/dynamic_layout.swift @@ -1,5 +1,4 @@ -// RUN: %target-swift-frontend %use_no_opaque_pointers %s -emit-ir -g -o - | %FileCheck %s -// RUN: %target-swift-frontend %s -emit-ir -g -o - +// RUN: %target-swift-frontend %s -emit-ir -g -o - | %FileCheck %s func markUsed(_ t: T) {} @@ -10,11 +9,11 @@ class Class { // Verify that the mangling of the type U is correct. // CHECK: define {{.*}}3foo - // CHECK: %[[U1:.*]] = alloca %swift.type* - // CHECK: call void @llvm.dbg.declare(metadata %swift.type** %[[U1]], + // CHECK: %[[U1:.*]] = alloca ptr + // CHECK: call void @llvm.dbg.declare(metadata ptr %[[U1]], // CHECK-SAME: metadata ![[U:[0-9]+]] - // CHECK: %[[T2:.*]] = alloca %swift.type* - // CHECK: call void @llvm.dbg.declare(metadata %swift.type** %[[T2]], + // CHECK: %[[T2:.*]] = alloca ptr + // CHECK: call void @llvm.dbg.declare(metadata ptr %[[T2]], // CHECK-SAME: metadata ![[T:[0-9]+]] // CHECK: ![[U]] = !DILocalVariable(name: "$\CF\84_1_0" // CHECK: ![[T]] = !DILocalVariable(name: "$\CF\84_0_0" diff --git a/test/DebugInfo/generic_arg.swift b/test/DebugInfo/generic_arg.swift index f09763da4a3ec..00acddb3fc2e1 100644 --- a/test/DebugInfo/generic_arg.swift +++ b/test/DebugInfo/generic_arg.swift @@ -1,18 +1,17 @@ -// RUN: %target-swift-frontend %use_no_opaque_pointers %s -emit-ir -g -o - | %FileCheck %s -// RUN: %target-swift-frontend %s -emit-ir -g -o - +// RUN: %target-swift-frontend %s -emit-ir -g -o - | %FileCheck %s import StdlibUnittest func foo(_ x: T) -> () { // CHECK: define {{.*}} @"$s11generic_arg3fooyyxlF" - // CHECK: %[[T:.*]] = alloca %swift.type* - // CHECK: call void @llvm.dbg.declare(metadata %swift.type** %[[T]], + // CHECK: %[[T:.*]] = alloca ptr + // CHECK: call void @llvm.dbg.declare(metadata ptr %[[T]], // CHECK-SAME: metadata ![[T1:.*]], metadata !DIExpression()) - // CHECK: %[[X:.*]] = alloca %swift.opaque* - // CHECK: call void @llvm.dbg.declare(metadata %swift.opaque** %[[X]], + // CHECK: %[[X:.*]] = alloca ptr + // CHECK: call void @llvm.dbg.declare(metadata ptr %[[X]], // CHECK-SAME: metadata ![[X1:.*]], metadata !DIExpression(DW_OP_deref)) - // CHECK: store %swift.type* %T, %swift.type** %[[T]], - // CHECK: store %swift.opaque* %0, %swift.opaque** %[[X]], + // CHECK: store ptr %T, ptr %[[T]], + // CHECK: store ptr %0, ptr %[[X]], // CHECK-DAG: ![[T1]] = !DILocalVariable(name: "$\CF\84_0_0",{{.*}}flags: DIFlagArtificial) - // CHECK-DAG: ![[X1]] = !DILocalVariable(name: "x", arg: 1,{{.*}}line: 4, type: ![[LET_TY2:[0-9]+]]) + // CHECK-DAG: ![[X1]] = !DILocalVariable(name: "x", arg: 1,{{.*}}line: 3, type: ![[LET_TY2:[0-9]+]]) // CHECK-DAG: ![[LET_TY2]] = !DIDerivedType(tag: DW_TAG_const_type,{{.*}}baseType: ![[TY2:[0-9]+]]) // CHECK-DAG: ![[TY2]] = !DICompositeType({{.*}}name: "$sxD" _blackHole(x) diff --git a/test/DebugInfo/generic_arg2.swift b/test/DebugInfo/generic_arg2.swift index 43d72a5b96da8..8876a76a38496 100644 --- a/test/DebugInfo/generic_arg2.swift +++ b/test/DebugInfo/generic_arg2.swift @@ -1,8 +1,7 @@ -// RUN: %target-swift-frontend %use_no_opaque_pointers %s -emit-ir -g -o - | %FileCheck %s -// RUN: %target-swift-frontend %s -emit-ir -g -o - +// RUN: %target-swift-frontend %s -emit-ir -g -o - | %FileCheck %s -// CHECK: define hidden swiftcc void @"$s12generic_arg25ClassC3foo{{.*}}, %swift.type* %U -// CHECK: call void @llvm.dbg.declare(metadata %swift.opaque** %y.debug, metadata ![[U:.*]], metadata !DIExpression(DW_OP_deref)) +// CHECK: define hidden swiftcc void @"$s12generic_arg25ClassC3foo{{.*}}, ptr %U +// CHECK: call void @llvm.dbg.declare(metadata ptr %y.debug, metadata ![[U:.*]], metadata !DIExpression(DW_OP_deref)) // Make sure there is no conflicting dbg.value for this variable.x // CHECK-NOT: dbg.value{{.*}}metadata ![[U]] class Class { diff --git a/test/DebugInfo/generic_arg3.swift b/test/DebugInfo/generic_arg3.swift index 93b5bc85d2d68..2844bcedf4201 100644 --- a/test/DebugInfo/generic_arg3.swift +++ b/test/DebugInfo/generic_arg3.swift @@ -1,14 +1,12 @@ -// RUN: %target-swift-frontend %use_no_opaque_pointers %s -emit-ir -g -o - | %FileCheck %s -// RUN: %target-swift-frontend %s -emit-ir -g -o - +// RUN: %target-swift-frontend %s -emit-ir -g -o - | %FileCheck %s func apply(_ T : Type, fn: (Type) -> Type) -> Type { return fn(T) } public func f(_ value : Type) { // CHECK: define {{.*}}$s12generic_arg31fyyxlFxxXEfU_ - // CHECK: call void @llvm.dbg.declare(metadata %swift.opaque** %[[ALLOCA:[^,]+]], - // CHECK-SAME: metadata ![[ARG:.*]], metadata !DIExpression(DW_OP_deref)) - // CHECK: store %swift.opaque* %1, %swift.opaque** %[[ALLOCA]], align + // CHECK: call void @llvm.dbg.declare(metadata ptr %[[ALLOCA:.*]], metadata ![[ARG:.*]], metadata !DIExpression(DW_OP_deref)) + // CHECK: store ptr %1, ptr %[[ALLOCA]], align // No deref here. // CHECK-DAG: ![[TY:.*]] = !DICompositeType({{.*}}name: "$sxD", file // CHECK-DAG: ![[LET_TY:[0-9]+]] = !DIDerivedType(tag: DW_TAG_const_type,{{.*}}baseType: ![[TY]]) diff --git a/test/DebugInfo/generic_arg4.swift b/test/DebugInfo/generic_arg4.swift index fe2f1158631ec..707209f0513c2 100644 --- a/test/DebugInfo/generic_arg4.swift +++ b/test/DebugInfo/generic_arg4.swift @@ -1,14 +1,13 @@ -// RUN: %target-swift-frontend %use_no_opaque_pointers %s -emit-ir -g -o - | %FileCheck %s -// RUN: %target-swift-frontend %s -emit-ir -g -o - +// RUN: %target-swift-frontend %s -emit-ir -g -o - | %FileCheck %s // REQUIRES: objc_interop public struct Q { let x: T } // CHECK: define {{.*}}$s12generic_arg43fooyySayAA1QVyxGGlF // CHECK: call void @llvm.dbg.declare -// CHECK: call void @llvm.dbg.declare(metadata %[[TY:.*]]** %[[ALLOCA:[^,]+]], +// CHECK: call void @llvm.dbg.declare(metadata ptr %[[ALLOCA:[^,]+]], // CHECK-SAME: metadata ![[ARG:.*]], metadata !DIExpression()) -// CHECK: store %[[TY]]* %0, %[[TY]]** %[[ALLOCA]], align +// CHECK: store ptr %0, ptr %[[ALLOCA]], align // No deref here: the array argument is passed by value. // CHECK: ![[DITY:.*]] = !DICompositeType({{.*}}name: "$sSay12generic_arg41QVyxGGD" public func foo(_ arg: [Q]) { diff --git a/test/DebugInfo/generic_arg5.swift b/test/DebugInfo/generic_arg5.swift index 80538d9d234ef..9cc609045998f 100644 --- a/test/DebugInfo/generic_arg5.swift +++ b/test/DebugInfo/generic_arg5.swift @@ -1,5 +1,4 @@ -// RUN: %target-swift-frontend %use_no_opaque_pointers %s -emit-ir -g -o - | %FileCheck %s -// RUN: %target-swift-frontend %s -emit-ir -g -o - +// RUN: %target-swift-frontend %s -emit-ir -g -o - | %FileCheck %s public struct S { let value : Type @@ -9,10 +8,10 @@ public func foo(_ values : [S]) { // CHECK: define {{.*}}$s12generic_arg53fooyySayAA1SVyxGGlFAESgAEXEfU_ // CHECK: call void @llvm.dbg.declare - // CHECK: call void @llvm.dbg.declare(metadata %[[TY:.*]]** %[[ALLOCA:[^,]+]], + // CHECK: call void @llvm.dbg.declare(metadata ptr %[[ALLOCA:[^,]+]], // CHECK-SAME: metadata ![[ARG:[0-9]+]], // CHECK-SAME: metadata !DIExpression(DW_OP_deref)) - // CHECK: store %[[TY]]* %1, %[[TY]]** %[[ALLOCA]], align + // CHECK: store ptr %1, ptr %[[ALLOCA]], align // CHECK: ![[TYP:[0-9]+]] = !DICompositeType({{.*}}, name: "$s12generic_arg51SVyxGD" // The argument is a by-ref struct and thus needs to be dereferenced. // CHECK: ![[ARG]] = !DILocalVariable(name: "arg", arg: 1, diff --git a/test/DebugInfo/generic_enum_closure.swift b/test/DebugInfo/generic_enum_closure.swift index c99a01cd5e9a5..e95c1463b3926 100644 --- a/test/DebugInfo/generic_enum_closure.swift +++ b/test/DebugInfo/generic_enum_closure.swift @@ -1,5 +1,4 @@ -// RUN: %target-swift-frontend %use_no_opaque_pointers -primary-file %s -emit-ir -g -o - | %FileCheck %s -// RUN: %target-swift-frontend -primary-file %s -emit-ir -g -o - +// RUN: %target-swift-frontend -primary-file %s -emit-ir -g -o - | %FileCheck %s struct __CurrentErrno {} struct CErrorOr @@ -12,9 +11,9 @@ struct CErrorOr // CHECK: call void @llvm.dbg.declare // Self is in a dynamic alloca, hence the shadow copy. // CHECK: call void @llvm.dbg.declare( - // CHECK-SAME: metadata i8** %[[SHADOW:.*]], metadata ![[SELF:.*]], meta + // CHECK-SAME: metadata ptr %[[SHADOW:.*]], metadata ![[SELF:.*]], meta // CHECK-SAME: !DIExpression(DW_OP_deref)) - // CHECK-DAG: store i8* %[[DYN:.*]], i8** %[[SHADOW]] + // CHECK-DAG: store ptr %[[DYN:.*]], ptr %[[SHADOW]] // CHECK-DAG: %[[DYN]] = alloca i8, i{{32|64}} % // CHECK-DAG: ![[SELF]] = !DILocalVariable(name: "self", scope:{{.*}}, type: ![[TY_CONTAINER:.*]]) // CHECK-DAG: ![[TY_CONTAINER]] = !DICompositeType({{.*}}elements: ![[TY_ELTS:[0-9]+]] diff --git a/test/DebugInfo/guard-let.swift b/test/DebugInfo/guard-let.swift index aca098d4b0e4c..6ac87a636b981 100644 --- a/test/DebugInfo/guard-let.swift +++ b/test/DebugInfo/guard-let.swift @@ -1,10 +1,9 @@ -// RUN: %target-swift-frontend %use_no_opaque_pointers %s -c -emit-ir -g -o - | \ +// RUN: %target-swift-frontend %s -c -emit-ir -g -o - | \ // RUN: %FileCheck %s --check-prefix=CHECK1 -// RUN: %target-swift-frontend %use_no_opaque_pointers %s -c -emit-ir -g -o - | \ +// RUN: %target-swift-frontend %s -c -emit-ir -g -o - | \ // RUN: %FileCheck %s --check-prefix=CHECK2 -// RUN: %target-swift-frontend %use_no_opaque_pointers %s -c -emit-ir -g -o - | \ +// RUN: %target-swift-frontend %s -c -emit-ir -g -o - | \ // RUN: %FileCheck %s --check-prefix=CHECK3 -// RUN: %target-swift-frontend %use_no_opaque_pointers %s -c -emit-ir -g -o - // UNSUPPORTED: OS=watchos @@ -21,12 +20,11 @@ func use(_ t: T) {} public func f(_ i : Int?) { // CHECK1-LABEL: define {{.*}}@"$s4main1fyySiSgF" - // CHECK1: %i.debug = alloca %TSiSg - // CHECK1: @llvm.dbg.declare(metadata %TSiSg* %i.debug - // CHECK1: %[[BITCAST:.*]] = bitcast %TSiSg* %i.debug to i8* - // CHECK1: call void @llvm.memset{{.*}}(i8* align {{(4|8)}} %[[BITCAST]], + // CHECK1: %[[alloca:.*]] = alloca %TSiSg + // CHECK1: @llvm.dbg.declare(metadata ptr %i.debug + // CHECK1: call void @llvm.memset{{.*}}(ptr align {{(4|8)}} %[[alloca]], // CHECK1-SAME: i8 0, i64 {{(5|9)}}, i1 false){{$}} - // CHECK1: @llvm.dbg.declare(metadata {{(i32|i64)}}* %val.debug, + // CHECK1: @llvm.dbg.declare(metadata ptr %val.debug, // CHECK1-SAME: !dbg ![[DBG0:.*]] // CHECK1-LABEL: define {{.*}}@"$s4main1gyySSSgF" // CHECK1: ![[F:.*]] = distinct !DISubprogram(name: "f", @@ -39,12 +37,11 @@ public func f(_ i : Int?) public func g(_ s : String?) { // CHECK2: define {{.*}}@"$s4main1gyySSSgF" - // CHECK2: %s.debug = alloca %TSSSg - // CHECK2: @llvm.dbg.declare(metadata %TSSSg* + // CHECK2: %[[alloca:.*]] = alloca %TSSSg + // CHECK2: @llvm.dbg.declare(metadata ptr // CHECK2: %val.debug = alloca %TSS - // CHECK2: @llvm.dbg.declare(metadata %TSS* - // CHECK2: %[[BITCAST:.*]] = bitcast %TSS* %val.debug to i8*{{$}} - // CHECK2: call void @llvm.memset.{{.*}}(i8* align {{(4|8)}} %[[BITCAST]], i8 0 + // CHECK2: @llvm.dbg.declare(metadata ptr + // CHECK2: call void @llvm.memset.{{.*}}(ptr align {{(4|8)}} %[[alloca]], i8 0 // CHECK2: ![[G:.*]] = distinct !DISubprogram(name: "g" guard let val = s else { return } use(val) @@ -54,11 +51,10 @@ public func h(_ s : String?) { // CHECK3: define {{.*}}@"$s4main1hyySSSgF" // CHECK3: %s.debug = alloca %TSSSg - // CHECK3: @llvm.dbg.declare(metadata %TSSSg* - // CHECK3: %s.debug1 = alloca %TSS - // CHECK3: @llvm.dbg.declare(metadata %TSS* - // CHECK3: %[[BITCAST:.*]] = bitcast %TSS* %s.debug1 to i8*{{$}} - // CHECK3: call void @llvm.memset.{{.*}}(i8* align {{(4|8)}} %[[BITCAST]], i8 0 + // CHECK3: @llvm.dbg.declare(metadata ptr + // CHECK3: %[[alloca:.*]] = alloca %TSS + // CHECK3: @llvm.dbg.declare(metadata ptr + // CHECK3: call void @llvm.memset.{{.*}}(ptr align {{(4|8)}} %[[alloca]], i8 0 // CHECK3: ![[G:.*]] = distinct !DISubprogram(name: "h" guard let s = s else { return } use(s) diff --git a/test/DebugInfo/initializer.swift b/test/DebugInfo/initializer.swift index 4c0457f5ae4d0..8bf7051315b16 100644 --- a/test/DebugInfo/initializer.swift +++ b/test/DebugInfo/initializer.swift @@ -1,5 +1,4 @@ -// RUN: %target-swift-frontend %use_no_opaque_pointers %s -import-objc-header %S/Inputs/serialized-objc-header.h -emit-ir -g -o - | %FileCheck %s -// RUN: %target-swift-frontend %s -import-objc-header %S/Inputs/serialized-objc-header.h -emit-ir -g -o - +// RUN: %target-swift-frontend %s -import-objc-header %S/Inputs/serialized-objc-header.h -emit-ir -g -o - | %FileCheck %s // REQUIRES: objc_interop @@ -8,11 +7,11 @@ protocol Named { } // initializer.Person.__allocating_init (initializer.Person.Type)() -> initializer.Person -// CHECK: define hidden {{.*}}%T11initializer6PersonC* @"$s11initializer6PersonCACycfC"(%swift.type*{{.*}}) {{.*}} { -// CHECK: call {{.*}}%T11initializer6PersonC* @"$s11initializer6PersonCACycfc"(%T11initializer6PersonC* {{.*}}), !dbg ![[ALLOCATING_INIT:.*]] +// CHECK: define hidden {{.*}}ptr @"$s11initializer6PersonCACycfC"(ptr{{.*}}) {{.*}} { +// CHECK: call {{.*}}ptr @"$s11initializer6PersonCACycfc"(ptr {{.*}}), !dbg ![[ALLOCATING_INIT:.*]] // initializer.Person.init (initializer.Person.Type)() -> initializer.Person -// CHECK: define hidden {{.*}}%T11initializer6PersonC* @"$s11initializer6PersonCACycfc"(%T11initializer6PersonC*{{.*}}) {{.*}} { +// CHECK: define hidden {{.*}}ptr @"$s11initializer6PersonCACycfc"(ptr{{.*}}) {{.*}} { // CHECK-DAG: ![[ALLOCATING_INIT]] = !DILocation(line: 0, scope class Person : Named { diff --git a/test/DebugInfo/inlined-generics-basic.swift b/test/DebugInfo/inlined-generics-basic.swift index a396583521239..f1e4c48605df3 100644 --- a/test/DebugInfo/inlined-generics-basic.swift +++ b/test/DebugInfo/inlined-generics-basic.swift @@ -3,7 +3,7 @@ // RUN: -Xllvm -sil-print-debuginfo %s -g -O -o - -emit-sil \ // RUN: | %FileCheck %s --check-prefix=SIL // IR. -// RUN: %target-swift-frontend %use_no_opaque_pointers -parse-as-library -module-name A \ +// RUN: %target-swift-frontend -parse-as-library -module-name A \ // RUN: %s -g -O -o - -emit-ir \ // RUN: | %FileCheck %s --check-prefix=IR @@ -50,12 +50,12 @@ public class C { // SIL: debug_value %0 : $*S, let, name "s", argno 1, expr op_deref, {{.*}} scope [[F]] // SIL: function_ref {{.*}}yes{{.*}} scope [[F1G1]] // SIL: function_ref {{.*}}use{{.*}} scope [[F1G3H]] - // IR: dbg.value(metadata %swift.type* %[[ARG_S]], metadata ![[MD_1_0:[0-9]+]] + // IR: dbg.value(metadata ptr %[[ARG_S]], metadata ![[MD_1_0:[0-9]+]] // IR: %[[RS_PAIR:.*]] = alloca i8, i64 % - // IR: dbg.declare({{.*}} %[[RS_PAIR]], metadata ![[GRS_T:[0-9]+]], - // IR: dbg.value(metadata %swift.opaque* %[[ARG_0]], metadata ![[S:[0-9]+]] - // IR: dbg.value(metadata %swift.opaque* %[[ARG_0]], metadata ![[GS_T:[0-9]+]] - // IR: dbg.value(metadata %swift.opaque* %[[ARG_0]], metadata ![[GS_U:[0-9]+]] + // IR: dbg.declare(metadata ptr %[[RS_PAIR]], metadata ![[GRS_T:[0-9]+]], + // IR: dbg.value(metadata ptr %[[ARG_0]], metadata ![[S:[0-9]+]] + // IR: dbg.value(metadata ptr %[[ARG_0]], metadata ![[GS_T:[0-9]+]] + // IR: dbg.value(metadata ptr %[[ARG_0]], metadata ![[GS_U:[0-9]+]] // IR: call {{.*}}3use #sourceLocation(file: "f.swift", line: 2) g(s) diff --git a/test/DebugInfo/inlined-generics.swift b/test/DebugInfo/inlined-generics.swift index bacb5b7dac860..3efba82d3428f 100644 --- a/test/DebugInfo/inlined-generics.swift +++ b/test/DebugInfo/inlined-generics.swift @@ -1,5 +1,4 @@ -// RUN: %target-swift-frontend %use_no_opaque_pointers -Xllvm -sil-inline-generics=true %s -O -g -o - -emit-ir | %FileCheck %s -// RUN: %target-swift-frontend -Xllvm -sil-inline-generics=true %s -O -g -o - -emit-ir +// RUN: %target-swift-frontend -Xllvm -sil-inline-generics=true %s -O -g -o - -emit-ir | %FileCheck %s public protocol P { associatedtype DT1 func getDT() -> DT1 @@ -13,7 +12,7 @@ func foo1(_ t: T, _ dt: T.DT1) -> T.DT1 { // CHECK: define {{.*}}@"$s4main4foo2yyxAA1PRzlF" public func foo2(_ s: S) { - // CHECK: call void @llvm.dbg.value(metadata %swift.type* %S, + // CHECK: call void @llvm.dbg.value(metadata ptr %S, // CHECK-SAME: metadata ![[META:[0-9]+]] foo1(s, s.getDT()) // T should get substituted with S diff --git a/test/DebugInfo/inout.swift b/test/DebugInfo/inout.swift index e75cf70a98b33..090c9654c2c2a 100644 --- a/test/DebugInfo/inout.swift +++ b/test/DebugInfo/inout.swift @@ -1,5 +1,4 @@ -// RUN: %target-swift-frontend %use_no_opaque_pointers %s -emit-ir -g -module-name inout -o %t.ll -// RUN: %target-swift-frontend %s -emit-ir -g -module-name inout +// RUN: %target-swift-frontend %s -emit-ir -g -module-name inout -o %t.ll // RUN: cat %t.ll | %FileCheck %s // RUN: cat %t.ll | %FileCheck %s --check-prefix=PROMO-CHECK // RUN: cat %t.ll | %FileCheck %s --check-prefix=FOO-CHECK @@ -10,13 +9,13 @@ func Close(_ fn: () -> Int64) { fn() } typealias MyFloat = Float // CHECK: define hidden swiftcc void @"$s5inout13modifyFooHeap{{[_0-9a-zA-Z]*}}F" -// CHECK: %[[ALLOCA:.*]] = alloca %Ts5Int64V* +// CHECK: %[[ALLOCA:.*]] = alloca ptr // CHECK: call void @llvm.dbg.declare(metadata // CHECK-SAME: %[[ALLOCA]], metadata ![[A:[0-9]+]] // Closure with promoted capture. // PROMO-CHECK: define {{.*}}@"$s5inout13modifyFooHeapyys5Int64Vz_SftFADyXEfU_" -// PROMO-CHECK: call void @llvm.dbg.declare(metadata %Ts5Int64V** % +// PROMO-CHECK: call void @llvm.dbg.declare(metadata ptr % // PROMO-CHECK-SAME: metadata ![[A1:[0-9]+]], metadata !DIExpression(DW_OP_deref)) // PROMO-CHECK: ![[INT:.*]] = !DICompositeType({{.*}}identifier: "$ss5Int64VD" @@ -37,7 +36,7 @@ func modifyFooHeap(_ a: inout Int64, // Inout reference type. // FOO-CHECK: define {{.*}}@"$s5inout9modifyFooyys5Int64Vz_SftF" -// FOO-CHECK: call void @llvm.dbg.declare(metadata %Ts5Int64V** % +// FOO-CHECK: call void @llvm.dbg.declare(metadata ptr % // FOO-CHECK-SAME: metadata ![[U:[0-9]+]], metadata !DIExpression(DW_OP_deref)) func modifyFoo(_ u: inout Int64, // FOO-CHECK-DAG: !DILocalVariable(name: "v", arg: 2{{.*}} line: [[@LINE+3]],{{.*}} type: ![[LET_MYFLOAT:[0-9]+]] diff --git a/test/DebugInfo/iuo_arg.swift b/test/DebugInfo/iuo_arg.swift index 8b6518646caee..701e1138a94d2 100644 --- a/test/DebugInfo/iuo_arg.swift +++ b/test/DebugInfo/iuo_arg.swift @@ -1,5 +1,4 @@ -// RUN: %target-swift-frontend %use_no_opaque_pointers %s -emit-ir -g -o - | %FileCheck %s -// RUN: %target-swift-frontend %s -emit-ir -g -o - +// RUN: %target-swift-frontend %s -emit-ir -g -o - | %FileCheck %s class CGImageRef {} class UIImage { @@ -14,12 +13,12 @@ class CIFilter { } class MyClass { - // CHECK: define hidden {{.*}} %T7iuo_arg7UIImageC* @"$s7iuo_arg7MyClassC11filterImageyAA7UIImageCAFSg_SbtF" + // CHECK: define hidden {{.*}} ptr @"$s7iuo_arg7MyClassC11filterImageyAA7UIImageCAFSg_SbtF" func filterImage(_ image: UIImage!, _ doSomething:Bool) -> UIImage { // Test that image is in an alloca, but not an indirect location. - // CHECK: call void @llvm.dbg.declare(metadata {{(i32|i64)}}* %[[ALLOCA:.*]], metadata ![[IMAGE:.*]], metadata !DIExpression()) - // CHECK: store {{(i32|i64)}} %0, {{(i32|i64)}}* %[[ALLOCA]], align + // CHECK: call void @llvm.dbg.declare(metadata ptr %[[ALLOCA:.*]], metadata ![[IMAGE:.*]], metadata !DIExpression()) + // CHECK: store {{(i32|i64)}} %0, ptr %[[ALLOCA]], align // CHECK: ![[IMAGE]] = !DILocalVariable(name: "image", arg: 1 // CHECK-NOT: flags: // CHECK-SAME: line: [[@LINE-7]] diff --git a/test/DebugInfo/let.swift b/test/DebugInfo/let.swift index cb99ad707d97c..7527526cc4e76 100644 --- a/test/DebugInfo/let.swift +++ b/test/DebugInfo/let.swift @@ -1,12 +1,11 @@ -// RUN: %target-swift-frontend %use_no_opaque_pointers -primary-file %s -emit-ir -g -o - | %FileCheck %s -// RUN: %target-swift-frontend -primary-file %s -emit-ir -g -o - +// RUN: %target-swift-frontend -primary-file %s -emit-ir -g -o - | %FileCheck %s class DeepThought { func query() -> Int64 { return 42 } } func foo() -> Int64 { - // CHECK: call void @llvm.dbg.declare(metadata %T3let11DeepThoughtC** {{.*}}, metadata ![[A:.*]], metadata !DIExpression()) + // CHECK: call void @llvm.dbg.declare(metadata ptr {{.*}}, metadata ![[A:.*]], metadata !DIExpression()) // CHECK-DAG: !DILocalVariable(name: "machine",{{.*}}line: [[@LINE+1]], type: !{{[0-9]+}}) let machine = DeepThought() // CHECK-DAG: !DILocalVariable(name: "a", {{.*}}line: [[@LINE+1]], diff --git a/test/DebugInfo/linetable-cleanups.swift b/test/DebugInfo/linetable-cleanups.swift index eafe989923982..02e04142c6c22 100644 --- a/test/DebugInfo/linetable-cleanups.swift +++ b/test/DebugInfo/linetable-cleanups.swift @@ -1,5 +1,4 @@ -// RUN: %target-swift-frontend %use_no_opaque_pointers %s -emit-ir -g -o - | %FileCheck %s -// RUN: %target-swift-frontend %s -emit-ir -g -o - +// RUN: %target-swift-frontend %s -emit-ir -g -o - | %FileCheck %s // TODO: check why this is failing on linux // REQUIRES: OS=macosx @@ -21,15 +20,14 @@ func main() { // CHECK: call {{.*}}void @"$s4main8markUsedyyxlF" // CHECK: br label // CHECK: {{[0-9]+}}: -// CHECK: call %Ts16IndexingIteratorVySaySiGG* @"$ss16IndexingIteratorVySaySiGGWOh"(%Ts16IndexingIteratorVySaySiGG* %{{.*}}), !dbg ![[LOOPHEADER_LOC:.*]] +// CHECK: call ptr @"$ss16IndexingIteratorVySaySiGGWOh"(ptr %{{.*}}), !dbg ![[LOOPHEADER_LOC:.*]] // CHECK: call {{.*}}void @"$s4main8markUsedyyxlF" // The cleanups should share the line number with the ret stmt. -// CHECK: call %TSa* @"$sSaySiGWOh"(%TSa* %{{.*}}), !dbg ![[CLEANUPS:.*]] -// CHECK-NEXT: !dbg ![[CLEANUPS]] +// CHECK: call ptr @"$sSaySiGWOh"(ptr %{{.*}}), !dbg ![[CLEANUPS:.*]] // CHECK-NEXT: llvm.lifetime.end +// CHECK-SAME: !dbg ![[CLEANUPS]] // CHECK-NEXT: load // CHECK-NEXT: swift_release -// CHECK-NEXT: bitcast // CHECK-NEXT: llvm.lifetime.end // CHECK-NEXT: ret void, !dbg ![[CLEANUPS]] // CHECK: ![[CLEANUPS]] = !DILocation(line: [[@LINE+1]], column: 1, diff --git a/test/DebugInfo/linetable-codeview.swift b/test/DebugInfo/linetable-codeview.swift index c3ba2aaf56650..1bae78e54340a 100644 --- a/test/DebugInfo/linetable-codeview.swift +++ b/test/DebugInfo/linetable-codeview.swift @@ -1,4 +1,4 @@ -// RUN: %swiftc_driver %use_no_opaque_pointers %s -g -debug-info-format=codeview -emit-ir -o - | %FileCheck %s +// RUN: %swiftc_driver %s -g -debug-info-format=codeview -emit-ir -o - | %FileCheck %s // REQUIRES: optimized_stdlib func markUsed(_ t: T) {} @@ -49,12 +49,12 @@ func foo() { // NOTE: The point of this test is to trigger IRGenSIL::emitShadowCopy() // and IRGenSIL::emitShadowCopyIfNeeded(). It may be worthwhile to // simplify this testcase. - // CHECK: store float %0, float* %myArg.debug, {{.*}}, !dbg ![[PROLOGUE:[0-9]+]] - // CHECK: store float {{.*}}, float* %self.debug.myVal1._value, {{.*}}, !dbg ![[PROLOGUE]] + // CHECK: store float %0, ptr %myArg.debug, {{.*}}, !dbg ![[PROLOGUE:[0-9]+]] + // CHECK: store float {{.*}}, ptr %self.debug.myVal1._value, {{.*}}, !dbg ![[PROLOGUE]] // func myLoop() { // CHECK: define {{.*}} @"$s4main6myLoopyyF" - // CHECK: call void @llvm.dbg.declare(metadata i64* %index.debug, {{.*}}), !dbg ![[FORLOOP:[0-9]+]] + // CHECK: call void @llvm.dbg.declare(metadata ptr %index.debug, {{.*}}), !dbg ![[FORLOOP:[0-9]+]] // CHECK: phi i64 [ %{{.[0-9]+}}, %{{.[0-9]+}} ], !dbg ![[FORLOOP]] // CHECK: call {{.*}} @"$s4main8markUsedyyxlF"{{.*}}, !dbg ![[FORBODY:[0-9]+]] // CHECK: ret void @@ -70,7 +70,7 @@ func foo() { // func foo() // CHECK: define {{.*}} @"$s4main3fooyyF" // CHECK: %[[MYARRAY:.*]] = alloca - // CHECK: call void @llvm.dbg.declare(metadata %TSa* %[[MYARRAY]], + // CHECK: call void @llvm.dbg.declare(metadata ptr %[[MYARRAY]], // CHECK-SAME: !dbg ![[ARRAY:[0-9]+]] // CHECK: call swiftcc { {{.*}} } @"${{.*}}_allocateUninitializedArray{{.*}}" // CHECK-SAME: !dbg ![[ARRAY_ALLOC:[0-9]+]] diff --git a/test/DebugInfo/move_function_dbginfo.swift b/test/DebugInfo/move_function_dbginfo.swift index 38a7a88fcca72..02ff1d2a3c49b 100644 --- a/test/DebugInfo/move_function_dbginfo.swift +++ b/test/DebugInfo/move_function_dbginfo.swift @@ -1,6 +1,6 @@ // RUN: %empty-directory(%t) -// RUN: %target-swift-frontend %use_no_opaque_pointers -parse-as-library -g -emit-ir -o - %s | %FileCheck %s -// RUN: %target-swift-frontend %use_no_opaque_pointers -parse-as-library -g -c %s -o %t/out.o +// RUN: %target-swift-frontend -parse-as-library -g -emit-ir -o - %s | %FileCheck %s +// RUN: %target-swift-frontend -parse-as-library -g -c %s -o %t/out.o // RUN: %llvm-dwarfdump --show-children %t/out.o | %FileCheck -check-prefix=DWARF %s // This test checks that: @@ -38,17 +38,17 @@ public var falseValue: Bool { false } // CHECK-LABEL: define swiftcc void @"$s21move_function_dbginfo17copyableValueTestyyF"() // // In contrast, we should have a dbg.declare for m since we aren't -// CHECK: call void @llvm.dbg.declare(metadata {{.*}}** %m.debug, metadata ![[M_COPYABLE_VALUE_TEST:[0-9]*]], +// CHECK: call void @llvm.dbg.declare(metadata ptr %m.debug, metadata ![[M_COPYABLE_VALUE_TEST:[0-9]*]], // // We should have a llvm.dbg.addr for k since we moved it. -// CHECK: call void @llvm.dbg.addr(metadata {{.*}}** %k.debug, metadata ![[K_COPYABLE_VALUE_METADATA:[0-9]*]], metadata !DIExpression()), !dbg ![[ADDR_LOC:[0-9]*]] +// CHECK: call void @llvm.dbg.addr(metadata ptr %k.debug, metadata ![[K_COPYABLE_VALUE_METADATA:[0-9]*]], metadata !DIExpression()), !dbg ![[ADDR_LOC:[0-9]*]] // CHECK-NEXT: br // // Our undef should be an llvm.dbg.value. Counter-intuitively this works for // both llvm.dbg.addr /and/ llvm.dbg.value. Importantly though its metadata // should be for k since that is the variable that we are telling the debugger // is no longer defined. -// CHECK: call void @llvm.dbg.value(metadata %T21move_function_dbginfo5KlassC* undef, metadata ![[K_COPYABLE_VALUE_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] +// CHECK: call void @llvm.dbg.value(metadata ptr undef, metadata ![[K_COPYABLE_VALUE_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] // CHECK-NOT: br label // // CHECK: ret void @@ -84,20 +84,20 @@ public func copyableValueTest() { m.doSomething() } -// CHECK-LABEL: define swiftcc void @"$s21move_function_dbginfo15copyableArgTestyyAA5KlassCnF"(%T21move_function_dbginfo5KlassC* %0) +// CHECK-LABEL: define swiftcc void @"$s21move_function_dbginfo15copyableArgTestyyAA5KlassCnF"(ptr %0) // // In contrast, we should have a dbg.declare for m since we aren't -// CHECK: call void @llvm.dbg.declare(metadata {{.*}}** %m.debug, metadata ![[M_COPYABLE_VALUE_TEST:[0-9]*]], +// CHECK: call void @llvm.dbg.declare(metadata ptr %m.debug, metadata ![[M_COPYABLE_VALUE_TEST:[0-9]*]], // // We should have a llvm.dbg.addr for k since we moved it. -// CHECK: call void @llvm.dbg.addr(metadata {{.*}}** %k.debug, metadata ![[K_COPYABLE_VALUE_METADATA:[0-9]*]], metadata !DIExpression()), !dbg ![[ADDR_LOC:[0-9]*]] +// CHECK: call void @llvm.dbg.addr(metadata ptr %k.debug, metadata ![[K_COPYABLE_VALUE_METADATA:[0-9]*]], metadata !DIExpression()), !dbg ![[ADDR_LOC:[0-9]*]] // CHECK-NEXT: br // // Our undef should be an llvm.dbg.value. Counter-intuitively this works for // both llvm.dbg.addr /and/ llvm.dbg.value. Importantly though its metadata // should be for k since that is the variable that we are telling the debugger // is no longer defined. -// CHECK: call void @llvm.dbg.value(metadata %T21move_function_dbginfo5KlassC* undef, metadata ![[K_COPYABLE_VALUE_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] +// CHECK: call void @llvm.dbg.value(metadata ptr undef, metadata ![[K_COPYABLE_VALUE_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] // CHECK-NOT: br label // // CHECK: ret void @@ -131,12 +131,12 @@ public func copyableArgTest(_ k: __owned Klass) { } // CHECK-LABEL: define swiftcc void @"$s21move_function_dbginfo15copyableVarTestyyF"() -// CHECK: call void @llvm.dbg.declare(metadata %T21move_function_dbginfo5KlassC** %m.debug, -// CHECK: call void @llvm.dbg.addr(metadata %T21move_function_dbginfo5KlassC** [[VAR:%.*]], metadata ![[K_COPYABLE_VAR_METADATA:[0-9]+]], metadata !DIExpression()), !dbg ![[ADDR_LOC:[0-9]*]] +// CHECK: call void @llvm.dbg.declare(metadata ptr %m.debug, +// CHECK: call void @llvm.dbg.addr(metadata ptr [[VAR:%.*]], metadata ![[K_COPYABLE_VAR_METADATA:[0-9]+]], metadata !DIExpression()), !dbg ![[ADDR_LOC:[0-9]*]] // CHECK-NEXT: br -// CHECK: call void @llvm.dbg.value(metadata %T21move_function_dbginfo5KlassC** undef, metadata ![[K_COPYABLE_VAR_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] +// CHECK: call void @llvm.dbg.value(metadata ptr undef, metadata ![[K_COPYABLE_VAR_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] // TODO: Should this be a deref like the original? -// CHECK: call void @llvm.dbg.addr(metadata %T21move_function_dbginfo5KlassC** [[VAR]], metadata ![[K_COPYABLE_VAR_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] +// CHECK: call void @llvm.dbg.addr(metadata ptr [[VAR]], metadata ![[K_COPYABLE_VAR_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] // CHECK-NEXT: br // CHECK: ret void // CHECK-NEXT: } @@ -176,12 +176,12 @@ public func copyableVarTest() { } // CHECK-LABEL: define swiftcc void @"$s21move_function_dbginfo18copyableVarArgTestyyAA5KlassCzF"( -// CHECK: call void @llvm.dbg.declare(metadata %T21move_function_dbginfo5KlassC** %m.debug, -// CHECK: call void @llvm.dbg.addr(metadata %T21move_function_dbginfo5KlassC*** [[VAR:%.*]], metadata ![[K_COPYABLE_VAR_METADATA:[0-9]+]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC:[0-9]*]] +// CHECK: call void @llvm.dbg.declare(metadata ptr %m.debug, +// CHECK: call void @llvm.dbg.addr(metadata ptr [[VAR:%.*]], metadata ![[K_COPYABLE_VAR_METADATA:[0-9]+]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC:[0-9]*]] // CHECK-NEXT: br -// CHECK: call void @llvm.dbg.value(metadata %T21move_function_dbginfo5KlassC** undef, metadata ![[K_COPYABLE_VAR_METADATA]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC]] +// CHECK: call void @llvm.dbg.value(metadata ptr undef, metadata ![[K_COPYABLE_VAR_METADATA]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC]] // TODO: Should this be a deref like the original? -// CHECK: call void @llvm.dbg.addr(metadata %T21move_function_dbginfo5KlassC*** [[VAR]], metadata ![[K_COPYABLE_VAR_METADATA]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC]] +// CHECK: call void @llvm.dbg.addr(metadata ptr [[VAR]], metadata ![[K_COPYABLE_VAR_METADATA]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC]] // CHECK-NEXT: br // CHECK: ret void // CHECK-NEXT: } @@ -218,10 +218,10 @@ public func copyableVarArgTest(_ k: inout Klass) { k.doSomething() } -// CHECK-LABEL: define swiftcc void @"$s21move_function_dbginfo20addressOnlyValueTestyyxAA1PRzlF"(%swift.opaque* noalias nocapture %0, %swift.type* %T, i8** %T.P) -// CHECK: @llvm.dbg.addr(metadata %swift.opaque** %k.debug, metadata ![[K_ADDR_LET_METADATA:[0-9]+]], metadata !DIExpression()), !dbg ![[ADDR_LOC:[0-9]*]] +// CHECK-LABEL: define swiftcc void @"$s21move_function_dbginfo20addressOnlyValueTestyyxAA1PRzlF"(ptr noalias nocapture %0, ptr %T, ptr %T.P) +// CHECK: @llvm.dbg.addr(metadata ptr %{{.*}}, metadata ![[K_ADDR_LET_METADATA:[0-9]+]], metadata !DIExpression()), !dbg ![[ADDR_LOC:[0-9]*]] // CHECK-NEXT: br -// CHECK: @llvm.dbg.value(metadata %swift.opaque* undef, metadata ![[K_ADDR_LET_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] +// CHECK: @llvm.dbg.value(metadata ptr undef, metadata ![[K_ADDR_LET_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] // CHECK: ret void // CHECK-NEXT: } // @@ -267,11 +267,11 @@ public func addressOnlyValueTest(_ x: T) { } // CHECK-LABEL: define swiftcc void @"$s21move_function_dbginfo23addressOnlyValueArgTestyyxnAA1PRzlF"( -// CHECK: @llvm.dbg.declare(metadata %swift.type** %T1, -// CHECK: @llvm.dbg.declare(metadata i8** %m.debug, -// CHECK: @llvm.dbg.addr(metadata %swift.opaque** %k.debug, metadata ![[K_ADDR_LET_METADATA:[0-9]+]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC:[0-9]*]] +// CHECK: @llvm.dbg.declare(metadata ptr %T1, +// CHECK: @llvm.dbg.declare(metadata ptr %m.debug, +// CHECK: @llvm.dbg.addr(metadata ptr %k.debug, metadata ![[K_ADDR_LET_METADATA:[0-9]+]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC:[0-9]*]] // CHECK-NEXT: br -// CHECK: @llvm.dbg.value(metadata %swift.opaque* undef, metadata ![[K_ADDR_LET_METADATA]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC]] +// CHECK: @llvm.dbg.value(metadata ptr undef, metadata ![[K_ADDR_LET_METADATA]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC]] // CHECK: ret void // CHECK-NEXT: } // @@ -308,11 +308,11 @@ public func addressOnlyValueArgTest(_ k: __owned T) { m.doSomething() } -// CHECK-LABEL: define swiftcc void @"$s21move_function_dbginfo18addressOnlyVarTestyyxAA1PRzlF"(%swift.opaque* noalias nocapture %0, %swift.type* %T, i8** %T.P) -// CHECK: @llvm.dbg.addr(metadata %swift.opaque** %k.debug, metadata ![[K_ADDRONLY_VAR_METADATA:[0-9]+]], metadata !DIExpression()), !dbg ![[ADDR_LOC:[0-9]*]] +// CHECK-LABEL: define swiftcc void @"$s21move_function_dbginfo18addressOnlyVarTestyyxAA1PRzlF"(ptr noalias nocapture %0, ptr %T, ptr %T.P) +// CHECK: @llvm.dbg.addr(metadata ptr %{{.*}}, metadata ![[K_ADDRONLY_VAR_METADATA:[0-9]+]], metadata !DIExpression()), !dbg ![[ADDR_LOC:[0-9]*]] // CHECK-NEXT: br -// CHECK: @llvm.dbg.value(metadata %swift.opaque* undef, metadata ![[K_ADDRONLY_VAR_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] -// CHECK: @llvm.dbg.addr(metadata %swift.opaque** %k.debug, metadata ![[K_ADDRONLY_VAR_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] +// CHECK: @llvm.dbg.value(metadata ptr undef, metadata ![[K_ADDRONLY_VAR_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] +// CHECK: @llvm.dbg.addr(metadata ptr %{{.*}}, metadata ![[K_ADDRONLY_VAR_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] // CHECK-NEXT: br // CHECK: ret void // CHECK-NEXT: } @@ -347,7 +347,7 @@ public func addressOnlyValueArgTest(_ k: __owned T) { // DWARF-NEXT: DW_AT_decl_line ( // DWARF-NEXT: DW_AT_type ( public func addressOnlyVarTest(_ x: T) { - var k = x + var k = x // << this k.doSomething() let m = consume k m.doSomething() @@ -356,10 +356,10 @@ public func addressOnlyVarTest(_ x: T) { } // CHECK-LABEL: define swiftcc void @"$s21move_function_dbginfo21addressOnlyVarArgTestyyxz_xtAA1PRzlF"( -// CHECK: call void @llvm.dbg.addr(metadata %swift.opaque** %k.debug, metadata ![[K_ADDRONLY_VAR_METADATA:[0-9]+]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC:[0-9]*]] +// CHECK: call void @llvm.dbg.addr(metadata ptr %k.debug, metadata ![[K_ADDRONLY_VAR_METADATA:[0-9]+]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC:[0-9]*]] // CHECK-NEXT: br -// CHECK: @llvm.dbg.value(metadata %swift.opaque* undef, metadata ![[K_ADDRONLY_VAR_METADATA]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC]] -// CHECK: @llvm.dbg.addr(metadata %swift.opaque** %k.debug, metadata ![[K_ADDRONLY_VAR_METADATA]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC]] +// CHECK: @llvm.dbg.value(metadata ptr undef, metadata ![[K_ADDRONLY_VAR_METADATA]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC]] +// CHECK: @llvm.dbg.addr(metadata ptr %k.debug, metadata ![[K_ADDRONLY_VAR_METADATA]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC]] // CHECK-NEXT: br // CHECK: ret void // CHECK-NEXT: } @@ -405,14 +405,14 @@ public func addressOnlyVarArgTest(_ k: inout T, _ x: T) { /////////////////////// // CHECK-LABEL: define swiftcc void @"$s21move_function_dbginfo23copyableValueCCFlowTestyyF"( -// CHECK: call void @llvm.dbg.addr(metadata %T21move_function_dbginfo5KlassC** %k.debug, metadata ![[K_COPYABLE_LET_CCFLOW_METADATA:[0-9]+]], metadata !DIExpression()), !dbg ![[ADDR_LOC:[0-9]+]] +// CHECK: call void @llvm.dbg.addr(metadata ptr %k.debug, metadata ![[K_COPYABLE_LET_CCFLOW_METADATA:[0-9]+]], metadata !DIExpression()), !dbg ![[ADDR_LOC:[0-9]+]] // CHECK-NEXT: br label %[[NEXT_BB:[a-z\.0-9]+]], // // CHECK: [[NEXT_BB]]: // CHECK: br i1 {{%[0-9]+}}, label %[[LHS:[0-9]+]], label %[[RHS:[0-9]+]], // // CHECK: [[LHS]]: -// CHECK: call void @llvm.dbg.value(metadata %T21move_function_dbginfo5KlassC* undef, metadata ![[K_COPYABLE_LET_CCFLOW_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] +// CHECK: call void @llvm.dbg.value(metadata ptr undef, metadata ![[K_COPYABLE_LET_CCFLOW_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] public func copyableValueCCFlowTest() { let k = Klass() k.doSomething() @@ -423,14 +423,14 @@ public func copyableValueCCFlowTest() { } // CHECK-LABEL: define swiftcc void @"$s21move_function_dbginfo26copyableValueArgCCFlowTestyyAA5KlassCnF"( -// CHECK: call void @llvm.dbg.addr(metadata %T21move_function_dbginfo5KlassC** %k.debug, metadata ![[K_COPYABLE_LET_CCFLOW_METADATA:[0-9]+]], metadata !DIExpression()), !dbg ![[ADDR_LOC:[0-9]+]] +// CHECK: call void @llvm.dbg.addr(metadata ptr %k.debug, metadata ![[K_COPYABLE_LET_CCFLOW_METADATA:[0-9]+]], metadata !DIExpression()), !dbg ![[ADDR_LOC:[0-9]+]] // CHECK-NEXT: br label %[[NEXT_BB:[a-z\.0-9]+]], // // CHECK: [[NEXT_BB]]: // CHECK: br i1 {{%[0-9]+}}, label %[[LHS:[0-9]+]], label %[[RHS:[0-9]+]], // // CHECK: [[LHS]]: -// CHECK: call void @llvm.dbg.value(metadata %T21move_function_dbginfo5KlassC* undef, metadata ![[K_COPYABLE_LET_CCFLOW_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] +// CHECK: call void @llvm.dbg.value(metadata ptr undef, metadata ![[K_COPYABLE_LET_CCFLOW_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] public func copyableValueArgCCFlowTest(_ k: __owned Klass) { k.doSomething() if trueValue { @@ -440,15 +440,15 @@ public func copyableValueArgCCFlowTest(_ k: __owned Klass) { } // CHECK-LABEL: define swiftcc void @"$s21move_function_dbginfo037copyableVarTestCCFlowReinitOutOfBlockF0yyF"( -// CHECK: call void @llvm.dbg.declare(metadata %T21move_function_dbginfo5KlassC** %m.debug, -// CHECK: call void @llvm.dbg.addr(metadata %T21move_function_dbginfo5KlassC** [[VAR:%.*]], metadata ![[K_COPYABLE_VAR_CCFLOW_REINIT_OUT_BLOCK_METADATA:[0-9]+]], metadata !DIExpression()), !dbg ![[ADDR_LOC:[0-9]*]] +// CHECK: call void @llvm.dbg.declare(metadata ptr %m.debug, +// CHECK: call void @llvm.dbg.addr(metadata ptr [[VAR:%.*]], metadata ![[K_COPYABLE_VAR_CCFLOW_REINIT_OUT_BLOCK_METADATA:[0-9]+]], metadata !DIExpression()), !dbg ![[ADDR_LOC:[0-9]*]] // CHECK-NEXT: br label %[[BB_NEXT:[a-z0-9\.]+]], // // CHECK: [[BB_NEXT]]: // CHECK: br i1 %{{[0-9]+}}, label %[[LHS:[0-9]+]], label %[[RHS:[0-9]+]], // // CHECK: [[LHS]]: -// CHECK: call void @llvm.dbg.value(metadata %T21move_function_dbginfo5KlassC** undef, metadata ![[K_COPYABLE_VAR_CCFLOW_REINIT_OUT_BLOCK_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] +// CHECK: call void @llvm.dbg.value(metadata ptr undef, metadata ![[K_COPYABLE_VAR_CCFLOW_REINIT_OUT_BLOCK_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] // CHECK: br label %[[CONT_BB:[0-9]+]], // // CHECK: [[RHS]]: @@ -456,7 +456,7 @@ public func copyableValueArgCCFlowTest(_ k: __owned Klass) { // // CHECK: [[CONT_BB]]: // TODO: Should this be a deref like the original? -// CHECK: call void @llvm.dbg.addr(metadata %T21move_function_dbginfo5KlassC** [[VAR]], metadata ![[K_COPYABLE_VAR_CCFLOW_REINIT_OUT_BLOCK_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] +// CHECK: call void @llvm.dbg.addr(metadata ptr [[VAR]], metadata ![[K_COPYABLE_VAR_CCFLOW_REINIT_OUT_BLOCK_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] // CHECK-NEXT: br // CHECK: ret void // CHECK-NEXT: } @@ -472,22 +472,22 @@ public func copyableVarTestCCFlowReinitOutOfBlockTest() { } // CHECK-LABEL: define swiftcc void @"$s21move_function_dbginfo040copyableVarArgTestCCFlowReinitOutOfBlockG0yyAA5KlassCzF"( -// CHECK: call void @llvm.dbg.declare(metadata %T21move_function_dbginfo5KlassC** %m.debug, -// CHECK: call void @llvm.dbg.addr(metadata %T21move_function_dbginfo5KlassC*** [[VAR:%.*]], metadata ![[K_COPYABLE_VAR_CCFLOW_REINIT_OUT_BLOCK_METADATA:[0-9]+]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC:[0-9]*]] +// CHECK: call void @llvm.dbg.declare(metadata ptr %m.debug, +// CHECK: call void @llvm.dbg.addr(metadata ptr [[VAR:%.*]], metadata ![[K_COPYABLE_VAR_CCFLOW_REINIT_OUT_BLOCK_METADATA:[0-9]+]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC:[0-9]*]] // CHECK-NEXT: br label %[[BB_NEXT:[a-z0-9\.]+]], // // CHECK: [[BB_NEXT]]: // CHECK: br i1 %{{[0-9]+}}, label %[[LHS:[0-9]+]], label %[[RHS:[0-9]+]], // // CHECK: [[LHS]]: -// CHECK: call void @llvm.dbg.value(metadata %T21move_function_dbginfo5KlassC** undef, metadata ![[K_COPYABLE_VAR_CCFLOW_REINIT_OUT_BLOCK_METADATA]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC]] +// CHECK: call void @llvm.dbg.value(metadata ptr undef, metadata ![[K_COPYABLE_VAR_CCFLOW_REINIT_OUT_BLOCK_METADATA]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC]] // CHECK: br label %[[CONT_BB:[0-9]+]], // // CHECK: [[RHS]]: // CHECK: br label %[[CONT_BB]], // // CHECK: [[CONT_BB]]: -// CHECK: call void @llvm.dbg.addr(metadata %T21move_function_dbginfo5KlassC*** [[VAR]], metadata ![[K_COPYABLE_VAR_CCFLOW_REINIT_OUT_BLOCK_METADATA]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC]] +// CHECK: call void @llvm.dbg.addr(metadata ptr [[VAR]], metadata ![[K_COPYABLE_VAR_CCFLOW_REINIT_OUT_BLOCK_METADATA]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC]] // CHECK-NEXT: br // CHECK: ret void // CHECK-NEXT: } @@ -503,17 +503,17 @@ public func copyableVarArgTestCCFlowReinitOutOfBlockTest(_ k: inout Klass) { // CHECK-LABEL: define swiftcc void @"$s21move_function_dbginfo034copyableVarTestCCFlowReinitInBlockF0yyF"( // CHECK: entry: -// CHECK: call void @llvm.dbg.declare(metadata %T21move_function_dbginfo5KlassC** %m.debug, -// CHECK: call void @llvm.dbg.addr(metadata %T21move_function_dbginfo5KlassC** [[VAR:%.*]], metadata ![[K_COPYABLE_VAR_CCFLOW_REINIT_IN_BLOCK_METADATA:[0-9]+]], metadata !DIExpression()), !dbg ![[ADDR_LOC:[0-9]*]] +// CHECK: call void @llvm.dbg.declare(metadata ptr %m.debug, +// CHECK: call void @llvm.dbg.addr(metadata ptr [[VAR:%.*]], metadata ![[K_COPYABLE_VAR_CCFLOW_REINIT_IN_BLOCK_METADATA:[0-9]+]], metadata !DIExpression()), !dbg ![[ADDR_LOC:[0-9]*]] // CHECK-NEXT: br label %[[BB_NEXT:[a-z0-9\.]+]], // // CHECK: [[BB_NEXT]]: // CHECK: br i1 %{{[0-9]+}}, label %[[LHS:[0-9]+]], label %[[RHS:[0-9]+]], // // CHECK: [[LHS]]: -// CHECK: call void @llvm.dbg.value(metadata %T21move_function_dbginfo5KlassC** undef, metadata ![[K_COPYABLE_VAR_CCFLOW_REINIT_IN_BLOCK_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] +// CHECK: call void @llvm.dbg.value(metadata ptr undef, metadata ![[K_COPYABLE_VAR_CCFLOW_REINIT_IN_BLOCK_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] // TODO: Should this be a deref like the original? -// CHECK: call void @llvm.dbg.addr(metadata %T21move_function_dbginfo5KlassC** [[VAR]], metadata ![[K_COPYABLE_VAR_CCFLOW_REINIT_IN_BLOCK_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] +// CHECK: call void @llvm.dbg.addr(metadata ptr [[VAR]], metadata ![[K_COPYABLE_VAR_CCFLOW_REINIT_IN_BLOCK_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] // CHECK-NEXT: br label %[[BB_NEXT_2:[a-z\.0-9]+]], // // CHECK: [[BB_NEXT_2]]: @@ -538,17 +538,17 @@ public func copyableVarTestCCFlowReinitInBlockTest() { // CHECK-LABEL: define swiftcc void @"$s21move_function_dbginfo037copyableVarArgTestCCFlowReinitInBlockG0yyAA5KlassCzF"( // CHECK: entry: -// CHECK: call void @llvm.dbg.declare(metadata %T21move_function_dbginfo5KlassC** %m.debug, -// CHECK: call void @llvm.dbg.addr(metadata %T21move_function_dbginfo5KlassC*** [[VAR:%.*]], metadata ![[K_COPYABLE_VAR_CCFLOW_REINIT_IN_BLOCK_METADATA:[0-9]+]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC:[0-9]*]] +// CHECK: call void @llvm.dbg.declare(metadata ptr %m.debug, +// CHECK: call void @llvm.dbg.addr(metadata ptr [[VAR:%.*]], metadata ![[K_COPYABLE_VAR_CCFLOW_REINIT_IN_BLOCK_METADATA:[0-9]+]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC:[0-9]*]] // CHECK-NEXT: br label %[[BB_NEXT:[a-z0-9\.]+]], // // CHECK: [[BB_NEXT]]: // CHECK: br i1 %{{[0-9]+}}, label %[[LHS:[0-9]+]], label %[[RHS:[0-9]+]], // // CHECK: [[LHS]]: -// CHECK: call void @llvm.dbg.value(metadata %T21move_function_dbginfo5KlassC** undef, metadata ![[K_COPYABLE_VAR_CCFLOW_REINIT_IN_BLOCK_METADATA]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC]] +// CHECK: call void @llvm.dbg.value(metadata ptr undef, metadata ![[K_COPYABLE_VAR_CCFLOW_REINIT_IN_BLOCK_METADATA]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC]] // TODO: Should this be a deref like the original? -// CHECK: call void @llvm.dbg.addr(metadata %T21move_function_dbginfo5KlassC*** [[VAR]], metadata ![[K_COPYABLE_VAR_CCFLOW_REINIT_IN_BLOCK_METADATA]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC]] +// CHECK: call void @llvm.dbg.addr(metadata ptr [[VAR]], metadata ![[K_COPYABLE_VAR_CCFLOW_REINIT_IN_BLOCK_METADATA]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC]] // CHECK-NEXT: br label %[[BB_NEXT_2:[a-z\.0-9]+]], // // CHECK: [[BB_NEXT_2]]: @@ -572,14 +572,14 @@ public func copyableVarArgTestCCFlowReinitInBlockTest(_ k: inout Klass) { // CHECK-LABEL: define swiftcc void @"$s21move_function_dbginfo040addressOnlyVarTestCCFlowReinitOutOfBlockG0yyxmAA1PRzlF"( // CHECK: entry: -// CHECK: call void @llvm.dbg.addr(metadata %T21move_function_dbginfo1PP* [[VAR:%.*]], metadata ![[K_ADDRESSONLY_VAR_CCFLOW_REINIT_OUT_BLOCK_METADATA:[0-9]+]], metadata !DIExpression()), !dbg ![[ADDR_LOC:[0-9]*]] +// CHECK: call void @llvm.dbg.addr(metadata ptr [[VAR:%.*]], metadata ![[K_ADDRESSONLY_VAR_CCFLOW_REINIT_OUT_BLOCK_METADATA:[0-9]+]], metadata !DIExpression()), !dbg ![[ADDR_LOC:[0-9]*]] // CHECK-NEXT: br label %[[BB_NEXT:[a-z0-9\.]+]], // // CHECK: [[BB_NEXT]]: // CHECK: br i1 %{{[0-9]+}}, label %[[LHS:[0-9]+]], label %[[RHS:[0-9]+]], // // CHECK: [[LHS]]: -// CHECK: call void @llvm.dbg.value(metadata %T21move_function_dbginfo1PP* undef, metadata ![[K_ADDRESSONLY_VAR_CCFLOW_REINIT_OUT_BLOCK_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] +// CHECK: call void @llvm.dbg.value(metadata ptr undef, metadata ![[K_ADDRESSONLY_VAR_CCFLOW_REINIT_OUT_BLOCK_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] // CHECK: br label %[[CONT_BB:[a-z\.0-9]+]], // // CHECK: [[RHS]]: @@ -587,7 +587,7 @@ public func copyableVarArgTestCCFlowReinitInBlockTest(_ k: inout Klass) { // // CHECK: [[CONT_BB]]: // TODO: Should this be a deref like the original? -// CHECK: call void @llvm.dbg.addr(metadata %T21move_function_dbginfo1PP* [[VAR]], metadata ![[K_ADDRESSONLY_VAR_CCFLOW_REINIT_OUT_BLOCK_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] +// CHECK: call void @llvm.dbg.addr(metadata ptr [[VAR]], metadata ![[K_ADDRESSONLY_VAR_CCFLOW_REINIT_OUT_BLOCK_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] // CHECK-NEXT: br // CHECK: ret void // CHECK-NEXT: } @@ -604,14 +604,14 @@ public func addressOnlyVarTestCCFlowReinitOutOfBlockTest(_ x: T.Type) { // CHECK-LABEL: define swiftcc void @"$s21move_function_dbginfo043addressOnlyVarArgTestCCFlowReinitOutOfBlockH0yyAA1P_pz_xmtAaCRzlF"( // CHECK: entry: -// CHECK: call void @llvm.dbg.addr(metadata %T21move_function_dbginfo1PP** [[VAR:%.*]], metadata ![[K_ADDRESSONLY_VAR_CCFLOW_REINIT_OUT_BLOCK_METADATA:[0-9]+]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC:[0-9]*]] +// CHECK: call void @llvm.dbg.addr(metadata ptr [[VAR:%.*]], metadata ![[K_ADDRESSONLY_VAR_CCFLOW_REINIT_OUT_BLOCK_METADATA:[0-9]+]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC:[0-9]*]] // CHECK-NEXT: br label %[[BB_NEXT:[a-z0-9\.]+]], // // CHECK: [[BB_NEXT]]: // CHECK: br i1 %{{[0-9]+}}, label %[[LHS:[0-9]+]], label %[[RHS:[0-9]+]], // // CHECK: [[LHS]]: -// CHECK: call void @llvm.dbg.value(metadata %T21move_function_dbginfo1PP* undef, metadata ![[K_ADDRESSONLY_VAR_CCFLOW_REINIT_OUT_BLOCK_METADATA]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC]] +// CHECK: call void @llvm.dbg.value(metadata ptr undef, metadata ![[K_ADDRESSONLY_VAR_CCFLOW_REINIT_OUT_BLOCK_METADATA]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC]] // CHECK: br label %[[CONT_BB:[a-z\.0-9]+]], // // CHECK: [[RHS]]: @@ -619,7 +619,7 @@ public func addressOnlyVarTestCCFlowReinitOutOfBlockTest(_ x: T.Type) { // // CHECK: [[CONT_BB]]: // TODO: Should this be a deref like the original? -// CHECK: call void @llvm.dbg.addr(metadata %T21move_function_dbginfo1PP** [[VAR]], metadata ![[K_ADDRESSONLY_VAR_CCFLOW_REINIT_OUT_BLOCK_METADATA]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC]] +// CHECK: call void @llvm.dbg.addr(metadata ptr [[VAR]], metadata ![[K_ADDRESSONLY_VAR_CCFLOW_REINIT_OUT_BLOCK_METADATA]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC]] // CHECK-NEXT: br // CHECK: ret void // CHECK-NEXT: } @@ -635,16 +635,16 @@ public func addressOnlyVarArgTestCCFlowReinitOutOfBlockTest(_ k: inout (a // CHECK-LABEL: define swiftcc void @"$s21move_function_dbginfo037addressOnlyVarTestCCFlowReinitInBlockG0yyxmAA1PRzlF"( // CHECK: entry: -// CHECK: call void @llvm.dbg.addr(metadata %T21move_function_dbginfo1PP* [[VAR:%.*]], metadata ![[K_ADDRESSONLY_VAR_CCFLOW_REINIT_IN_BLOCK_METADATA:[0-9]+]], metadata !DIExpression()), !dbg ![[ADDR_LOC:[0-9]*]] +// CHECK: call void @llvm.dbg.addr(metadata ptr [[VAR:%.*]], metadata ![[K_ADDRESSONLY_VAR_CCFLOW_REINIT_IN_BLOCK_METADATA:[0-9]+]], metadata !DIExpression()), !dbg ![[ADDR_LOC:[0-9]*]] // CHECK-NEXT: br label %[[BB_NEXT:[a-z0-9\.]+]], // // CHECK: [[BB_NEXT]]: // CHECK: br i1 %{{[0-9]+}}, label %[[LHS:[0-9]+]], label %[[RHS:[0-9]+]], // // CHECK: [[LHS]]: -// CHECK: call void @llvm.dbg.value(metadata %T21move_function_dbginfo1PP* undef, metadata ![[K_ADDRESSONLY_VAR_CCFLOW_REINIT_IN_BLOCK_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] +// CHECK: call void @llvm.dbg.value(metadata ptr undef, metadata ![[K_ADDRESSONLY_VAR_CCFLOW_REINIT_IN_BLOCK_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] // TODO: Should this be a deref like the original? -// CHECK: call void @llvm.dbg.addr(metadata %T21move_function_dbginfo1PP* [[VAR]], metadata ![[K_ADDRESSONLY_VAR_CCFLOW_REINIT_IN_BLOCK_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] +// CHECK: call void @llvm.dbg.addr(metadata ptr [[VAR]], metadata ![[K_ADDRESSONLY_VAR_CCFLOW_REINIT_IN_BLOCK_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] // CHECK-NEXT: br label %[[BB_NEXT_2:[a-z\.0-9]+]], // // CHECK: [[BB_NEXT_2]]: @@ -669,16 +669,16 @@ public func addressOnlyVarTestCCFlowReinitInBlockTest(_ x: T.Type) { // CHECK-LABEL: define swiftcc void @"$s21move_function_dbginfo040addressOnlyVarArgTestCCFlowReinitInBlockH0yyAA1P_pz_xmtAaCRzlF"( // CHECK: entry: -// CHECK: call void @llvm.dbg.addr(metadata %T21move_function_dbginfo1PP** [[VAR:%.*]], metadata ![[K_ADDRESSONLY_VAR_CCFLOW_REINIT_IN_BLOCK_METADATA:[0-9]+]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC:[0-9]*]] +// CHECK: call void @llvm.dbg.addr(metadata ptr [[VAR:%.*]], metadata ![[K_ADDRESSONLY_VAR_CCFLOW_REINIT_IN_BLOCK_METADATA:[0-9]+]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC:[0-9]*]] // CHECK-NEXT: br label %[[BB_NEXT:[a-z0-9\.]+]], // // CHECK: [[BB_NEXT]]: // CHECK: br i1 %{{[0-9]+}}, label %[[LHS:[0-9]+]], label %[[RHS:[0-9]+]], // // CHECK: [[LHS]]: -// CHECK: call void @llvm.dbg.value(metadata %T21move_function_dbginfo1PP* undef, metadata ![[K_ADDRESSONLY_VAR_CCFLOW_REINIT_IN_BLOCK_METADATA]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC]] +// CHECK: call void @llvm.dbg.value(metadata ptr undef, metadata ![[K_ADDRESSONLY_VAR_CCFLOW_REINIT_IN_BLOCK_METADATA]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC]] // TODO: Should this be a deref like the original? -// CHECK: call void @llvm.dbg.addr(metadata %T21move_function_dbginfo1PP** [[VAR]], metadata ![[K_ADDRESSONLY_VAR_CCFLOW_REINIT_IN_BLOCK_METADATA]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC]] +// CHECK: call void @llvm.dbg.addr(metadata ptr [[VAR]], metadata ![[K_ADDRESSONLY_VAR_CCFLOW_REINIT_IN_BLOCK_METADATA]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC]] // CHECK-NEXT: br label %[[BB_NEXT_2:[a-z\.0-9]+]], // // CHECK: [[BB_NEXT_2]]: diff --git a/test/DebugInfo/move_function_dbginfo_async.swift b/test/DebugInfo/move_function_dbginfo_async.swift index 03185937b7e18..2a27a90da07df 100644 --- a/test/DebugInfo/move_function_dbginfo_async.swift +++ b/test/DebugInfo/move_function_dbginfo_async.swift @@ -1,6 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-swift-frontend -parse-as-library -disable-availability-checking -g -emit-sil -o - %s | %FileCheck -check-prefix=SIL %s -// RUN: %target-swift-frontend %use_no_opaque_pointers -parse-as-library -disable-availability-checking -g -emit-ir -o - %s | %FileCheck %s +// RUN: %target-swift-frontend -parse-as-library -disable-availability-checking -g -emit-ir -o - %s | %FileCheck %s // RUN: %target-swift-frontend -parse-as-library -disable-availability-checking -g -c %s -o %t/out.o // This test checks that: @@ -43,22 +43,22 @@ public func forceSplit5() async {} // Tests // /////////// -// CHECK-LABEL: define swifttailcc void @"$s27move_function_dbginfo_async13letSimpleTestyyxnYalF"(%swift.context* swiftasync %0, %swift.opaque* noalias %1, %swift.type* %T) +// CHECK-LABEL: define swifttailcc void @"$s27move_function_dbginfo_async13letSimpleTestyyxnYalF"(ptr swiftasync %0, ptr noalias %1, ptr %T) // CHECK: entry: -// CHECK: call void @llvm.dbg.addr(metadata %swift.context* %{{[0-9]+}}, metadata ![[SIMPLE_TEST_METADATA:[0-9]+]], metadata !DIExpression(DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 8, DW_OP_deref)), !dbg ![[ADDR_LOC:[0-9]+]] +// CHECK: call void @llvm.dbg.addr(metadata ptr %{{[0-9]+}}, metadata ![[SIMPLE_TEST_METADATA:[0-9]+]], metadata !DIExpression(DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 8, DW_OP_deref)), !dbg ![[ADDR_LOC:[0-9]+]] // CHECK: musttail call swifttailcc void // CHECK-NEXT: ret void -// CHECK-LABEL: define internal swifttailcc void @"$s27move_function_dbginfo_async13letSimpleTestyyxnYalFTQ0_"(i8* swiftasync %0) +// CHECK-LABEL: define internal swifttailcc void @"$s27move_function_dbginfo_async13letSimpleTestyyxnYalFTQ0_"(ptr swiftasync %0) // CHECK: entryresume.0: -// CHECK: call void @llvm.dbg.addr(metadata i8* %{{[0-9]+}}, metadata ![[SIMPLE_TEST_METADATA_2:[0-9]+]], metadata !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 8, DW_OP_deref)), +// CHECK: call void @llvm.dbg.addr(metadata ptr %{{[0-9]+}}, metadata ![[SIMPLE_TEST_METADATA_2:[0-9]+]], metadata !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 8, DW_OP_deref)), // CHECK: musttail call swifttailcc void // CHECK-NEXT: ret void // -// CHECK-LABEL: define internal swifttailcc void @"$s27move_function_dbginfo_async13letSimpleTestyyxnYalFTY1_"(i8* swiftasync %0) +// CHECK-LABEL: define internal swifttailcc void @"$s27move_function_dbginfo_async13letSimpleTestyyxnYalFTY1_"(ptr swiftasync %0) // CHECK: entryresume.1: -// CHECK: call void @llvm.dbg.addr(metadata i8* %{{[0-9]+}}, metadata ![[SIMPLE_TEST_METADATA_3:[0-9]+]], metadata !DIExpression(DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 8, DW_OP_deref)), !dbg ![[ADDR_LOC:[0-9]+]] -// CHECK: call void @llvm.dbg.value(metadata %swift.opaque* undef, metadata ![[SIMPLE_TEST_METADATA_3]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC]] +// CHECK: call void @llvm.dbg.addr(metadata ptr %{{[0-9]+}}, metadata ![[SIMPLE_TEST_METADATA_3:[0-9]+]], metadata !DIExpression(DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 8, DW_OP_deref)), !dbg ![[ADDR_LOC:[0-9]+]] +// CHECK: call void @llvm.dbg.value(metadata ptr undef, metadata ![[SIMPLE_TEST_METADATA_3]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC]] // CHECK: musttail call swifttailcc void // CHECK-NEXT: ret void @@ -88,35 +88,35 @@ public func letSimpleTest(_ msg: __owned T) async { use(consume msg) } -// CHECK-LABEL: define swifttailcc void @"$s27move_function_dbginfo_async13varSimpleTestyyxz_xtYalF"(%swift.context* swiftasync %0, %swift.opaque* %1, %swift.opaque* noalias %2, %swift.type* %T) -// CHECK: call void @llvm.dbg.addr(metadata %swift.context* %{{[0-9]+}}, metadata !{{[0-9]+}}, metadata !DIExpression(DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 8, DW_OP_deref)) -// CHECK: musttail call swifttailcc void @"$s27move_function_dbginfo_async10forceSplityyYaF"(%swift.context* swiftasync %{{[0-9]+}}) +// CHECK-LABEL: define swifttailcc void @"$s27move_function_dbginfo_async13varSimpleTestyyxz_xtYalF"(ptr swiftasync %0, ptr %1, ptr noalias %2, ptr %T) +// CHECK: call void @llvm.dbg.addr(metadata ptr %{{[0-9]+}}, metadata !{{[0-9]+}}, metadata !DIExpression(DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 8, DW_OP_deref)) +// CHECK: musttail call swifttailcc void @"$s27move_function_dbginfo_async10forceSplityyYaF"(ptr swiftasync %{{[0-9]+}}) // CHECK-NEXT: ret void // CHECK-NEXT: } // -// CHECK-LABEL: define internal swifttailcc void @"$s27move_function_dbginfo_async13varSimpleTestyyxz_xtYalFTQ0_"(i8* swiftasync %0) +// CHECK-LABEL: define internal swifttailcc void @"$s27move_function_dbginfo_async13varSimpleTestyyxz_xtYalFTQ0_"(ptr swiftasync %0) // CHECK: entryresume.0: -// CHECK: call void @llvm.dbg.addr(metadata i8* %{{[0-9]+}}, metadata !{{[0-9]+}}, metadata !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 8, DW_OP_deref)) -// CHECK: musttail call swifttailcc void @swift_task_switch(%swift.context* swiftasync %{{[0-9]+}}, i8* bitcast (void (i8*)* @"$s27move_function_dbginfo_async13varSimpleTestyyxz_xtYalFTY1_" to i8*), i64 0, i64 0) +// CHECK: call void @llvm.dbg.addr(metadata ptr %{{[0-9]+}}, metadata !{{[0-9]+}}, metadata !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 8, DW_OP_deref)) +// CHECK: musttail call swifttailcc void @swift_task_switch(ptr swiftasync %{{[0-9]+}}, ptr @"$s27move_function_dbginfo_async13varSimpleTestyyxz_xtYalFTY1_", i64 0, i64 0) // CHECK-NEXT: ret void // CHECK-NEXT: } // -// CHECK-LABEL: define internal swifttailcc void @"$s27move_function_dbginfo_async13varSimpleTestyyxz_xtYalFTY1_"(i8* swiftasync %0) +// CHECK-LABEL: define internal swifttailcc void @"$s27move_function_dbginfo_async13varSimpleTestyyxz_xtYalFTY1_"(ptr swiftasync %0) // CHECK: entryresume.1: -// CHECK: call void @llvm.dbg.addr(metadata i8* %{{[0-9]+}}, metadata ![[METADATA:[0-9]+]], metadata !DIExpression(DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 8, DW_OP_deref)), !dbg ![[ADDR_LOC:[0-9]+]] -// CHECK: call void @llvm.dbg.value(metadata %swift.opaque* undef, metadata ![[METADATA]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC]] -// CHECK: musttail call swifttailcc void @"$s27move_function_dbginfo_async10forceSplityyYaF"(%swift.context* swiftasync +// CHECK: call void @llvm.dbg.addr(metadata ptr %{{[0-9]+}}, metadata ![[METADATA:[0-9]+]], metadata !DIExpression(DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 8, DW_OP_deref)), !dbg ![[ADDR_LOC:[0-9]+]] +// CHECK: call void @llvm.dbg.value(metadata ptr undef, metadata ![[METADATA]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC]] +// CHECK: musttail call swifttailcc void @"$s27move_function_dbginfo_async10forceSplityyYaF"(ptr swiftasync // CHECK-NEXT: ret void // CHECK-NEXT: } // -// CHECK-LABEL: define internal swifttailcc void @"$s27move_function_dbginfo_async13varSimpleTestyyxz_xtYalFTQ2_"(i8* swiftasync %0) +// CHECK-LABEL: define internal swifttailcc void @"$s27move_function_dbginfo_async13varSimpleTestyyxz_xtYalFTQ2_"(ptr swiftasync %0) // CHECK: entryresume.2: -// CHECK-LABEL: define internal swifttailcc void @"$s27move_function_dbginfo_async13varSimpleTestyyxz_xtYalFTY3_"(i8* swiftasync %0) +// CHECK-LABEL: define internal swifttailcc void @"$s27move_function_dbginfo_async13varSimpleTestyyxz_xtYalFTY3_"(ptr swiftasync %0) // CHECK: entryresume.3: -// CHECK: call void @llvm.dbg.addr(metadata i8* %{{[0-9]+}}, metadata ![[METADATA:[0-9]+]], metadata !DIExpression(DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 8, DW_OP_deref)), !dbg ![[ADDR_LOC:[0-9]+]] -// CHECK: call void @llvm.dbg.value(metadata %swift.opaque* undef, metadata ![[METADATA]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC]] -// CHECK: call void @llvm.dbg.addr(metadata i8* %{{[0-9]+}}, metadata ![[METADATA]], metadata !DIExpression(DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 8, DW_OP_deref)), !dbg ![[ADDR_LOC]] +// CHECK: call void @llvm.dbg.addr(metadata ptr %{{[0-9]+}}, metadata ![[METADATA:[0-9]+]], metadata !DIExpression(DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 8, DW_OP_deref)), !dbg ![[ADDR_LOC:[0-9]+]] +// CHECK: call void @llvm.dbg.value(metadata ptr undef, metadata ![[METADATA]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC]] +// CHECK: call void @llvm.dbg.addr(metadata ptr %{{[0-9]+}}, metadata ![[METADATA]], metadata !DIExpression(DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 8, DW_OP_deref)), !dbg ![[ADDR_LOC]] // CHECK: musttail call swifttailcc void @"$s27move_function_dbginfo_async10forceSplityyYaF"( // CHECK-NEXT: ret void // CHECK-NEXT: } @@ -201,31 +201,31 @@ public func varSimpleTest(_ msg: inout T, _ msg2: T) async { // We don't have an argument here, so we shouldn't have an llvm.dbg.addr in the // initial function. // -// CHECK-LABEL: define swifttailcc void @"$s27move_function_dbginfo_async16varSimpleTestVaryyYaF"(%swift.context* swiftasync %0) +// CHECK-LABEL: define swifttailcc void @"$s27move_function_dbginfo_async16varSimpleTestVaryyYaF"(ptr swiftasync %0) // CHECK-NOT: llvm.dbg.addr // -// CHECK-LABEL: define internal swifttailcc void @"$s27move_function_dbginfo_async16varSimpleTestVaryyYaFTY0_"(i8* swiftasync %0) -// CHECK: call void @llvm.dbg.addr(metadata i8* %{{[0-9]+}}, metadata !{{[0-9]+}}, metadata !DIExpression(DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 8)) +// CHECK-LABEL: define internal swifttailcc void @"$s27move_function_dbginfo_async16varSimpleTestVaryyYaFTY0_"(ptr swiftasync %0) +// CHECK: call void @llvm.dbg.addr(metadata ptr %{{[0-9]+}}, metadata !{{[0-9]+}}, metadata !DIExpression(DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 8)) // -// CHECK-LABEL: define internal swifttailcc void @"$s27move_function_dbginfo_async16varSimpleTestVaryyYaFTQ1_"(i8* swiftasync %0) -// CHECK: call void @llvm.dbg.addr(metadata i8* %{{[0-9]+}}, metadata !{{[0-9]+}}, metadata !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 8)) +// CHECK-LABEL: define internal swifttailcc void @"$s27move_function_dbginfo_async16varSimpleTestVaryyYaFTQ1_"(ptr swiftasync %0) +// CHECK: call void @llvm.dbg.addr(metadata ptr %{{[0-9]+}}, metadata !{{[0-9]+}}, metadata !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 8)) -// CHECK-LABEL: define internal swifttailcc void @"$s27move_function_dbginfo_async16varSimpleTestVaryyYaFTY2_"(i8* swiftasync %0) -// CHECK: call void @llvm.dbg.addr(metadata i8* %{{[0-9]+}}, metadata ![[METADATA:[0-9]+]], metadata !DIExpression(DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 8)), !dbg ![[ADDR_LOC:[0-9]+]] -// CHECK: call void @llvm.dbg.value(metadata %T27move_function_dbginfo_async5KlassC** undef, metadata ![[METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] +// CHECK-LABEL: define internal swifttailcc void @"$s27move_function_dbginfo_async16varSimpleTestVaryyYaFTY2_"(ptr swiftasync %0) +// CHECK: call void @llvm.dbg.addr(metadata ptr %{{[0-9]+}}, metadata ![[METADATA:[0-9]+]], metadata !DIExpression(DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 8)), !dbg ![[ADDR_LOC:[0-9]+]] +// CHECK: call void @llvm.dbg.value(metadata ptr undef, metadata ![[METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] -// CHECK-LABEL: define internal swifttailcc void @"$s27move_function_dbginfo_async16varSimpleTestVaryyYaFTQ3_"(i8* swiftasync %0) +// CHECK-LABEL: define internal swifttailcc void @"$s27move_function_dbginfo_async16varSimpleTestVaryyYaFTQ3_"(ptr swiftasync %0) // We should only see an llvm.dbg.value here. // CHECK-NOT: llvm.dbg.addr -// CHECK: call void @llvm.dbg.value(metadata %T27move_function_dbginfo_async5KlassC** undef, +// CHECK: call void @llvm.dbg.value(metadata ptr undef, // CHECK-NOT: llvm.dbg.addr // // We should see first a llvm.dbg.value to undef the value until we reinit. Then // we should see a llvm.dbg.addr to reinit. // -// CHECK-LABEL: define internal swifttailcc void @"$s27move_function_dbginfo_async16varSimpleTestVaryyYaFTY4_"(i8* swiftasync %0) -// CHECK: call void @llvm.dbg.value(metadata %T27move_function_dbginfo_async5KlassC** undef, metadata ![[METADATA:[0-9]+]], metadata !DIExpression()), !dbg ![[ADDR_LOC:[0-9]+]] -// CHECK: call void @llvm.dbg.addr(metadata i8* %{{[0-9]+}}, metadata ![[METADATA]], metadata !DIExpression(DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 8)), !dbg ![[ADDR_LOC]] +// CHECK-LABEL: define internal swifttailcc void @"$s27move_function_dbginfo_async16varSimpleTestVaryyYaFTY4_"(ptr swiftasync %0) +// CHECK: call void @llvm.dbg.value(metadata ptr undef, metadata ![[METADATA:[0-9]+]], metadata !DIExpression()), !dbg ![[ADDR_LOC:[0-9]+]] +// CHECK: call void @llvm.dbg.addr(metadata ptr %{{[0-9]+}}, metadata ![[METADATA]], metadata !DIExpression(DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 8)), !dbg ![[ADDR_LOC]] // We are not an argument, so no problem here. // @@ -312,20 +312,20 @@ public func varSimpleTestVar() async { // CHECK-NEXT: } // CHECK-LABEL: define internal swifttailcc void @"$s27move_function_dbginfo_async20letArgCCFlowTrueTestyyxnYalFTQ0_"( -// CHECK: call void @llvm.dbg.addr(metadata i8* %{{[0-9]+}}, metadata !{{[0-9]+}}, metadata !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 8, DW_OP_deref)), -// CHECK: musttail call swifttailcc void @swift_task_switch(%swift.context* swiftasync %{{[0-9]+}}, i8* bitcast (void (i8*)* @"$s27move_function_dbginfo_async20letArgCCFlowTrueTestyyxnYalFTY1_" to i8*), i64 0, i64 0) +// CHECK: call void @llvm.dbg.addr(metadata ptr %{{[0-9]+}}, metadata !{{[0-9]+}}, metadata !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 8, DW_OP_deref)), +// CHECK: musttail call swifttailcc void @swift_task_switch(ptr swiftasync %{{[0-9]+}}, ptr @"$s27move_function_dbginfo_async20letArgCCFlowTrueTestyyxnYalFTY1_", i64 0, i64 0) // CHECK-NEXT: ret void // CHECK-NEXT: } // CHECK-LABEL: define internal swifttailcc void @"$s27move_function_dbginfo_async20letArgCCFlowTrueTestyyxnYalFTY1_"( -// CHECK: call void @llvm.dbg.addr(metadata i8* %{{[0-9]+}}, metadata ![[METADATA:[0-9]*]], metadata !DIExpression(DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 8, DW_OP_deref)), !dbg ![[ADDR_LOC:[0-9]*]] +// CHECK: call void @llvm.dbg.addr(metadata ptr %{{[0-9]+}}, metadata ![[METADATA:[0-9]*]], metadata !DIExpression(DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 8, DW_OP_deref)), !dbg ![[ADDR_LOC:[0-9]*]] // CHECK-NEXT: br label %[[BLOCK:[a-zA-Z\.0-9]*]], // // CHECK: [[BLOCK]]: // CHECK: br i1 %{{[0-9]}}, label %[[LHS_BLOCK:[a-zA-Z\.0-9]*]], label %[[RHS_BLOCK:[a-zA-Z\.0-9]*]], // // CHECK: [[LHS_BLOCK]]: -// CHECK: call void @llvm.dbg.value(metadata %swift.opaque* undef, metadata ![[METADATA]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC]] +// CHECK: call void @llvm.dbg.value(metadata ptr undef, metadata ![[METADATA]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC]] // CHECK: musttail call swifttailcc void @"$s27move_function_dbginfo_async11forceSplit2yyYaF"( // CHECK-NEXT: ret void // @@ -341,22 +341,22 @@ public func varSimpleTestVar() async { // _move. // // CHECK-LABEL: define internal swifttailcc void @"$s27move_function_dbginfo_async20letArgCCFlowTrueTestyyxnYalFTQ2_"( -// CHECK: call void @llvm.dbg.value(metadata %swift.opaque* undef, metadata ![[METADATA:[0-9]*]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC:[0-9]*]] -// CHECK: call void @llvm.dbg.value(metadata %swift.opaque* undef, metadata ![[METADATA]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC]] +// CHECK: call void @llvm.dbg.value(metadata ptr undef, metadata ![[METADATA:[0-9]*]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC:[0-9]*]] +// CHECK: call void @llvm.dbg.value(metadata ptr undef, metadata ![[METADATA]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC]] // CHECK: musttail call swifttailcc void @"$s27move_function_dbginfo_async11forceSplit4yyYaF"( // CHECK-NEXT: ret void // // This is the false branch. // // CHECK-LABEL: define internal swifttailcc void @"$s27move_function_dbginfo_async20letArgCCFlowTrueTestyyxnYalFTQ3_"( -// CHECK: call void @llvm.dbg.addr(metadata i8* %{{[0-9]+}}, metadata !{{[0-9]+}}, metadata !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 8, DW_OP_deref)) +// CHECK: call void @llvm.dbg.addr(metadata ptr %{{[0-9]+}}, metadata !{{[0-9]+}}, metadata !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 8, DW_OP_deref)) // CHECK: musttail call swifttailcc void @"$s27move_function_dbginfo_async11forceSplit4yyYaF"( // CHECK-NEXT: ret void, // CHECK-NEXT: } // // This is the continuation block // CHECK-LABEL: define internal swifttailcc void @"$s27move_function_dbginfo_async20letArgCCFlowTrueTestyyxnYalFTQ4_"( -// CHECK: call void @llvm.dbg.value(metadata %swift.opaque* undef, metadata !{{.*}}, metadata !DIExpression(DW_OP_deref)), +// CHECK: call void @llvm.dbg.value(metadata ptr undef, metadata !{{.*}}, metadata !DIExpression(DW_OP_deref)), // RUN: %llvm-dwarfdump -c --name='$s3out20letArgCCFlowTrueTestyyxnYalF' %t/out.o | %FileCheck -check-prefix=DWARF17 %s // DWARF17: DW_TAG_subprogram @@ -451,18 +451,18 @@ public func letArgCCFlowTrueTest(_ msg: __owned T) async { // SIL: } // end sil function '$s27move_function_dbginfo_async20varArgCCFlowTrueTestyyxzYaAA1PRzlF' // CHECK-LABEL: define swifttailcc void @"$s27move_function_dbginfo_async20varArgCCFlowTrueTestyyxzYaAA1PRzlF"( -// CHECK: call void @llvm.dbg.addr(metadata %swift.context* %{{[0-9]+}}, metadata !{{[0-9]+}}, metadata !DIExpression(DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 48, DW_OP_deref)), +// CHECK: call void @llvm.dbg.addr(metadata ptr %{{[0-9]+}}, metadata !{{[0-9]+}}, metadata !DIExpression(DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 48, DW_OP_deref)), // CHECK: musttail call swifttailcc void @"$s27move_function_dbginfo_async11forceSplit1yyYaF"( // CHECK-LABEL: define internal swifttailcc void @"$s27move_function_dbginfo_async20varArgCCFlowTrueTestyyxzYaAA1PRzlFTQ0_"( -// CHECK: call void @llvm.dbg.addr(metadata i8* %{{[0-9]+}}, metadata !{{[0-9]+}}, metadata !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 48, DW_OP_deref)), +// CHECK: call void @llvm.dbg.addr(metadata ptr %{{[0-9]+}}, metadata !{{[0-9]+}}, metadata !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 48, DW_OP_deref)), // CHECK-LABEL: define internal swifttailcc void @"$s27move_function_dbginfo_async20varArgCCFlowTrueTestyyxzYaAA1PRzlFTY1_"( -// CHECK: call void @llvm.dbg.addr(metadata i8* %{{[0-9]+}}, metadata ![[METADATA:[0-9]+]], metadata !DIExpression(DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 48, DW_OP_deref)), !dbg ![[ADDR_LOC:[0-9]+]] +// CHECK: call void @llvm.dbg.addr(metadata ptr %{{[0-9]+}}, metadata ![[METADATA:[0-9]+]], metadata !DIExpression(DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 48, DW_OP_deref)), !dbg ![[ADDR_LOC:[0-9]+]] // CHECK: br i1 %{{[0-9]+}}, label %[[LHS_BLOCK:[a-zA-Z0-9]+]], label %[[RHS_BLOCK:[a-zA-Z0-9]+]] // CHECK: [[LHS_BLOCK]]: -// CHECK: call void @llvm.dbg.value(metadata %swift.opaque* undef, metadata ![[METADATA]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC]] +// CHECK: call void @llvm.dbg.value(metadata ptr undef, metadata ![[METADATA]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC]] // CHECK: musttail call swifttailcc void @"$s27move_function_dbginfo_async11forceSplit2yyYaF"( // CHECK: [[RHS_BLOCK]]: @@ -471,34 +471,34 @@ public func letArgCCFlowTrueTest(_ msg: __owned T) async { // CHECK-LABEL: define internal swifttailcc void @"$s27move_function_dbginfo_async20varArgCCFlowTrueTestyyxzYaAA1PRzlFTQ2_"( // CHECK-NOT: @llvm.dbg.addr -// CHECK: call void @llvm.dbg.value(metadata %swift.opaque* undef, metadata !{{[0-9]+}}, metadata !DIExpression(DW_OP_deref)), +// CHECK: call void @llvm.dbg.value(metadata ptr undef, metadata !{{[0-9]+}}, metadata !DIExpression(DW_OP_deref)), // CHECK-NOT: @llvm.dbg.addr -// CHECK: musttail call swifttailcc void @swift_task_switch(%swift.context* swiftasync %{{[0-9]+}}, i8* bitcast (void (i8*)* @"$s27move_function_dbginfo_async20varArgCCFlowTrueTestyyxzYaAA1PRzlFTY3_" to i8*), i64 0, i64 0) +// CHECK: musttail call swifttailcc void @swift_task_switch(ptr swiftasync %{{[0-9]+}}, ptr @"$s27move_function_dbginfo_async20varArgCCFlowTrueTestyyxzYaAA1PRzlFTY3_", i64 0, i64 0) // CHECK-LABEL: define internal swifttailcc void @"$s27move_function_dbginfo_async20varArgCCFlowTrueTestyyxzYaAA1PRzlFTY3_"( // CHECK-NOT: @llvm.dbg.addr -// CHECK: call void @llvm.dbg.value(metadata %swift.opaque* undef, metadata ![[METADATA:[0-9]+]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC:[0-9]+]] -// CHECK: call void @llvm.dbg.value(metadata %swift.opaque* undef, metadata ![[METADATA]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC]] -// CHECK: call void @llvm.dbg.addr(metadata i8* %{{[0-9]+}}, metadata ![[METADATA]], metadata !DIExpression(DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 48, DW_OP_deref)), !dbg ![[ADDR_LOC]] +// CHECK: call void @llvm.dbg.value(metadata ptr undef, metadata ![[METADATA:[0-9]+]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC:[0-9]+]] +// CHECK: call void @llvm.dbg.value(metadata ptr undef, metadata ![[METADATA]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC]] +// CHECK: call void @llvm.dbg.addr(metadata ptr %{{[0-9]+}}, metadata ![[METADATA]], metadata !DIExpression(DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 48, DW_OP_deref)), !dbg ![[ADDR_LOC]] // CHECK: musttail call swifttailcc void @"$s27move_function_dbginfo_async11forceSplit4yyYaF"( // CHECK-LABEL: define internal swifttailcc void @"$s27move_function_dbginfo_async20varArgCCFlowTrueTestyyxzYaAA1PRzlFTQ4_"( // CHECK-NOT: @llvm.dbg.value -// CHECK: call void @llvm.dbg.addr(metadata i8* %{{[0-9]+}}, metadata ![[METADATA:[0-9]+]], metadata !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 48, DW_OP_deref)), !dbg ![[ADDR_LOC:[0-9]+]] -// CHECK: call void @llvm.dbg.value(metadata %swift.opaque* undef, metadata ![[METADATA]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC]] -// CHECK: musttail call swifttailcc void @swift_task_switch(%swift.context* swiftasync %{{[0-9]+}}, i8* bitcast (void (i8*)* @"$s27move_function_dbginfo_async20varArgCCFlowTrueTestyyxzYaAA1PRzlFTY5_" to i8*), +// CHECK: call void @llvm.dbg.addr(metadata ptr %{{[0-9]+}}, metadata ![[METADATA:[0-9]+]], metadata !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 48, DW_OP_deref)), !dbg ![[ADDR_LOC:[0-9]+]] +// CHECK: call void @llvm.dbg.value(metadata ptr undef, metadata ![[METADATA]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC]] +// CHECK: musttail call swifttailcc void @swift_task_switch(ptr swiftasync %{{[0-9]+}}, ptr @"$s27move_function_dbginfo_async20varArgCCFlowTrueTestyyxzYaAA1PRzlFTY5_", // CHECK: define internal swifttailcc void @"$s27move_function_dbginfo_async20varArgCCFlowTrueTestyyxzYaAA1PRzlFTY5_"( -// CHECK: call void @llvm.dbg.value(metadata %swift.opaque* undef, metadata ![[METADATA:[0-9]+]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC:[0-9]+]] -// CHECK: call void @llvm.dbg.value(metadata %swift.opaque* undef, metadata ![[METADATA]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC]] -// CHECK: call void @llvm.dbg.addr(metadata i8* %{{[0-9]+}}, metadata ![[METADATA]], metadata !DIExpression(DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 48, DW_OP_deref)), !dbg ![[ADDR_LOC]] +// CHECK: call void @llvm.dbg.value(metadata ptr undef, metadata ![[METADATA:[0-9]+]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC:[0-9]+]] +// CHECK: call void @llvm.dbg.value(metadata ptr undef, metadata ![[METADATA]], metadata !DIExpression(DW_OP_deref)), !dbg ![[ADDR_LOC]] +// CHECK: call void @llvm.dbg.addr(metadata ptr %{{[0-9]+}}, metadata ![[METADATA]], metadata !DIExpression(DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 48, DW_OP_deref)), !dbg ![[ADDR_LOC]] // CHECK: musttail call swifttailcc void @"$s27move_function_dbginfo_async11forceSplit4yyYaF"( // CHECK-LABEL: define internal swifttailcc void @"$s27move_function_dbginfo_async20varArgCCFlowTrueTestyyxzYaAA1PRzlFTQ6_"( // CHECK-NOT: @llvm.dbg.value( -// CHECK: call void @llvm.dbg.addr(metadata i8* %{{[0-9]+}}, metadata !{{[0-9]+}}, metadata !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 48, DW_OP_deref)), +// CHECK: call void @llvm.dbg.addr(metadata ptr %{{[0-9]+}}, metadata !{{[0-9]+}}, metadata !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 16, DW_OP_plus_uconst, 48, DW_OP_deref)), // CHECK-NOT: @llvm.dbg.value( -// CHECK: musttail call swifttailcc void %{{[0-9]+}}(%swift.context* swiftasync +// CHECK: musttail call swifttailcc void %{{[0-9]+}}(ptr swiftasync // CHECK-NEXT: ret void, // CHECK-NEXT: } diff --git a/test/DebugInfo/nostorage.swift b/test/DebugInfo/nostorage.swift index 21267c6de1421..9b3741cc53238 100644 --- a/test/DebugInfo/nostorage.swift +++ b/test/DebugInfo/nostorage.swift @@ -1,5 +1,4 @@ -// RUN: %target-swift-frontend %use_no_opaque_pointers %s -emit-ir -g -o %t -// RUN: %target-swift-frontend %s -emit-ir -g +// RUN: %target-swift-frontend %s -emit-ir -g -o %t // RUN: cat %t | %FileCheck %s --check-prefix=CHECK1 // RUN: cat %t | %FileCheck %s --check-prefix=CHECK2 // RUN: cat %t | %FileCheck %s --check-prefix=CHECK3 @@ -29,7 +28,7 @@ struct AStruct {} // CHECK2: define{{.*}}app public func app() { // No members? No storage! - // CHECK2: call void @llvm.dbg.value(metadata {{.*}}* undef, + // CHECK2: call void @llvm.dbg.value(metadata ptr undef, // CHECK2-SAME: metadata ![[AT:.*]], metadata // CHECK2: ![[AT]] = !DILocalVariable(name: "at",{{.*}}line: [[@LINE+1]] var at = AStruct() diff --git a/test/DebugInfo/protocol-extension.swift b/test/DebugInfo/protocol-extension.swift index 30788b2354444..aace6d8336245 100644 --- a/test/DebugInfo/protocol-extension.swift +++ b/test/DebugInfo/protocol-extension.swift @@ -1,5 +1,4 @@ -// RUN: %target-swift-frontend %use_no_opaque_pointers -primary-file %s -emit-ir -g -o - | %FileCheck %s -// RUN: %target-swift-frontend -primary-file %s -emit-ir -g -o - +// RUN: %target-swift-frontend -primary-file %s -emit-ir -g -o - | %FileCheck %s public protocol P { var v : Int32 { get }; @@ -9,8 +8,8 @@ public extension P { // CHECK: define {{.*}}swiftcc i32 @"$s4main1PPAAE1fs5Int32VyF" public func f() -> Int32 { // CHECK-NEXT: entry: - // CHECK-NEXT: %[[ALLOCA:.*]] = alloca %swift.type*, - // CHECK-NEXT: @llvm.dbg.declare(metadata %swift.type** %[[ALLOCA]], + // CHECK-NEXT: %[[ALLOCA:.*]] = alloca ptr, + // CHECK-NEXT: @llvm.dbg.declare(metadata ptr %[[ALLOCA]], // CHECK-SAME: metadata ![[SELFMETA:.*]], metadata !DIExpression()) return v } diff --git a/test/DebugInfo/protocolarg.swift b/test/DebugInfo/protocolarg.swift index 3dcaf60722808..999def8e3680b 100644 --- a/test/DebugInfo/protocolarg.swift +++ b/test/DebugInfo/protocolarg.swift @@ -1,5 +1,4 @@ -// RUN: %target-swift-frontend %use_no_opaque_pointers %s -emit-ir -g -o - | %FileCheck %s -// RUN: %target-swift-frontend %s -emit-ir -g -o - +// RUN: %target-swift-frontend %s -emit-ir -g -o - | %FileCheck %s func markUsed(_ t: T) {} func use(_ t: inout T) {} @@ -9,10 +8,10 @@ public protocol IGiveOutInts { } // CHECK: define {{.*}}@"$s11protocolarg16printSomeNumbersyyAA12IGiveOutInts_pF" -// CHECK: @llvm.dbg.declare(metadata %T11protocolarg12IGiveOutIntsP** % +// CHECK: @llvm.dbg.declare(metadata ptr % // CHECK-SAME: metadata ![[ARG:[0-9]+]], // CHECK-SAME: metadata !DIExpression(DW_OP_deref)) -// CHECK: @llvm.dbg.declare(metadata %T11protocolarg12IGiveOutIntsP* % +// CHECK: @llvm.dbg.declare(metadata ptr % // CHECK-SAME: metadata ![[VAR:.*]], metadata !DIExpression()) public func printSomeNumbers(_ gen: IGiveOutInts) { diff --git a/test/DebugInfo/resilient_debug_value.sil b/test/DebugInfo/resilient_debug_value.sil index 25e44b6834aa3..73054d0df6ed3 100644 --- a/test/DebugInfo/resilient_debug_value.sil +++ b/test/DebugInfo/resilient_debug_value.sil @@ -5,8 +5,7 @@ // RUN: -emit-module-path=%t/resilient_struct.swiftmodule \ // RUN: -module-name=resilient_struct %S/../Inputs/resilient_struct.swift // -// RUN: %target-swift-frontend %use_no_opaque_pointers -g -I %t -emit-ir %s -o - | %FileCheck %s -// RUN: %target-swift-frontend -g -I %t -emit-ir %s -o - +// RUN: %target-swift-frontend -g -I %t -emit-ir %s -o - | %FileCheck %s // REQUIRES: CPU=arm64 || CPU=x86_64 @@ -23,6 +22,6 @@ bb0: return %1 : $() } // CHECK: define{{.*}} swiftcc void @test_debug_value_resilient() -// CHECK: [[ASSERTIONSDBG:%.*]] = alloca i8* +// CHECK: [[ASSERTIONSDBG:%.*]] = alloca ptr // CHECK: [[ASSERTIONS:%.*]] = alloca i8, i64 %size -// CHECK: store i8* [[ASSERTIONS]], i8** [[ASSERTIONSDBG]] +// CHECK: store ptr [[ASSERTIONS]], ptr [[ASSERTIONSDBG]] diff --git a/test/DebugInfo/return.swift b/test/DebugInfo/return.swift index 65ac0407e357d..e42fd3210b637 100644 --- a/test/DebugInfo/return.swift +++ b/test/DebugInfo/return.swift @@ -1,5 +1,4 @@ -// RUN: %target-swift-frontend %use_no_opaque_pointers %s -g -emit-ir -o - | %FileCheck %s -// RUN: %target-swift-frontend %s -g -emit-ir -o - +// RUN: %target-swift-frontend %s -g -emit-ir -o - | %FileCheck %s class X { init (i : Int64) { x = i } @@ -9,20 +8,20 @@ class X { // CHECK: define {{.*}}ifelseexpr public func ifelseexpr() -> Int64 { var x = X(i:0) - // CHECK: [[ALLOCA:%.*]] = alloca %T6return1XC* + // CHECK: [[ALLOCA:%.*]] = alloca ptr // CHECK: [[TMP:%.*]] = call swiftcc %swift.metadata_response @"$s6return1XCMa"( // CHECK: [[META:%.*]] = extractvalue %swift.metadata_response [[TMP]], 0 - // CHECK: [[X:%.*]] = call {{.*}}%T6return1XC* @"$s6return1XC1iACs5Int64V_tcfC"( - // CHECK-SAME: i64 0, %swift.type* swiftself [[META]]) - // CHECK: store %T6return1XC* [[X]], %T6return1XC** [[ALLOCA]] - // CHECK: @swift_release to void (%T6return1XC*)*)(%T6return1XC* [[X]]) + // CHECK: [[X:%.*]] = call {{.*}}ptr @"$s6return1XC1iACs5Int64V_tcfC"( + // CHECK-SAME: i64 0, ptr swiftself [[META]]) + // CHECK: store ptr [[X]], ptr [[ALLOCA]] + // CHECK: @swift_release if true { x.x += 1 } else { x.x -= 1 } - // CHECK: [[L:%.*]] = load %T6return1XC*, %T6return1XC** [[ALLOCA]] - // CHECK: @swift_release to void (%T6return1XC*)*)(%T6return1XC* [[L]]) + // CHECK: [[L:%.*]] = load ptr, ptr [[ALLOCA]] + // CHECK: @swift_release // CHECK-SAME: , !dbg ![[RELEASE:.*]] // The ret instruction should be in the same scope as the return expression. // CHECK: ret{{.*}}, !dbg ![[RELEASE]] diff --git a/test/DebugInfo/self.swift b/test/DebugInfo/self.swift index e46c369ef1fa4..3cd5cae576a5f 100644 --- a/test/DebugInfo/self.swift +++ b/test/DebugInfo/self.swift @@ -1,5 +1,4 @@ -// RUN: %target-swift-frontend %use_no_opaque_pointers -primary-file %s -emit-ir -g -o - | %FileCheck %s -// RUN: %target-swift-frontend -primary-file %s -emit-ir -g -o - +// RUN: %target-swift-frontend -primary-file %s -emit-ir -g -o - | %FileCheck %s public struct stuffStruct { var a: Int64 = 6 @@ -17,7 +16,7 @@ public func f() { // CHECK: define {{.*}} @"$s4self11stuffStructVACycfC"( // CHECK-NEXT: entry: // CHECK: %[[ALLOCA:.*]] = alloca %T4self11stuffStructV, align {{(4|8)}} -// CHECK: call void @llvm.dbg.declare(metadata %T4self11stuffStructV* %[[ALLOCA]], +// CHECK: call void @llvm.dbg.declare(metadata ptr %[[ALLOCA]], // CHECK-SAME: metadata ![[SELF:.*]], metadata !DIExpression()), !dbg // CHECK: ![[STUFFSTRUCT:.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "stuffStruct", scope:{{.*}}identifier // CHECK: ![[SELF]] = !DILocalVariable(name: "self", scope diff --git a/test/DebugInfo/shadow_copies.swift b/test/DebugInfo/shadow_copies.swift index 4d3a7af891fa8..c3e9bdd4dfaed 100644 --- a/test/DebugInfo/shadow_copies.swift +++ b/test/DebugInfo/shadow_copies.swift @@ -1,9 +1,6 @@ -// RUN: %target-swift-frontend %use_no_opaque_pointers %s -Onone -emit-ir -g -o - | %FileCheck %s -// RUN: %target-swift-frontend %s -Onone -emit-ir -g -o - -// RUN: %target-swift-frontend %use_no_opaque_pointers %s -Onone -emit-ir -g -o - \ -// RUN: -disable-debugger-shadow-copies | %FileCheck %s --check-prefix=NOCOPY +// RUN: %target-swift-frontend %s -Onone -emit-ir -g -o - | %FileCheck %s // RUN: %target-swift-frontend %s -Onone -emit-ir -g -o - \ -// RUN: -disable-debugger-shadow-copies +// RUN: -disable-debugger-shadow-copies | %FileCheck %s --check-prefix=NOCOPY class ClassA { var x : Int64 @@ -22,15 +19,15 @@ class ClassB : ClassA { // CHECK: @"$s{{.*}}6ClassBCyACs5Int64Vcfc" // NOCOPY: @"$s{{.*}}6ClassBCyACs5Int64Vcfc" - // CHECK: alloca {{.*}}ClassBC* - // NOCOPY: alloca {{.*}}ClassBC* + // CHECK: alloca ptr + // NOCOPY: alloca ptr // CHECK: alloca i64 // CHECK-NOT: alloca // NOCOPY-NOT: alloca - // CHECK: ret {{.*}}ClassBC - // NOCOPY: ret {{.*}}ClassBC + // CHECK: ret ptr + // NOCOPY: ret ptr super.init (input) } } @@ -45,7 +42,7 @@ class ClassC // NOCOPY: define {{.*}}@"$s13shadow_copies6ClassCCACycfc" init () { - // CHECK: alloca %T13shadow_copies6ClassCC* + // CHECK: alloca ptr // CHECK-NOT: alloca // NOCOPY-NOT: alloca diff --git a/test/DebugInfo/shadowcopy-linetable.swift b/test/DebugInfo/shadowcopy-linetable.swift index 521ebf7ee043c..777cf88248a77 100644 --- a/test/DebugInfo/shadowcopy-linetable.swift +++ b/test/DebugInfo/shadowcopy-linetable.swift @@ -1,5 +1,4 @@ -// RUN: %target-swift-frontend %use_no_opaque_pointers %s -emit-ir -g -o - | %FileCheck %s -// RUN: %target-swift-frontend %s -emit-ir -g -o - +// RUN: %target-swift-frontend %s -emit-ir -g -o - | %FileCheck %s func markUsed(_ t: T) {} @@ -7,13 +6,13 @@ func foo(_ x: inout Int64) { // Make sure the shadow copy is being made in the prologue or (at // line 0), but the code to load the value from the inout storage is // not. - // CHECK: %[[X:.*]] = alloca %Ts5Int64V*, align {{(4|8)}} + // CHECK: define hidden swiftcc void @"$s4main3fooyys5Int64VzF" + // CHECK: %[[X:.*]] = alloca ptr, align {{(4|8)}} // CHECK-NEXT: call void @llvm.dbg.declare - // CHECK-NEXT: %[[ZEROED:[0-9]+]] = bitcast %Ts5Int64V** %[[X]] to i8*{{$}} - // CHECK-NEXT: call void @llvm.memset.{{.*}}(i8* align {{(4|8)}} %[[ZEROED]], i8 0 - // CHECK: store %Ts5Int64V* %0, %Ts5Int64V** %[[X]], align {{(4|8)}} + // CHECK-NEXT: call void @llvm.memset.{{.*}}(ptr align {{(4|8)}} %[[X]], i8 0 + // CHECK: store ptr %0, ptr %[[X]], align {{(4|8)}} // CHECK-SAME: !dbg ![[LOC0:.*]] - // CHECK-NEXT: getelementptr inbounds %Ts5Int64V, %Ts5Int64V* %0, i32 0, i32 0, + // CHECK-NEXT: getelementptr inbounds %Ts5Int64V, ptr %0, i32 0, i32 0, // CHECK-SAME: !dbg ![[LOC0]] // CHECK: ![[LOC0]] = !DILocation(line: 0, // CHECK: !DILocation(line: [[@LINE+1]], diff --git a/test/DebugInfo/sil_combine.sil b/test/DebugInfo/sil_combine.sil index a8ede98677bf3..ee38762a5b5cc 100644 --- a/test/DebugInfo/sil_combine.sil +++ b/test/DebugInfo/sil_combine.sil @@ -1,6 +1,5 @@ // RUN: %target-sil-opt -sil-verify-all -sil-combine %s | %FileCheck %s -// RUN: %target-swift-frontend %use_no_opaque_pointers -g -O -emit-ir -primary-file %s | %FileCheck --check-prefix=CHECK-IR %s -// RUN: %target-swift-frontend -g -O -emit-ir -primary-file %s +// RUN: %target-swift-frontend -g -O -emit-ir -primary-file %s | %FileCheck --check-prefix=CHECK-IR %s sil_stage canonical @@ -18,7 +17,7 @@ bb0(%0 : $Builtin.RawPointer): %addr1 = index_addr %addr : $*UInt8, %offset1 : $Builtin.Word // CHECK: debug_value %[[ADDR]] : $*UInt8, let, name "hello" // CHECK-SAME: expr op_constu:3:op_plus:op_deref - // CHECK-IR: call void @llvm.dbg.value(metadata i8* %0, metadata ![[DBG_VAR:[0-9]+]], + // CHECK-IR: call void @llvm.dbg.value(metadata ptr %0, metadata ![[DBG_VAR:[0-9]+]], // CHECK-IR-SAME: !DIExpression(DW_OP_constu, 3, DW_OP_plus, DW_OP_deref) debug_value %addr1 : $*UInt8, let, name "hello", expr op_deref %addr2 = index_addr %addr1 : $*UInt8, %offset2 : $Builtin.Word diff --git a/test/DebugInfo/struct_resilience.swift b/test/DebugInfo/struct_resilience.swift index 96cdbddf1b3d5..d3f5a2fcc0c69 100644 --- a/test/DebugInfo/struct_resilience.swift +++ b/test/DebugInfo/struct_resilience.swift @@ -6,15 +6,13 @@ // RUN: -emit-module-path=%t/resilient_struct.swiftmodule \ // RUN: -module-name=resilient_struct %S/../Inputs/resilient_struct.swift // -// RUN: %target-swift-frontend %use_no_opaque_pointers -g -I %t -emit-ir -enable-library-evolution %s \ -// RUN: -o - | %FileCheck %s // RUN: %target-swift-frontend -g -I %t -emit-ir -enable-library-evolution %s \ -// RUN: -o - +// RUN: -o - | %FileCheck %s // import resilient_struct -// CHECK-LABEL: define{{.*}} swiftcc void @"$s17struct_resilience9takesSizeyy010resilient_A00D0VF"(%swift.opaque* noalias nocapture %0) -// CHECK-LLDB-LABEL: define{{.*}} swiftcc void @"$s17struct_resilience9takesSizeyy010resilient_A00D0VF"(%T16resilient_struct4SizeV* noalias nocapture dereferenceable({{8|16}}) %0) +// CHECK-LABEL: define{{.*}} swiftcc void @"$s17struct_resilience9takesSizeyy010resilient_A00D0VF"(ptr noalias nocapture %0) +// CHECK-LLDB-LABEL: define{{.*}} swiftcc void @"$s17struct_resilience9takesSizeyy010resilient_A00D0VF"(ptr noalias nocapture dereferenceable({{8|16}}) %0) public func takesSize(_ s: Size) {} @@ -23,12 +21,12 @@ public func takesSize(_ s: Size) {} func f() { let s1 = Size(w: 1, h: 2) takesSize(s1) - // CHECK: %[[ADDR:.*]] = alloca i8* - // CHECK: call void @llvm.dbg.declare(metadata i8** %[[ADDR]], + // CHECK: %[[ADDR:.*]] = alloca ptr + // CHECK: call void @llvm.dbg.declare(metadata ptr %[[ADDR]], // CHECK-SAME: metadata ![[V1:[0-9]+]], // CHECK-SAME: metadata !DIExpression(DW_OP_deref)) // CHECK: %[[S1:.*]] = alloca i8, - // CHECK: store i8* %[[S1]], i8** %[[ADDR]] + // CHECK: store ptr %[[S1]], ptr %[[ADDR]] } f() diff --git a/test/DebugInfo/structs.swift b/test/DebugInfo/structs.swift index 00321ff86397a..4a951f9c21df9 100644 --- a/test/DebugInfo/structs.swift +++ b/test/DebugInfo/structs.swift @@ -1,5 +1,4 @@ -// RUN: %target-swift-frontend %use_no_opaque_pointers -primary-file %s -emit-ir -g -o - | %FileCheck %s -// RUN: %target-swift-frontend -primary-file %s -emit-ir -g -o - +// RUN: %target-swift-frontend -primary-file %s -emit-ir -g -o - | %FileCheck %s // Capture the pointer size from type Int // CHECK: %TSi = type <{ i[[PTRSIZE:[0-9]+]] }> @@ -13,7 +12,7 @@ func test(_ x : A) { } // CHECK: define hidden {{.*}}void @"$s7structs4test{{[_0-9a-zA-Z]*}}F" // CHECK: [[X_DBG:%.*]] = alloca -// CHECK: call void @llvm.dbg.declare(metadata {{.*}}* [[X_DBG]], metadata [[X_MD:!.*]], metadata +// CHECK: call void @llvm.dbg.declare(metadata ptr [[X_DBG]], metadata [[X_MD:!.*]], metadata // A class is represented by a pointer, so B's total size should be PTRSIZE. // CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "B",{{.*}}size: [[PTRSIZE]] diff --git a/test/DebugInfo/typearg.swift b/test/DebugInfo/typearg.swift index 4e471cb51ffbd..1d9e640049dc6 100644 --- a/test/DebugInfo/typearg.swift +++ b/test/DebugInfo/typearg.swift @@ -1,5 +1,4 @@ -// RUN: %target-swift-frontend %use_no_opaque_pointers %s -emit-ir -g -o - | %FileCheck %s -// RUN: %target-swift-frontend %s -emit-ir -g -o - +// RUN: %target-swift-frontend %s -emit-ir -g -o - | %FileCheck %s protocol AProtocol { func f() -> String @@ -9,7 +8,7 @@ class AClass : AProtocol { } // CHECK: define hidden {{.*}}void @{{.*}}aFunction -// CHECK: call void @llvm.dbg.declare(metadata %swift.type** %{{.*}}, metadata ![[TYPEARG:.*]], metadata !DIExpression()), +// CHECK: call void @llvm.dbg.declare(metadata ptr %{{.*}}, metadata ![[TYPEARG:.*]], metadata !DIExpression()), // CHECK: ![[TYPEARG]] = !DILocalVariable(name: "$\CF\84_0_0" // CHECK-SAME: type: ![[SWIFTMETATYPE:[^,)]+]] // CHECK-SAME: flags: DIFlagArtificial diff --git a/test/DebugInfo/uninitialized.swift b/test/DebugInfo/uninitialized.swift index 55e828153f7b0..3664dfbb4bcfd 100644 --- a/test/DebugInfo/uninitialized.swift +++ b/test/DebugInfo/uninitialized.swift @@ -1,17 +1,14 @@ -// RUN: %target-swift-frontend %use_no_opaque_pointers %s -c -emit-ir -g -o - | %FileCheck %s -// RUN: %target-swift-frontend %s -c -emit-ir -g -o - -// RUN: %target-swift-frontend %use_no_opaque_pointers %s -O -c -emit-ir -g -o - | %FileCheck %s --check-prefix=OPT -// RUN: %target-swift-frontend %s -O -c -emit-ir -g -o - +// RUN: %target-swift-frontend %s -c -emit-ir -g -o - | %FileCheck %s +// RUN: %target-swift-frontend %s -O -c -emit-ir -g -o - | %FileCheck %s --check-prefix=OPT class MyClass {} // CHECK-LABEL: define {{.*}} @"$s13uninitialized1fyyF" // OPT-LABEL: define {{.*}} @"$s13uninitialized1fyyF" public func f() { var object: MyClass - // CHECK: %[[OBJ:.*]] = alloca %[[T1:.*]]*, align - // CHECK: call void @llvm.dbg.declare(metadata %[[T1]]** %[[OBJ]], - // CHECK: %[[BC1:.*]] = bitcast %[[T1]]** %[[OBJ]] to i8*{{$}} - // CHECK: void @llvm.memset.{{.*}}(i8* align {{(4|8)}} %[[BC1]], i8 0, + // CHECK: %[[OBJ:.*]] = alloca ptr, align + // CHECK: call void @llvm.dbg.declare(metadata ptr %[[OBJ]], + // CHECK: void @llvm.memset.{{.*}}(ptr align {{(4|8)}} %[[OBJ]], i8 0, // CHECK-SAME: ){{$}} // OPT-NOT: @llvm.memset // OPT: ret @@ -21,10 +18,9 @@ public func f() { // OPT-LABEL: define {{.*}} @"$s13uninitialized1gyyF" public func g() { var dict: Dictionary - // CHECK: %[[DICT:.*]] = alloca %[[T2:.*]], align - // CHECK: call void @llvm.dbg.declare(metadata %[[T2]]* %[[DICT]], - // CHECK: %[[BC2:.*]] = bitcast %[[T2]]* %[[DICT]] to i8* - // CHECK: void @llvm.memset.{{.*}}(i8* align {{(4|8)}} %[[BC2]], i8 0, + // CHECK: %[[DICT:.*]] = alloca + // CHECK: call void @llvm.dbg.declare(metadata ptr %[[DICT]], + // CHECK: void @llvm.memset.{{.*}}(ptr align {{(4|8)}} %[[DICT]], i8 0, // CHECK-SAME: ){{$}} // OPT-NOT: @llvm.memset // OPT: ret diff --git a/test/DebugInfo/variadic-generics-count.swift b/test/DebugInfo/variadic-generics-count.swift index 0f4cb79db204b..45cddba6b6410 100644 --- a/test/DebugInfo/variadic-generics-count.swift +++ b/test/DebugInfo/variadic-generics-count.swift @@ -1,34 +1,32 @@ -// RUN: %target-swift-frontend %use_no_opaque_pointers -emit-ir %s -g -o - \ -// RUN: -parse-as-library -module-name a -disable-availability-checking | %FileCheck %s // RUN: %target-swift-frontend -emit-ir %s -g -o - \ -// RUN: -parse-as-library -module-name a -disable-availability-checking +// RUN: -parse-as-library -module-name a -disable-availability-checking | %FileCheck %s public func f1(ts: repeat each T) { - // CHECK: define {{.*}} @"$s1a2f12tsyxxQp_tRvzlF"(%swift.opaque** {{.*}}, i{{32|64}} [[COUNT1_1:.*]], %swift.type** {{.*}}) - // CHECK-DAG: store i{{32|64}} [[COUNT1_1]], i{{32|64}}* %[[COUNT1_1_A:.*]], align + // CHECK: define {{.*}} @"$s1a2f12tsyxxQp_tRvzlF"(ptr {{.*}}, i{{32|64}} [[COUNT1_1:.*]], ptr {{.*}}) + // CHECK-DAG: store i{{32|64}} [[COUNT1_1]], ptr %[[COUNT1_1_A:.*]], align // CHECK-DAG: call void @llvm.dbg.declare({{.*}}[[COUNT1_1_A]], metadata ![[COUNT1_1_VAR:[0-9]+]], metadata !DIExpression()) // CHECK-LABEL: ret void } public func f2(us: repeat each U, vs: repeat each V) { - // CHECK: define {{.*}} @"$s1a2f22us2vsyxxQp_q_q_QptRvzRv_r0_lF"(%swift.opaque** {{.*}}, %swift.opaque** {{.*}}, i{{32|64}} [[COUNT2_1:.*]], i{{32|64}} [[COUNT2_2:.*]], %swift.type** {{.*}}, %swift.type** {{.*}}) - // CHECK-DAG: store i{{32|64}} [[COUNT2_1]], i{{32|64}}* %[[COUNT2_1_A:.*]], align - // CHECK-DAG: store i{{32|64}} [[COUNT2_2]], i{{32|64}}* %[[COUNT2_2_A:.*]], align + // CHECK: define {{.*}} @"$s1a2f22us2vsyxxQp_q_q_QptRvzRv_r0_lF"(ptr {{.*}}, ptr {{.*}}, i{{32|64}} [[COUNT2_1:.*]], i{{32|64}} [[COUNT2_2:.*]], ptr {{.*}}, ptr {{.*}}) + // CHECK-DAG: store i{{32|64}} [[COUNT2_1]], ptr %[[COUNT2_1_A:.*]], align + // CHECK-DAG: store i{{32|64}} [[COUNT2_2]], ptr %[[COUNT2_2_A:.*]], align // CHECK-DAG: call void @llvm.dbg.declare({{.*}}[[COUNT2_1_A]], metadata ![[COUNT2_1_VAR:[0-9]+]], metadata !DIExpression()) // CHECK-DAG: call void @llvm.dbg.declare({{.*}}[[COUNT2_2_A]], metadata ![[COUNT2_2_VAR:[0-9]+]], metadata !DIExpression()) // CHECK-LABEL: ret void } public func f3(ts: repeat each T, more_ts: repeat each T) { - // CHECK: define {{.*}} @"$s1a2f32ts05more_B0yxxQp_xxQptRvzlF"(%swift.opaque** {{.*}}, %swift.opaque** {{.*}}, i{{32|64}} [[COUNT3_1:.*]], %swift.type** {{.*}}) - // CHECK-DAG: store i{{32|64}} [[COUNT3_1]], i{{32|64}}* %[[COUNT3_1_A:.*]], align + // CHECK: define {{.*}} @"$s1a2f32ts05more_B0yxxQp_xxQptRvzlF"(ptr {{.*}}, ptr {{.*}}, i{{32|64}} [[COUNT3_1:.*]], ptr {{.*}}) + // CHECK-DAG: store i{{32|64}} [[COUNT3_1]], ptr %[[COUNT3_1_A:.*]], align // CHECK-DAG: call void @llvm.dbg.declare({{.*}}[[COUNT3_1_A]], metadata ![[COUNT3_1_VAR:[0-9]+]], metadata !DIExpression()) // CHECK-LABEL: ret void } public func f4(us: repeat (each U, each V)) { - // CHECK: define {{.*}} @"$s1a2f42usyx_q_txQp_tRvzRv_q_Rhzr0_lF"(%swift.opaque** {{.*}}, i{{32|64}} [[COUNT4_1:.*]], %swift.type** {{.*}}, %swift.type** {{.*}}) - // CHECK-DAG: store i{{32|64}} [[COUNT4_1]], i{{32|64}}* %[[COUNT4_1_A:.*]], align + // CHECK: define {{.*}} @"$s1a2f42usyx_q_txQp_tRvzRv_q_Rhzr0_lF"(ptr {{.*}}, i{{32|64}} [[COUNT4_1:.*]], ptr {{.*}}, ptr {{.*}}) + // CHECK-DAG: store i{{32|64}} [[COUNT4_1]], ptr %[[COUNT4_1_A:.*]], align // CHECK-DAG: call void @llvm.dbg.declare({{.*}}[[COUNT4_1_A]], metadata ![[COUNT4_1_VAR:[0-9]+]], metadata !DIExpression()) // CHECK-LABEL: ret void } @@ -37,13 +35,13 @@ public struct S { let vals: (repeat each T) public func f5() { - // CHECK: define {{.*}} @"$s1a1SV2f5yyF"(%swift.type* {{.*}}, %T1a1SV* {{.*}} %0) + // CHECK: define {{.*}} @"$s1a1SV2f5yyF"(ptr {{.*}}, ptr {{.*}} %0) } } public func f6(s: S) { - // CHECK: define {{.*}} @"$s1a2f61syAA1SVyxxQp_QPG_tRvzlF"(%T1a1SV* {{.*}}, i{{32|64}} [[COUNT6_1:.*]], %swift.type** {{.*}}) - // CHECK-DAG: store i{{32|64}} [[COUNT6_1]], i{{32|64}}* %[[COUNT6_1_A:.*]], align + // CHECK: define {{.*}} @"$s1a2f61syAA1SVyxxQp_QPG_tRvzlF"(ptr {{.*}}, i{{32|64}} [[COUNT6_1:.*]], ptr {{.*}}) + // CHECK-DAG: store i{{32|64}} [[COUNT6_1]], ptr %[[COUNT6_1_A:.*]], align // CHECK-DAG: call void @llvm.dbg.declare({{.*}}[[COUNT6_1_A]], metadata ![[COUNT6_1_VAR:[0-9]+]], metadata !DIExpression()) } diff --git a/test/DebugInfo/variadic-generics.swift b/test/DebugInfo/variadic-generics.swift index ba4b3c3325e36..041537ae70d1e 100644 --- a/test/DebugInfo/variadic-generics.swift +++ b/test/DebugInfo/variadic-generics.swift @@ -1,21 +1,20 @@ -// RUN: %target-swift-frontend %use_no_opaque_pointers -emit-ir %s -g -o - \ -// RUN: -parse-as-library -module-name a | %IRGenFileCheck %s // RUN: %target-swift-frontend -emit-ir %s -g -o - \ -// RUN: -parse-as-library -module-name a +// RUN: -parse-as-library -module-name a | %IRGenFileCheck %s public func foo(args: repeat each T) { // CHECK: define {{.*}} @"$s1a3foo4argsyxxQp_tRvzlF" - // CHECK-SAME: %swift.type** %[[TYPE_PACK_ARG:.*]]) - // CHECK: %[[TYPE_PACK_ALLOCA:.*]] = alloca %swift.type** - // CHECK: call void @llvm.dbg.declare(metadata %swift.type*** %[[TYPE_PACK_ALLOCA]], metadata ![[TYPE_PACK_VAR:[0-9]+]], metadata !DIExpression()) - // CHECK: %[[ARGS_ALLOCA:.*]] = alloca %swift.opaque** - // CHECK-DAG: call void @llvm.dbg.declare(metadata %swift.opaque*** %[[ARGS_ALLOCA]], metadata ![[ARGS_VAR:[0-9]+]], metadata !DIExpression(DW_OP_deref)) - // CHECK-DAG: %[[TYPE_PACK_ARG_INT:[^,]+]] = ptrtoint %swift.type** %[[TYPE_PACK_ARG]] to [[INT]] + // CHECK-SAME: ptr {{.*}} %[[ARG_0:.*]], i64 %{{.*}}, + // CHECK-SAME: ptr %[[TYPE_PACK_ARG:.*]]) + // CHECK: %[[TYPE_PACK_ALLOCA:.*]] = alloca ptr + // CHECK: call void @llvm.dbg.declare(metadata ptr %[[TYPE_PACK_ALLOCA]], metadata ![[TYPE_PACK_VAR:[0-9]+]], metadata !DIExpression()) + // CHECK: %[[ARGS_ALLOCA:.*]] = alloca ptr + // CHECK-DAG: call void @llvm.dbg.declare(metadata ptr %[[ARGS_ALLOCA]], metadata ![[ARGS_VAR:[0-9]+]], metadata !DIExpression(DW_OP_deref)) + // CHECK-DAG: %[[TYPE_PACK_ARG_INT:[^,]+]] = ptrtoint ptr %[[TYPE_PACK_ARG]] to [[INT]] // CHECK-DAG: %[[TYPE_PACK_ARG_MASKED_INT:[^,]+]] = and [[INT]] %[[TYPE_PACK_ARG_INT]], -2 - // CHECK-DAG: %[[TYPE_PACK_ARG_MASKED:[^,]+]] = inttoptr [[INT]] %[[TYPE_PACK_ARG_MASKED_INT]] to %swift.type** - // CHECK-DAG: store %swift.type** %[[TYPE_PACK_ARG_MASKED]], %swift.type*** %[[TYPE_PACK_ALLOCA]] - // CHECK-DAG: store %swift.opaque** %0, %swift.opaque*** %[[ARGS_ALLOCA]] - // CHECK-DAG: ![[ARGS_VAR]] = !DILocalVariable(name: "args", arg: 1, {{.*}}line: [[@LINE-12]], type: ![[ARGS_LET_TY:[0-9]+]]) + // CHECK-DAG: %[[TYPE_PACK_ARG_MASKED:[^,]+]] = inttoptr [[INT]] %[[TYPE_PACK_ARG_MASKED_INT]] to ptr + // CHECK-DAG: store ptr %[[TYPE_PACK_ARG_MASKED]], ptr %[[TYPE_PACK_ALLOCA]] + // CHECK-DAG: store ptr %[[ARG_0]], ptr %[[ARGS_ALLOCA]] + // CHECK-DAG: ![[ARGS_VAR]] = !DILocalVariable(name: "args", arg: 1, {{.*}}line: [[@LINE-13]], type: ![[ARGS_LET_TY:[0-9]+]]) // CHECK-DAG: ![[ARGS_LET_TY]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: ![[ARGS_TY:[0-9]+]]) // CHECK-DAG: ![[ARGS_TY]] = !DICompositeType({{.*}}identifier: "$sxxQp_QSiD") // CHECK-DAG: ![[TYPE_PACK_VAR]] = !DILocalVariable(name: "$\CF\84_0_0", {{.*}}type: ![[TYPE_PACK_TYD:[0-9]+]], flags: DIFlagArtificial) diff --git a/test/DebugInfo/weak-self-capture.swift b/test/DebugInfo/weak-self-capture.swift index 6c5235eb5b875..676a1482e3a6f 100644 --- a/test/DebugInfo/weak-self-capture.swift +++ b/test/DebugInfo/weak-self-capture.swift @@ -1,5 +1,4 @@ -// RUN: %target-swift-frontend %use_no_opaque_pointers %s -emit-ir -g -o - | %FileCheck %s -// RUN: %target-swift-frontend %s -emit-ir -g -o - +// RUN: %target-swift-frontend %s -emit-ir -g -o - | %FileCheck %s public class ClosureMaker { var a : Int @@ -17,4 +16,4 @@ public class ClosureMaker { } // CHECK: define {{.*}} @"$s4main12ClosureMakerC03getB0SiycyFSiycfU_" -// CHECK: call void @llvm.dbg.declare(metadata %swift.weak** %{{.*}} !DIExpression(DW_OP_deref)), +// CHECK: call void @llvm.dbg.declare(metadata ptr %{{.*}} !DIExpression(DW_OP_deref)), From 5d7aa848905e05b1b9567fb22aecb0ae0c48bc45 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Fri, 16 Jun 2023 13:17:20 -0700 Subject: [PATCH 27/41] [SILOpt] Don't opt move-only lifetimes. According to language rules, such lifetimes are fixed and the relative order of their deinits is guaranteed. rdar://110913116 --- .../Transforms/DestroyAddrHoisting.cpp | 5 ++ .../Utils/CanonicalizeOSSALifetime.cpp | 6 +++ .../canonicalize_ossa_lifetime_unit.sil | 46 +++++++++++++++++++ test/SILOptimizer/hoist_destroy_addr.sil | 34 ++++++++++++++ 4 files changed, 91 insertions(+) diff --git a/lib/SILOptimizer/Transforms/DestroyAddrHoisting.cpp b/lib/SILOptimizer/Transforms/DestroyAddrHoisting.cpp index 4feb70403f429..94598b56c84aa 100644 --- a/lib/SILOptimizer/Transforms/DestroyAddrHoisting.cpp +++ b/lib/SILOptimizer/Transforms/DestroyAddrHoisting.cpp @@ -870,6 +870,11 @@ bool hoistDestroys(SILValue root, bool ignoreDeinitBarriers, BasicCalleeAnalysis *calleeAnalysis) { LLVM_DEBUG(llvm::dbgs() << "Performing destroy hoisting on " << root); + // Don't canonicalize the lifetimes of addresses of move-only type. + // According to language rules, they are fixed. + if (root->getType().isMoveOnly()) + return false; + SILFunction *function = root->getFunction(); if (!function) return false; diff --git a/lib/SILOptimizer/Utils/CanonicalizeOSSALifetime.cpp b/lib/SILOptimizer/Utils/CanonicalizeOSSALifetime.cpp index f9fda092cbea2..85d0a7e33e8e2 100644 --- a/lib/SILOptimizer/Utils/CanonicalizeOSSALifetime.cpp +++ b/lib/SILOptimizer/Utils/CanonicalizeOSSALifetime.cpp @@ -1156,6 +1156,12 @@ void CanonicalizeOSSALifetime::rewriteLifetimes() { bool CanonicalizeOSSALifetime::canonicalizeValueLifetime(SILValue def) { LivenessState livenessState(*this, def); + // Don't canonicalize the lifetimes of values of move-only type. According to + // language rules, they are fixed. + if (def->getType().isMoveOnly()) { + return false; + } + // Step 1: Compute liveness. if (!computeLiveness()) { LLVM_DEBUG(llvm::dbgs() << "Failed to compute liveness boundary!\n"); diff --git a/test/SILOptimizer/canonicalize_ossa_lifetime_unit.sil b/test/SILOptimizer/canonicalize_ossa_lifetime_unit.sil index 2f36344f108d6..7d2f7425b1f25 100644 --- a/test/SILOptimizer/canonicalize_ossa_lifetime_unit.sil +++ b/test/SILOptimizer/canonicalize_ossa_lifetime_unit.sil @@ -5,6 +5,9 @@ sil @getOwned : $@convention(thin) () -> @owned C sil @barrier : $@convention(thin) () -> () struct S {} +@_moveOnly struct MoS {} +@_moveOnly struct MoE {} + // When access scopes are respected, the lifetime which previously extended // beyond the access scope still extends beyond it. // CHECK-LABEL: begin running test 1 of 2 on retract_value_lifetime_into_access_scope_when_access_scopes_not_respected: canonicalize-ossa-lifetime with: true, false, true, @trace @@ -134,3 +137,46 @@ exit(%phi : @owned $C, %typhi : $S): %retval = tuple () return %retval : $() } + +sil @empty : $@convention(thin) () -> () { +[global: ] +bb0: + %0 = tuple () + return %0 : $() +} + +// Even though the apply of %empty is not a deinit barrier, verify that the +// destroy is not hoisted, because MoS is move-only. +// CHECK-LABEL: begin running test {{.*}} on dont_move_destroy_value_of_moveonly_struct: canonicalize-ossa-lifetime with: true, false, true, @argument +// CHECK-LABEL: sil [ossa] @dont_move_destroy_value_of_moveonly_struct : {{.*}} { +// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : +// CHECK: apply +// CHECK: destroy_value [[INSTANCE]] +// CHECK-LABEL: } // end sil function 'dont_move_destroy_value_of_moveonly_struct' +// CHECK-LABEL: end running test {{.*}} on dont_move_destroy_value_of_moveonly_struct: canonicalize-ossa-lifetime with: true, false, true, @argument +sil [ossa] @dont_move_destroy_value_of_moveonly_struct : $@convention(thin) (@owned MoS) -> () { +entry(%instance : @owned $MoS): + test_specification "canonicalize-ossa-lifetime true false true @argument" + %empty = function_ref @empty : $@convention(thin) () -> () + apply %empty() : $@convention(thin) () -> () + destroy_value %instance : $MoS + %retval = tuple () + return %retval : $() +} + +// CHECK-LABEL: begin running test {{.*}} on dont_move_destroy_value_of_moveonly_enum: canonicalize-ossa-lifetime with: true, false, true, @argument +// CHECK-LABEL: sil [ossa] @dont_move_destroy_value_of_moveonly_enum : {{.*}} { +// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : +// CHECK: apply +// CHECK: destroy_value [[INSTANCE]] +// CHECK-LABEL: } // end sil function 'dont_move_destroy_value_of_moveonly_enum' +// CHECK-LABEL: end running test {{.*}} on dont_move_destroy_value_of_moveonly_enum: canonicalize-ossa-lifetime with: true, false, true, @argument +sil [ossa] @dont_move_destroy_value_of_moveonly_enum : $@convention(thin) (@owned MoE) -> () { +entry(%instance : @owned $MoE): + test_specification "canonicalize-ossa-lifetime true false true @argument" + %empty = function_ref @empty : $@convention(thin) () -> () + apply %empty() : $@convention(thin) () -> () + destroy_value %instance : $MoE + %retval = tuple () + return %retval : $() +} diff --git a/test/SILOptimizer/hoist_destroy_addr.sil b/test/SILOptimizer/hoist_destroy_addr.sil index 71e7099d13d33..837203379b38a 100644 --- a/test/SILOptimizer/hoist_destroy_addr.sil +++ b/test/SILOptimizer/hoist_destroy_addr.sil @@ -79,6 +79,9 @@ struct STXXITXXII { var i: I } +@_moveOnly struct MoS {} +@_moveOnly struct MoE {} + sil @unknown : $@convention(thin) () -> () sil @use_S : $@convention(thin) (@in_guaranteed S) -> () @@ -1145,3 +1148,34 @@ entry(%addr : $*X): %retval = tuple () return %retval : $() } + +// Even though the apply of %empty is not a deinit barrier (c.f. +// hoist_over_apply_of_non_barrier_fn), verify that the destroy_addr is not +// hoisted, because MoS is move-only. +// CHECK-LABEL: sil [ossa] @dont_move_destroy_addr_of_moveonly_struct : {{.*}} { +// CHECK: {{bb[0-9]+}}([[ADDR:%[^,]+]] : +// CHECK: apply +// CHECK: destroy_addr [[ADDR]] +// CHECK-LABEL: } // end sil function 'dont_move_destroy_addr_of_moveonly_struct' +sil [ossa] @dont_move_destroy_addr_of_moveonly_struct : $@convention(thin) (@in MoS) -> () { +entry(%addr : $*MoS): + %empty = function_ref @empty : $@convention(thin) () -> () + apply %empty() : $@convention(thin) () -> () + destroy_addr %addr : $*MoS + %retval = tuple () + return %retval : $() +} + +// CHECK-LABEL: sil [ossa] @dont_move_destroy_addr_of_moveonly_enum : {{.*}} { +// CHECK: {{bb[0-9]+}}([[ADDR:%[^,]+]] : +// CHECK: apply +// CHECK: destroy_addr [[ADDR]] +// CHECK-LABEL: } // end sil function 'dont_move_destroy_addr_of_moveonly_enum' +sil [ossa] @dont_move_destroy_addr_of_moveonly_enum : $@convention(thin) (@in MoE) -> () { +entry(%addr : $*MoE): + %empty = function_ref @empty : $@convention(thin) () -> () + apply %empty() : $@convention(thin) () -> () + destroy_addr %addr : $*MoE + %retval = tuple () + return %retval : $() +} From 8db8451c7154c827280cb7a46867d04752106d9f Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Fri, 16 Jun 2023 13:17:20 -0700 Subject: [PATCH 28/41] [SILOpt] Don't opt move-only lifetimes. According to language rules, such lifetimes are fixed and the relative order of their deinits is guaranteed. rdar://110913116 --- .../Transforms/DestroyAddrHoisting.cpp | 5 ++ .../Utils/CanonicalizeOSSALifetime.cpp | 6 +++ .../canonicalize_ossa_lifetime_unit.sil | 46 +++++++++++++++++++ test/SILOptimizer/hoist_destroy_addr.sil | 34 ++++++++++++++ 4 files changed, 91 insertions(+) diff --git a/lib/SILOptimizer/Transforms/DestroyAddrHoisting.cpp b/lib/SILOptimizer/Transforms/DestroyAddrHoisting.cpp index 4feb70403f429..94598b56c84aa 100644 --- a/lib/SILOptimizer/Transforms/DestroyAddrHoisting.cpp +++ b/lib/SILOptimizer/Transforms/DestroyAddrHoisting.cpp @@ -870,6 +870,11 @@ bool hoistDestroys(SILValue root, bool ignoreDeinitBarriers, BasicCalleeAnalysis *calleeAnalysis) { LLVM_DEBUG(llvm::dbgs() << "Performing destroy hoisting on " << root); + // Don't canonicalize the lifetimes of addresses of move-only type. + // According to language rules, they are fixed. + if (root->getType().isMoveOnly()) + return false; + SILFunction *function = root->getFunction(); if (!function) return false; diff --git a/lib/SILOptimizer/Utils/CanonicalizeOSSALifetime.cpp b/lib/SILOptimizer/Utils/CanonicalizeOSSALifetime.cpp index f9fda092cbea2..85d0a7e33e8e2 100644 --- a/lib/SILOptimizer/Utils/CanonicalizeOSSALifetime.cpp +++ b/lib/SILOptimizer/Utils/CanonicalizeOSSALifetime.cpp @@ -1156,6 +1156,12 @@ void CanonicalizeOSSALifetime::rewriteLifetimes() { bool CanonicalizeOSSALifetime::canonicalizeValueLifetime(SILValue def) { LivenessState livenessState(*this, def); + // Don't canonicalize the lifetimes of values of move-only type. According to + // language rules, they are fixed. + if (def->getType().isMoveOnly()) { + return false; + } + // Step 1: Compute liveness. if (!computeLiveness()) { LLVM_DEBUG(llvm::dbgs() << "Failed to compute liveness boundary!\n"); diff --git a/test/SILOptimizer/canonicalize_ossa_lifetime_unit.sil b/test/SILOptimizer/canonicalize_ossa_lifetime_unit.sil index 2f36344f108d6..7d2f7425b1f25 100644 --- a/test/SILOptimizer/canonicalize_ossa_lifetime_unit.sil +++ b/test/SILOptimizer/canonicalize_ossa_lifetime_unit.sil @@ -5,6 +5,9 @@ sil @getOwned : $@convention(thin) () -> @owned C sil @barrier : $@convention(thin) () -> () struct S {} +@_moveOnly struct MoS {} +@_moveOnly struct MoE {} + // When access scopes are respected, the lifetime which previously extended // beyond the access scope still extends beyond it. // CHECK-LABEL: begin running test 1 of 2 on retract_value_lifetime_into_access_scope_when_access_scopes_not_respected: canonicalize-ossa-lifetime with: true, false, true, @trace @@ -134,3 +137,46 @@ exit(%phi : @owned $C, %typhi : $S): %retval = tuple () return %retval : $() } + +sil @empty : $@convention(thin) () -> () { +[global: ] +bb0: + %0 = tuple () + return %0 : $() +} + +// Even though the apply of %empty is not a deinit barrier, verify that the +// destroy is not hoisted, because MoS is move-only. +// CHECK-LABEL: begin running test {{.*}} on dont_move_destroy_value_of_moveonly_struct: canonicalize-ossa-lifetime with: true, false, true, @argument +// CHECK-LABEL: sil [ossa] @dont_move_destroy_value_of_moveonly_struct : {{.*}} { +// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : +// CHECK: apply +// CHECK: destroy_value [[INSTANCE]] +// CHECK-LABEL: } // end sil function 'dont_move_destroy_value_of_moveonly_struct' +// CHECK-LABEL: end running test {{.*}} on dont_move_destroy_value_of_moveonly_struct: canonicalize-ossa-lifetime with: true, false, true, @argument +sil [ossa] @dont_move_destroy_value_of_moveonly_struct : $@convention(thin) (@owned MoS) -> () { +entry(%instance : @owned $MoS): + test_specification "canonicalize-ossa-lifetime true false true @argument" + %empty = function_ref @empty : $@convention(thin) () -> () + apply %empty() : $@convention(thin) () -> () + destroy_value %instance : $MoS + %retval = tuple () + return %retval : $() +} + +// CHECK-LABEL: begin running test {{.*}} on dont_move_destroy_value_of_moveonly_enum: canonicalize-ossa-lifetime with: true, false, true, @argument +// CHECK-LABEL: sil [ossa] @dont_move_destroy_value_of_moveonly_enum : {{.*}} { +// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : +// CHECK: apply +// CHECK: destroy_value [[INSTANCE]] +// CHECK-LABEL: } // end sil function 'dont_move_destroy_value_of_moveonly_enum' +// CHECK-LABEL: end running test {{.*}} on dont_move_destroy_value_of_moveonly_enum: canonicalize-ossa-lifetime with: true, false, true, @argument +sil [ossa] @dont_move_destroy_value_of_moveonly_enum : $@convention(thin) (@owned MoE) -> () { +entry(%instance : @owned $MoE): + test_specification "canonicalize-ossa-lifetime true false true @argument" + %empty = function_ref @empty : $@convention(thin) () -> () + apply %empty() : $@convention(thin) () -> () + destroy_value %instance : $MoE + %retval = tuple () + return %retval : $() +} diff --git a/test/SILOptimizer/hoist_destroy_addr.sil b/test/SILOptimizer/hoist_destroy_addr.sil index 71e7099d13d33..837203379b38a 100644 --- a/test/SILOptimizer/hoist_destroy_addr.sil +++ b/test/SILOptimizer/hoist_destroy_addr.sil @@ -79,6 +79,9 @@ struct STXXITXXII { var i: I } +@_moveOnly struct MoS {} +@_moveOnly struct MoE {} + sil @unknown : $@convention(thin) () -> () sil @use_S : $@convention(thin) (@in_guaranteed S) -> () @@ -1145,3 +1148,34 @@ entry(%addr : $*X): %retval = tuple () return %retval : $() } + +// Even though the apply of %empty is not a deinit barrier (c.f. +// hoist_over_apply_of_non_barrier_fn), verify that the destroy_addr is not +// hoisted, because MoS is move-only. +// CHECK-LABEL: sil [ossa] @dont_move_destroy_addr_of_moveonly_struct : {{.*}} { +// CHECK: {{bb[0-9]+}}([[ADDR:%[^,]+]] : +// CHECK: apply +// CHECK: destroy_addr [[ADDR]] +// CHECK-LABEL: } // end sil function 'dont_move_destroy_addr_of_moveonly_struct' +sil [ossa] @dont_move_destroy_addr_of_moveonly_struct : $@convention(thin) (@in MoS) -> () { +entry(%addr : $*MoS): + %empty = function_ref @empty : $@convention(thin) () -> () + apply %empty() : $@convention(thin) () -> () + destroy_addr %addr : $*MoS + %retval = tuple () + return %retval : $() +} + +// CHECK-LABEL: sil [ossa] @dont_move_destroy_addr_of_moveonly_enum : {{.*}} { +// CHECK: {{bb[0-9]+}}([[ADDR:%[^,]+]] : +// CHECK: apply +// CHECK: destroy_addr [[ADDR]] +// CHECK-LABEL: } // end sil function 'dont_move_destroy_addr_of_moveonly_enum' +sil [ossa] @dont_move_destroy_addr_of_moveonly_enum : $@convention(thin) (@in MoE) -> () { +entry(%addr : $*MoE): + %empty = function_ref @empty : $@convention(thin) () -> () + apply %empty() : $@convention(thin) () -> () + destroy_addr %addr : $*MoE + %retval = tuple () + return %retval : $() +} From 329e42849a3a1acbcfc5ad355f0f3d0961e1387c Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Fri, 16 Jun 2023 12:36:10 -0700 Subject: [PATCH 29/41] Compute VarDeclScopeMap up front. The previous lazy discovery did not always work because sometimes a debug_value is emitted before the first SIL instruction in the variable's scope. rdar://110841130 --- lib/SILGen/SILGenFunction.cpp | 71 +++++++++++-------- test/DebugInfo/case-scope2.swift | 4 +- test/DebugInfo/case-scope3.swift | 4 +- test/DebugInfo/for-scope.swift | 2 +- test/DebugInfo/guard-let-scope.swift | 4 +- test/DebugInfo/guard-let-scope2.swift | 11 +-- test/DebugInfo/guard-let-scope3.swift | 9 ++- test/DebugInfo/guard-let-scope4.swift | 18 +++++ test/DebugInfo/if-let-scope.swift | 7 +- .../switch-case-debug-descriptions.swift | 4 +- 10 files changed, 83 insertions(+), 51 deletions(-) create mode 100644 test/DebugInfo/guard-let-scope4.swift diff --git a/lib/SILGen/SILGenFunction.cpp b/lib/SILGen/SILGenFunction.cpp index 90d3014bd6109..33fc549d59017 100644 --- a/lib/SILGen/SILGenFunction.cpp +++ b/lib/SILGen/SILGenFunction.cpp @@ -55,10 +55,51 @@ SILGenFunction::SILGenFunction(SILGenModule &SGM, SILFunction &F, assert(DC && "creating SGF without a DeclContext?"); B.setInsertionPoint(createBasicBlock()); B.setCurrentDebugScope(F.getDebugScope()); + + // Populate VarDeclScopeMap. SourceLoc SLoc = F.getLocation().getSourceLoc(); if (SF && SLoc) { FnASTScope = ast_scope::ASTScopeImpl::findStartingScopeForLookup(SF, SLoc); ScopeMap.insert({{FnASTScope, nullptr}, F.getDebugScope()}); + + // Collect all variable declarations in this scope. + struct Consumer : public namelookup::AbstractASTScopeDeclConsumer { + const ast_scope::ASTScopeImpl *ASTScope; + VarDeclScopeMapTy &VarDeclScopeMap; + Consumer(const ast_scope::ASTScopeImpl *ASTScope, + VarDeclScopeMapTy &VarDeclScopeMap) + : ASTScope(ASTScope), VarDeclScopeMap(VarDeclScopeMap) {} + + bool consume(ArrayRef values, + NullablePtr baseDC) override { + LLVM_DEBUG(ASTScope->print(llvm::errs(), 0, false, false)); + for (auto &value : values) { + LLVM_DEBUG({ + if (value->hasName()) + llvm::dbgs() << "+ " << value->getBaseIdentifier() << "\n"; + }); + + assert((VarDeclScopeMap.count(value) == 0 || + VarDeclScopeMap[value] == ASTScope) && + "VarDecl appears twice"); + VarDeclScopeMap.insert({value, ASTScope}); + } + return false; + } + bool lookInMembers(const DeclContext *) const override { return false; } +#ifndef NDEBUG + void startingNextLookupStep() override {} + void finishingLookup(std::string) const override {} + bool isTargetLookup() const override { return false; } +#endif + }; + const_cast(FnASTScope) + ->preOrderChildrenDo([&](ast_scope::ASTScopeImpl *ASTScope) { + if (!ASTScope->ignoreInDebugInfo()) { + Consumer consumer(ASTScope, VarDeclScopeMap); + ASTScope->lookupLocalsOrMembers(consumer); + } + }); } } @@ -202,8 +243,6 @@ const SILDebugScope *SILGenFunction::getScopeOrNull(SILLocation Loc, SourceLoc SLoc = Loc.getSourceLoc(); if (!SF || LastSourceLoc == SLoc) return nullptr; - // Prime VarDeclScopeMap. - auto Scope = getOrCreateScope(SLoc); if (ForMetaInstruction) if (ValueDecl *ValDecl = Loc.getAsASTNode()) { // The source location of a VarDecl isn't necessarily in the same scope @@ -212,7 +251,7 @@ const SILDebugScope *SILGenFunction::getScopeOrNull(SILLocation Loc, if (ValueScope != VarDeclScopeMap.end()) return getOrCreateScope(ValueScope->second, F.getDebugScope()); } - return Scope; + return getOrCreateScope(SLoc); } const SILDebugScope *SILGenFunction::getOrCreateScope(SourceLoc SLoc) { @@ -406,32 +445,6 @@ SILGenFunction::getOrCreateScope(const ast_scope::ASTScopeImpl *ASTScope, return ParentScope->InlinedCallSite != InlinedAt ? FnScope : ParentScope; } - // Collect all variable declarations in this scope. - struct Consumer : public namelookup::AbstractASTScopeDeclConsumer { - const ast_scope::ASTScopeImpl *ASTScope; - VarDeclScopeMapTy &VarDeclScopeMap; - Consumer(const ast_scope::ASTScopeImpl *ASTScope, - VarDeclScopeMapTy &VarDeclScopeMap) - : ASTScope(ASTScope), VarDeclScopeMap(VarDeclScopeMap) {} - - bool consume(ArrayRef values, - NullablePtr baseDC) override { - for (auto &value : values) { - assert(VarDeclScopeMap.count(value) == 0 && "VarDecl appears twice"); - VarDeclScopeMap.insert({value, ASTScope}); - } - return false; - } - bool lookInMembers(const DeclContext *) const override { return false; } -#ifndef NDEBUG - void startingNextLookupStep() override {} - void finishingLookup(std::string) const override {} - bool isTargetLookup() const override { return false; } -#endif - }; - Consumer consumer(ASTScope, VarDeclScopeMap); - ASTScope->lookupLocalsOrMembers(consumer); - // Collapse BraceStmtScopes whose parent is a .*BodyScope. if (auto Parent = ASTScope->getParent().getPtrOrNull()) if (Parent->getSourceRangeOfThisASTNode() == diff --git a/test/DebugInfo/case-scope2.swift b/test/DebugInfo/case-scope2.swift index 3ae29af43d817..ca96e9ad59245 100644 --- a/test/DebugInfo/case-scope2.swift +++ b/test/DebugInfo/case-scope2.swift @@ -9,10 +9,10 @@ func consume(_ t: T) {} public func f(_ s1: Set?, _ s2: Set?) { switch (s1, s2) { case (nil, let a), (let a, nil): - // CHECK: debug_value {{.*}} $Optional>, let, name "a", {{.*}}:[[@LINE-1]]:18, scope [[S1]] + // CHECK: debug_value {{.*}} $Optional>, let, name "a", {{.*}}:11:18, scope [[S2]] consume(a) case (let a?, _): - // CHECK: debug_value {{.*}} $Set, let, name "a", {{.*}}:[[@LINE-1]]:13, scope [[S3]] + // CHECK: debug_value {{.*}} $Set, let, name "a", {{.*}}:14:13, scope [[S3]] consume((a)) } } diff --git a/test/DebugInfo/case-scope3.swift b/test/DebugInfo/case-scope3.swift index 0055f1089e3db..293e9ea3b0ce6 100644 --- a/test/DebugInfo/case-scope3.swift +++ b/test/DebugInfo/case-scope3.swift @@ -14,8 +14,8 @@ func f() -> Int { // CHECK: sil_scope [[S2:[0-9]+]] { loc "{{.*}}":10:44 parent [[S0]] } // CHECK: sil_scope [[S3:[0-9]+]] { loc "{{.*}}":10:68 parent [[S2]] } // CHECK: sil_scope [[S4:[0-9]+]] { loc "{{.*}}":10:78 parent [[S3]] } -// CHECK: debug_value {{.*}}: $Optional, let, name "nextValue", {{.*}}:10:31, scope [[S0]] -// CHECK: debug_value {{.*}}: $Int, let, name "nextValue", {{.*}}:10:56, scope [[S2]] +// CHECK: debug_value {{.*}}: $Optional, let, name "nextValue", {{.*}}:10:31, scope [[S2]] +// CHECK: debug_value {{.*}}: $Int, let, name "nextValue", {{.*}}:10:56, scope [[S3]] return nextValue } return 0 diff --git a/test/DebugInfo/for-scope.swift b/test/DebugInfo/for-scope.swift index 3b7c3997636f6..2ad423d3d9714 100644 --- a/test/DebugInfo/for-scope.swift +++ b/test/DebugInfo/for-scope.swift @@ -15,7 +15,7 @@ public func f(_ xs: [String?]) { // CHECK: sil_scope [[S5:[0-9]+]] { loc "{{.*}}":7:13 parent [[S4]] } // CHECK: sil_scope [[S6:[0-9]+]] { loc "{{.*}}":7:9 parent [[S4]] } -// CHECK: debug_value %[[X:.*]] : $Optional, let, name "x", {{.*}}, scope [[S3]] +// CHECK: debug_value %[[X:.*]] : $Optional, let, name "x", {{.*}}, scope [[S4]] // CHECK: retain_value %[[X]] : $Optional, {{.*}}, scope [[S5]] // CHECK: debug_value %[[X1:[0-9]+]] : $String, let, name "x", {{.*}}, scope [[S6]] // CHECK: release_value %[[X1]] : $String, {{.*}}, scope [[S6]] diff --git a/test/DebugInfo/guard-let-scope.swift b/test/DebugInfo/guard-let-scope.swift index 646568f4c56db..644d581c0a11c 100644 --- a/test/DebugInfo/guard-let-scope.swift +++ b/test/DebugInfo/guard-let-scope.swift @@ -14,8 +14,8 @@ func f(c: AnyObject??) { // CHECK: sil_scope [[S9:[0-9]+]] { loc "{{.*}}":7:28 parent [[S8]] } // CHECK: sil_scope [[S10:[0-9]+]] { loc "{{.*}}":7:28 parent [[S8]] } // CHECK: debug_value %{{.*}} : $Optional>, let, name "x"{{.*}} scope [[S5]] - // CHECK: debug_value %{{.*}} : $Optional, let, name "x", {{.*}} scope [[S6]] - // CHECK: debug_value %{{.*}} : $AnyObject, let, name "x", {{.*}} scope [[S8]] + // CHECK: debug_value %{{.*}} : $Optional, let, name "x", {{.*}} scope [[S8]] + // CHECK: debug_value %{{.*}} : $AnyObject, let, name "x", {{.*}} scope [[S10]] fatalError() } // CHECK: function_ref {{.*3use.*}} scope [[S10]] diff --git a/test/DebugInfo/guard-let-scope2.swift b/test/DebugInfo/guard-let-scope2.swift index ab85c650cf5c7..20c455df897ad 100644 --- a/test/DebugInfo/guard-let-scope2.swift +++ b/test/DebugInfo/guard-let-scope2.swift @@ -16,11 +16,12 @@ public func f(x: String?) throws { s = SomeObject() return s != nil } - // CHECK: sil_scope [[S1:[0-9]+]] { {{.*}} parent @{{.*}}1f - // CHECK: sil_scope [[S2:[0-9]+]] { {{.*}} parent [[S1]] } - // CHECK: sil_scope [[S3:[0-9]+]] { {{.*}} parent [[S1]] } - // CHECK: sil_scope [[S4:[0-9]+]] { {{.*}} parent [[S2]] } - // CHECK: alloc_stack {{.*}} $SomeObject, let, name "s", {{.*}} scope [[S4]] + // CHECK: sil_scope [[S1:[0-9]+]] { {{.*}}:13:13 parent @{{.*}}1f + // CHECK: sil_scope [[S2:[0-9]+]] { {{.*}}:14:7 parent [[S1]] } + // CHECK: sil_scope [[S3:[0-9]+]] { {{.*}}:14:26 parent [[S1]] } + // CHECK: sil_scope [[S4:[0-9]+]] { {{.*}}:25:3 parent [[S2]] } + // CHECK: sil_scope [[S5:[0-9]+]] { {{.*}}:25:17 parent [[S4]] } + // CHECK: alloc_stack {{.*}} $SomeObject, let, name "s", {{.*}} scope [[S5]] guard let s = s else { assert(false) return diff --git a/test/DebugInfo/guard-let-scope3.swift b/test/DebugInfo/guard-let-scope3.swift index d5af36b1d9898..d97db8f2f69a5 100644 --- a/test/DebugInfo/guard-let-scope3.swift +++ b/test/DebugInfo/guard-let-scope3.swift @@ -8,15 +8,14 @@ public class S { public func f(_ i: Int) throws -> C { guard let x = c[i], let x else { // CHECK: sil_scope [[P:[0-9]+]] { loc "{{.*}}":9:5 - // CHECK: sil_scope [[X1_:[0-9]+]] { loc "{{.*}}":9:19 parent [[P]] + // CHECK: sil_scope [[X1_RHS:[0-9]+]] { loc "{{.*}}":9:19 parent [[P]] // CHECK: sil_scope [[X1:[0-9]+]] { loc "{{.*}}":9:19 parent [[P]] // CHECK: sil_scope [[X2:[0-9]+]] { loc "{{.*}}":9:29 parent [[X1]] - // CHECK: sil_scope [[X2_:[0-9]+]] { loc "{{.*}}":9:29 parent [[X1]] // CHECK: sil_scope [[GUARD:[0-9]+]] { loc "{{.*}}":9:36 parent [[P]] - // CHECK: debug_value {{.*}} : $Optional, let, name "x", {{.*}}, scope [[P]] + // CHECK: debug_value {{.*}} : $Optional, let, name "x", {{.*}}, scope [[X1]] // CHECK: debug_value {{.*}} : $C, let, name "x", {{.*}}, scope [[X2]] - // FIXME: This source location & scope are a little wild. - // CHECK-NEXT: strong_retain{{.*}}:[[@LINE+4]]:12, scope [[X2_]] + // FIXME: This source location is a little wild. + // CHECK-NEXT: strong_retain{{.*}}:[[@LINE+4]]:12, scope [[X2]] throw MyError() // CHECK: function_ref {{.*}}MyError{{.*}}:[[@LINE-1]]:13, scope [[GUARD]] } diff --git a/test/DebugInfo/guard-let-scope4.swift b/test/DebugInfo/guard-let-scope4.swift new file mode 100644 index 0000000000000..ba84a006d7422 --- /dev/null +++ b/test/DebugInfo/guard-let-scope4.swift @@ -0,0 +1,18 @@ +// RUN: %target-swift-frontend -g -emit-sil %s -parse-as-library -module-name a | %FileCheck %s +open class C { + public func fun() {} + + public func run() { + { [weak self] in + guard let self else { fatalError("cannot happen") } + // CHECK: sil_scope [[LAMBDA:[0-9]+]] { loc "{{.*}}":6:5 + // CHECK: sil_scope [[BODY:[0-9]+]] { loc "{{.*}}":6:19 parent [[LAMBDA]] + // CHECK: sil_scope [[LET:[0-9]+]] { loc "{{.*}}":7:7 parent [[BODY]] + // CHECK: sil_scope [[GUARD:[0-9]+]] { loc "{{.*}}":7:17 parent [[LET]] + // CHECK: debug_value {{.*}} : $C, let, name "self", {{.*}}, scope [[GUARD]] + // CHECK: function_ref {{.*}}3fun{{.*}}, scope [[GUARD]] + // CHECK-NEXT: apply {{.*}}, scope [[GUARD]] + self.fun() + }() + } +} diff --git a/test/DebugInfo/if-let-scope.swift b/test/DebugInfo/if-let-scope.swift index 0672fc49e6b5e..74fd72a198eac 100644 --- a/test/DebugInfo/if-let-scope.swift +++ b/test/DebugInfo/if-let-scope.swift @@ -3,13 +3,14 @@ func use(_ t: T) {} public func f(value: String?) { // CHECK: sil_scope [[S0:[0-9]+]] { loc "{{.*}}":3:13 if let value, let value = Int(value) { - // CHECK: sil_scope [[S1:[0-9]+]] { loc "{{.*}}":5:10 + // CHECK: sil_scope [[S1:[0-9]+]] { loc "{{.*}}":5:3 // CHECK: sil_scope [[S2:[0-9]+]] { loc "{{.*}}":5:10 // CHECK: sil_scope [[S3:[0-9]+]] { loc "{{.*}}":5:29 parent [[S2]] } // CHECK: sil_scope [[S4:[0-9]+]] { loc "{{.*}}":5:29 parent [[S2]] } + // CHECK: sil_scope [[S5:[0-9]+]] { loc "{{.*}}":5:40 parent [[S4]] } // CHECK: debug_value {{.*}} : $Optional, let, name "value", {{.*}}, scope [[S0]] - // CHECK: debug_value {{.*}} : $String, let, name "value", {{.*}}, scope [[S1]] - // CHECK: debug_value {{.*}} : $Int, let, name "value", {{.*}}, scope [[S2]] + // CHECK: debug_value {{.*}} : $String, let, name "value", {{.*}}, scope [[S2]] + // CHECK: debug_value {{.*}} : $Int, let, name "value", {{.*}}, scope [[S4]] use((value)) } } diff --git a/test/SILGen/switch-case-debug-descriptions.swift b/test/SILGen/switch-case-debug-descriptions.swift index acf2d46451726..68b118406653a 100644 --- a/test/SILGen/switch-case-debug-descriptions.swift +++ b/test/SILGen/switch-case-debug-descriptions.swift @@ -9,7 +9,7 @@ enum E { func test1(_ e: E) { switch e { // SCOPE: sil_scope [[test1_switch:[0-9]+]] {{.*}}:[[@LINE]]:3 case .one(let payload), .two(let payload): // SCOPE-NEXT: sil_scope [[test1_case1:[0-9]+]] {{.*}}:[[@LINE]]:3 parent [[test1_switch]] - print(payload) + print(payload) // SCOPE-NEXT: sil_scope {{.*}}:[[@LINE]]:5 parent [[test1_case1]] case .three(let payload): // SCOPE-NEXT: sil_scope [[test1_case2:[0-9]+]] {{.*}}:[[@LINE]]:3 parent [[test1_switch]] print(payload) } @@ -43,7 +43,7 @@ func test4(_ e: E) { print(x) // SCOPE-NEXT: sil_scope {{.*}}:[[@LINE]]:5 parent [[test4_case1]] fallthrough case .two(let x): // SCOPE-NEXT: sil_scope [[test4_case2:[0-9]+]] {{.*}}:[[@LINE]]:3 parent [[test4_switch]] - print(x) + print(x) // SCOPE-NEXT: {{.*}}:[[@LINE]]:5 parent [[test4_case2]] fallthrough default: // SCOPE-NEXT: sil_scope [[test4_default:[0-9]+]] {{.*}}:[[@LINE]]:3 parent [[test4_switch]] print("default") // SCOPE: sil_scope [[test4_default1:[0-9]+]] {{.*}}:[[@LINE]]:5 From fef357848419e57deea168e95fe94f12c4819b90 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Fri, 16 Jun 2023 14:50:04 -0700 Subject: [PATCH 30/41] Temporarily disable assertion. --- lib/SILGen/SILGenFunction.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/SILGen/SILGenFunction.cpp b/lib/SILGen/SILGenFunction.cpp index 33fc549d59017..1a019092f1dc4 100644 --- a/lib/SILGen/SILGenFunction.cpp +++ b/lib/SILGen/SILGenFunction.cpp @@ -79,9 +79,10 @@ SILGenFunction::SILGenFunction(SILGenModule &SGM, SILFunction &F, llvm::dbgs() << "+ " << value->getBaseIdentifier() << "\n"; }); - assert((VarDeclScopeMap.count(value) == 0 || - VarDeclScopeMap[value] == ASTScope) && - "VarDecl appears twice"); + // FIXME: ASTs coming out of the autodiff transformation trigger this. + // assert((VarDeclScopeMap.count(value) == 0 || + // VarDeclScopeMap[value] == ASTScope) && + // "VarDecl appears twice"); VarDeclScopeMap.insert({value, ASTScope}); } return false; From d067453ee1979994e25b3669822ceca3987a4f40 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Thu, 8 Jun 2023 10:56:54 -0700 Subject: [PATCH 31/41] [FieldSensitivePL] NFC: Implemented print. The members were declared but undefined. --- .../Utils/FieldSensitivePrunedLiveness.cpp | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/lib/SIL/Utils/FieldSensitivePrunedLiveness.cpp b/lib/SIL/Utils/FieldSensitivePrunedLiveness.cpp index 27cbaebc45098..93d1893a6f4c7 100644 --- a/lib/SIL/Utils/FieldSensitivePrunedLiveness.cpp +++ b/lib/SIL/Utils/FieldSensitivePrunedLiveness.cpp @@ -563,6 +563,38 @@ void FieldSensitivePrunedLiveBlocks::print(llvm::raw_ostream &OS) const { void FieldSensitivePrunedLiveBlocks::dump() const { print(llvm::dbgs()); } +//===----------------------------------------------------------------------===// +// FieldSensitivePrunedLivenessBoundary +//===----------------------------------------------------------------------===// + +void FieldSensitivePrunedLivenessBoundary::print(llvm::raw_ostream &OS) const { + for (auto pair : lastUsers) { + auto *user = pair.first; + auto bits = pair.second; + OS << "last user: " << *user + << "\tat " << bits << "\n"; + } + for (auto pair : boundaryEdges) { + auto *block = pair.first; + auto bits = pair.second; + OS << "boundary edge: "; + block->printAsOperand(OS); + OS << "\n" << "\tat " << bits << "\n"; + } + if (!deadDefs.empty()) { + for (auto pair : deadDefs) { + auto *deadDef = pair.first; + auto bits = pair.second; + OS << "dead def: " << *deadDef + << "\tat " << bits << "\n"; + } + } +} + +void FieldSensitivePrunedLivenessBoundary::dump() const { + print(llvm::dbgs()); +} + //===----------------------------------------------------------------------===// // MARK: FieldSensitiveLiveness //===----------------------------------------------------------------------===// From 934ec10f68b9cf69c8c826ee519e4bbd7b2a6b1b Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Fri, 16 Jun 2023 11:35:20 -0700 Subject: [PATCH 32/41] [Basic] Removed spurious req from FrozenMultiMap. Its storage vector is intended to be of some type like `std::vector>>`, i.e., some collection of pairs whose `second` is an `Optional`. So when constructing a default instance of that pair, just construct an Optional in the None case. --- include/swift/Basic/FrozenMultiMap.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/swift/Basic/FrozenMultiMap.h b/include/swift/Basic/FrozenMultiMap.h index 617fd64407266..a36f3e4704b1d 100644 --- a/include/swift/Basic/FrozenMultiMap.h +++ b/include/swift/Basic/FrozenMultiMap.h @@ -71,7 +71,7 @@ class FrozenMultiMap { // Since our array is sorted, we need to first find the first pair with our // inst as the first element. auto start = std::lower_bound( - storage.begin(), storage.end(), std::make_pair(key, Value()), + storage.begin(), storage.end(), std::make_pair(key, llvm::None), [&](const std::pair> &p1, const std::pair> &p2) { return p1.first < p2.first; From f4d8761445734c2a34999f661fbb5c71c335433a Mon Sep 17 00:00:00 2001 From: Xi Ge Date: Fri, 16 Jun 2023 13:50:25 -0700 Subject: [PATCH 33/41] ModuleLoader: minor clean-up to remove dead code. NFC --- lib/Frontend/ModuleInterfaceLoader.cpp | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/lib/Frontend/ModuleInterfaceLoader.cpp b/lib/Frontend/ModuleInterfaceLoader.cpp index 1a5296f910910..5aaaf9d90de1c 100644 --- a/lib/Frontend/ModuleInterfaceLoader.cpp +++ b/lib/Frontend/ModuleInterfaceLoader.cpp @@ -719,15 +719,16 @@ class ModuleInterfaceLoaderImpl { return pathStartsWith(hostPath, path); } - bool isInSystemFrameworks(StringRef path) { + bool isInSystemFrameworks(StringRef path, bool publicFramework) { StringRef sdkPath = ctx.SearchPathOpts.getSDKPath(); if (sdkPath.empty()) return false; - SmallString<128> publicFrameworksPath; - llvm::sys::path::append(publicFrameworksPath, - sdkPath, "System", "Library", "Frameworks"); + SmallString<128> frameworksPath; + llvm::sys::path::append(frameworksPath, + sdkPath, "System", "Library", + publicFramework ? "Frameworks" : "PrivateFrameworks"); - return pathStartsWith(publicFrameworksPath, path); + return pathStartsWith(frameworksPath, path); } std::pair getCompiledModuleCandidates() { @@ -738,11 +739,7 @@ class ModuleInterfaceLoaderImpl { // Don't use the adjacent swiftmodule for frameworks from the public // Frameworks folder of the SDK. - SmallString<128> publicFrameworksPath; - llvm::sys::path::append(publicFrameworksPath, - ctx.SearchPathOpts.getSDKPath(), - "System", "Library", "Frameworks"); - if (isInSystemFrameworks(modulePath)) { + if (isInSystemFrameworks(modulePath, /*publicFramework*/true)) { shouldLoadAdjacentModule = false; rebuildInfo.addIgnoredModule(modulePath, ReasonIgnored::PublicFramework); } else if (isInResourceHostDir(modulePath)) { From 1ec900e2a00e9905e9b49e894d057c38b76bd720 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Thu, 15 Jun 2023 17:45:48 -0700 Subject: [PATCH 34/41] [Macros] Add default plugin paths for Darwin SDKs and platforms. Corresponding to https://github.com/apple/swift-driver/pull/1377, this adds some default plugin paths for Darwin SDKs and platforms. Fixes rdar://110819604. --- include/swift/Driver/ToolChain.h | 5 +++ lib/Driver/DarwinToolChains.cpp | 45 +++++++++++++++++++ lib/Driver/ToolChains.cpp | 11 +++++ lib/Driver/ToolChains.h | 6 +++ test/Driver/compiler_plugin_path_macosx.swift | 24 ++++++++++ test/Driver/driver-compile.swift | 2 +- test/Driver/merge-module.swift | 7 +-- test/Driver/sdk.swift | 2 +- 8 files changed, 97 insertions(+), 5 deletions(-) create mode 100644 test/Driver/compiler_plugin_path_macosx.swift diff --git a/include/swift/Driver/ToolChain.h b/include/swift/Driver/ToolChain.h index d76b0c6c99036..9655eebe6ae71 100644 --- a/include/swift/Driver/ToolChain.h +++ b/include/swift/Driver/ToolChain.h @@ -143,6 +143,11 @@ class ToolChain { const llvm::opt::ArgList &inputArgs, llvm::opt::ArgStringList &arguments) const; + virtual void addPlatformSpecificPluginFrontendArgs( + const OutputInfo &OI, + const CommandOutput &output, + const llvm::opt::ArgList &inputArgs, + llvm::opt::ArgStringList &arguments) const; virtual InvocationInfo constructInvocation(const CompileJobAction &job, const JobContext &context) const; virtual InvocationInfo constructInvocation(const InterpretJobAction &job, diff --git a/lib/Driver/DarwinToolChains.cpp b/lib/Driver/DarwinToolChains.cpp index 02024e99257a5..7ec1a9a1b7eb8 100644 --- a/lib/Driver/DarwinToolChains.cpp +++ b/lib/Driver/DarwinToolChains.cpp @@ -620,6 +620,51 @@ void toolchains::Darwin::addCommonFrontendArgs( } } +/// Add the frontend arguments needed to find external plugins in standard +/// locations based on the base path. +static void addExternalPluginFrontendArgs( + StringRef basePath, const llvm::opt::ArgList &inputArgs, + llvm::opt::ArgStringList &arguments) { + // Plugin server: $BASE/usr/bin/swift-plugin-server + SmallString<128> pluginServer; + llvm::sys::path::append( + pluginServer, basePath, "usr", "bin", "swift-plugin-server"); + + SmallString<128> pluginDir; + llvm::sys::path::append(pluginDir, basePath, "usr", "lib"); + llvm::sys::path::append(pluginDir, "swift", "host", "plugins"); + arguments.push_back("-external-plugin-path"); + arguments.push_back(inputArgs.MakeArgString(pluginDir + "#" + pluginServer)); + + pluginDir.clear(); + llvm::sys::path::append(pluginDir, basePath, "usr", "local", "lib"); + llvm::sys::path::append(pluginDir, "swift", "host", "plugins"); + arguments.push_back("-external-plugin-path"); + arguments.push_back(inputArgs.MakeArgString(pluginDir + "#" + pluginServer)); +} + +void toolchains::Darwin::addPlatformSpecificPluginFrontendArgs( + const OutputInfo &OI, + const CommandOutput &output, + const llvm::opt::ArgList &inputArgs, + llvm::opt::ArgStringList &arguments) const { + // Add SDK-relative directories for plugins. + if (!OI.SDKPath.empty()) { + addExternalPluginFrontendArgs(OI.SDKPath, inputArgs, arguments); + } + + // Add platform-relative directories for plugins. + if (!OI.SDKPath.empty()) { + SmallString<128> platformPath; + llvm::sys::path::append(platformPath, OI.SDKPath); + llvm::sys::path::remove_filename(platformPath); // specific SDK + llvm::sys::path::remove_filename(platformPath); // SDKs + llvm::sys::path::remove_filename(platformPath); // Developer + llvm::sys::path::append(platformPath, "Developer"); + addExternalPluginFrontendArgs(platformPath, inputArgs, arguments); + } +} + ToolChain::InvocationInfo toolchains::Darwin::constructInvocation(const DynamicLinkJobAction &job, const JobContext &context) const { diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index c17b17f808b2d..eb1c8a0ade532 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -375,6 +375,9 @@ void ToolChain::addCommonFrontendArgs(const OutputInfo &OI, // Specify default plugin search path options after explicitly specified // options. inputArgs.AddAllArgs(arguments, options::OPT_plugin_search_Group); + addPlatformSpecificPluginFrontendArgs(OI, output, inputArgs, arguments); + + // Toolchain-relative plugin paths { SmallString<64> pluginPath; auto programPath = getDriver().getSwiftProgramPath(); @@ -403,6 +406,14 @@ void ToolChain::addCommonFrontendArgs(const OutputInfo &OI, inputArgs.AddAllArgs(arguments, options::OPT_Xcc); } +void ToolChain::addPlatformSpecificPluginFrontendArgs( + const OutputInfo &OI, + const CommandOutput &output, + const llvm::opt::ArgList &inputArgs, + llvm::opt::ArgStringList &arguments) const { + // Overridden where necessary. +} + static void addRuntimeLibraryFlags(const OutputInfo &OI, ArgStringList &Arguments) { if (!OI.RuntimeVariant) diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h index c30b04809e4f1..a91f3dd78cc29 100644 --- a/lib/Driver/ToolChains.h +++ b/lib/Driver/ToolChains.h @@ -53,6 +53,12 @@ class LLVM_LIBRARY_VISIBILITY Darwin : public ToolChain { const llvm::opt::ArgList &inputArgs, llvm::opt::ArgStringList &arguments) const override; + void addPlatformSpecificPluginFrontendArgs( + const OutputInfo &OI, + const CommandOutput &output, + const llvm::opt::ArgList &inputArgs, + llvm::opt::ArgStringList &arguments) const override; + InvocationInfo constructInvocation(const InterpretJobAction &job, const JobContext &context) const override; InvocationInfo constructInvocation(const DynamicLinkJobAction &job, diff --git a/test/Driver/compiler_plugin_path_macosx.swift b/test/Driver/compiler_plugin_path_macosx.swift new file mode 100644 index 0000000000000..556dcf21579a6 --- /dev/null +++ b/test/Driver/compiler_plugin_path_macosx.swift @@ -0,0 +1,24 @@ +// RUN: %swiftc_driver -driver-print-jobs -target x86_64-apple-macosx10.9 %s 2>^1 | %FileCheck %s +// REQUIRES: OS=macosx + +// CHECK: -external-plugin-path +// CHECK-SAME: .sdk/usr/lib/swift/host/plugins# +// CHECK-SAME: .sdk/usr/bin/swift-plugin-server + +// CHECK-SAME: -external-plugin-path +// CHECK-SAME: .sdk/usr/local/lib/swift/host/plugins# +// CHECK-SAME: .sdk/usr/bin/swift-plugin-server + +// CHECK-SAME: -external-plugin-path +// CHECK-SAME: MacOSX.platform/Developer/usr/lib/swift/host/plugins# +// CHECK-SAME: MacOSX.platform/Developer/usr/bin/swift-plugin-server + +// CHECK-SAME: -external-plugin-path +// CHECK-SAME: MacOSX.platform/Developer/usr/local/lib/swift/host/plugins# +// CHECK-SAME: MacOSX.platform/Developer/usr/bin/swift-plugin-server + +// CHECK-SAME: -plugin-path +// CHECK-SAME: {{(/|\\\\)}}lib{{(/|\\\\)}}swift{{(/|\\\\)}}host{{(/|\\\\)}}plugins + +// CHECK-SAME: -plugin-path +// CHECK-SAME: {{(/|\\\\)}}local{{(/|\\\\)}}lib{{(/|\\\\)}}swift{{(/|\\\\)}}host{{(/|\\\\)}}plugins diff --git a/test/Driver/driver-compile.swift b/test/Driver/driver-compile.swift index 920bd127e199c..5910b4f1b794e 100644 --- a/test/Driver/driver-compile.swift +++ b/test/Driver/driver-compile.swift @@ -75,7 +75,7 @@ // COMPLEX: bin{{/|\\\\}}swift // COMPLEX: -c // COMPLEX: Driver{{/|\\\\}}driver-compile.swift -// COMPLEX-DAG: -sdk {{.*}}/Inputs/clang-importer-sdk +// COMPLEX-DAG: -sdk // COMPLEX-DAG: -foo -bar // COMPLEX-DAG: -Xllvm -baz // COMPLEX-DAG: -Xcc -garply diff --git a/test/Driver/merge-module.swift b/test/Driver/merge-module.swift index b8cf77ba0ee13..9a2e934661bcc 100644 --- a/test/Driver/merge-module.swift +++ b/test/Driver/merge-module.swift @@ -36,15 +36,16 @@ // SIMPLE: -o main.swiftmodule -// COMPLEX: {{bin(/|\\\\)swift(-frontend|c)?(\.exe)?"?}} -frontend +// COMPLEX: -frontend // COMPLEX: -emit-module // COMPLEX-DAG: -emit-module-doc-path {{[^ ]*[/\\]}}merge-module-{{[^ ]*}}.swiftdoc -// COMPLEX-DAG: -sdk {{.*}}/Inputs/clang-importer-sdk +// COMPLEX-DAG: -sdk +// COMPLEX-DAG /Inputs/clang-importer-sdk // COMPLEX-DAG: -foo -bar // COMPLEX-DAG: -F /path/to/frameworks -F /path/to/more/frameworks // COMPLEX-DAG: -I /path/to/headers -I path/to/more/headers // COMPLEX-DAG: -module-cache-path /tmp/modules -// COMPLEX: {{bin(/|\\\\)swift(-frontend|c)?(\.exe)?"?}} -frontend +// COMPLEX-DAG: -frontend // COMPLEX: -emit-module // COMPLEX-DAG: -F /path/to/frameworks -F /path/to/more/frameworks // COMPLEX-DAG: -I /path/to/headers -I path/to/more/headers diff --git a/test/Driver/sdk.swift b/test/Driver/sdk.swift index 8aba6e15f51f3..6ec138bd8fbc1 100644 --- a/test/Driver/sdk.swift +++ b/test/Driver/sdk.swift @@ -12,7 +12,7 @@ // OSX: bin{{/|\\\\}}swift // OSX: Driver{{/|\\\\}}sdk.swift // OSX: -sdk {{.*}}/Inputs/clang-importer-sdk -// OSX-NEXT: bin{{/|\\\\}}swift +// OSX: bin{{/|\\\\}}swift // OSX: -sdk {{.*}}/Inputs/clang-importer-sdk // OSX: {{.*}}.o{{[ "]}} // OSX: {{-syslibroot|--sysroot}} {{[^ ]*}}/Inputs/clang-importer-sdk From 36451efb5521a641f19bbb5d44c78f35a44338a6 Mon Sep 17 00:00:00 2001 From: Kavon Farvardin Date: Fri, 16 Jun 2023 11:47:30 -0700 Subject: [PATCH 35/41] require `consume x` for noncopyable pattern bindings since they're consuming this was staged in as a warning initially but it was intended to be an error if it is not written so that we can move to a world where these pattern matches are done as a borrowing operation instead. rdar://110908714 --- include/swift/AST/DiagnosticsSema.def | 2 +- test/SILGen/moveonly.swift | 16 ++++++--- test/Sema/moveonly_enum.swift | 48 +++++++++++++-------------- 3 files changed, 36 insertions(+), 30 deletions(-) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 63cde20ba0480..3a6606abf2a63 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -4672,7 +4672,7 @@ ERROR(unknown_case_multiple_patterns,none, ERROR(unknown_case_must_be_last,none, "'@unknown' can only be applied to the last case in a switch", ()) -WARNING(move_only_pattern_match_not_consumed,none, +ERROR(move_only_pattern_match_not_consumed,none, "noncopyable binding being pattern-matched must have the 'consume' operator applied", ()) WARNING(where_on_one_item, none, diff --git a/test/SILGen/moveonly.swift b/test/SILGen/moveonly.swift index e25375482eb4e..9bab733282537 100644 --- a/test/SILGen/moveonly.swift +++ b/test/SILGen/moveonly.swift @@ -131,7 +131,7 @@ public func useNonTrivialOwnedStruct(_ s: __owned NonTrivialStruct) { public func useNonTrivialEnum(_ s: borrowing NonTrivialEnum) { borrowVal(s) let s2 = s - switch s { + switch consume s { case _: break } @@ -149,7 +149,7 @@ public func useNonTrivialEnum(_ s: borrowing NonTrivialEnum) { public func useNonTrivialOwnedEnum(_ s: __owned NonTrivialEnum) { borrowVal(s) let s2 = s - switch s { + switch consume s { case _: break } @@ -705,7 +705,13 @@ var booleanGuard2: Bool { false } // CHECK-LABEL: sil hidden [ossa] @$s8moveonly15enumSwitchTest1yyAA04EnumC5TestsO1EOF : $@convention(thin) (@guaranteed EnumSwitchTests.E) -> () { // CHECK: bb0([[ARG:%.*]] : @guaranteed // CHECK: [[COPY_ARG:%.*]] = copy_value [[ARG]] -// CHECK: [[MARKED_VALUE:%.*]] = mark_must_check [no_consume_or_assign] [[COPY_ARG]] +// CHECK: [[ARG_MARKED_VALUE:%.*]] = mark_must_check [no_consume_or_assign] [[COPY_ARG]] +// -- code corresponding to the consume x -- +// CHECK: [[BORROW_ARG_MARKED_VALUE:%.*]] = begin_borrow [[ARG_MARKED_VALUE]] +// CHECK: [[COPY_COPY_ARG:%.*]] = copy_value [[BORROW_ARG_MARKED_VALUE]] +// CHECK: [[MOVE_COPY_COPY_ARG:%.*]] = move_value [allows_diagnostics] [[COPY_COPY_ARG]] +// CHECK: [[MARKED_VALUE:%.*]] = mark_must_check [consumable_and_assignable] [[MOVE_COPY_COPY_ARG]] +// -- now switching on the `consume x` -- // CHECK: [[BORROWED_VALUE:%.*]] = begin_borrow [[MARKED_VALUE]] // CHECK: switch_enum [[BORROWED_VALUE]] : $EnumSwitchTests.E, case #EnumSwitchTests.E.first!enumelt: [[BB_E_1:bb[0-9]+]], case #EnumSwitchTests.E.second!enumelt: [[BB_E_2:bb[0-9]+]], case #EnumSwitchTests.E.third!enumelt: [[BB_E_3:bb[0-9]+]], case #EnumSwitchTests.E.fourth!enumelt: [[BB_E_4:bb[0-9]+]] // @@ -758,10 +764,10 @@ var booleanGuard2: Bool { false } // CHECK: br [[BB_CONT]] // // CHECK: [[BB_CONT]]: -// CHECK: destroy_value [[MARKED_VALUE]] +// CHECK: destroy_value [[ARG_MARKED_VALUE]] // CHECK: } // end sil function '$s8moveonly15enumSwitchTest1yyAA04EnumC5TestsO1EOF' func enumSwitchTest1(_ e: borrowing EnumSwitchTests.E) { - switch e { + switch consume e { case .first: break case .second(let x): diff --git a/test/Sema/moveonly_enum.swift b/test/Sema/moveonly_enum.swift index 4218967baa3ae..ed1121ad31c06 100644 --- a/test/Sema/moveonly_enum.swift +++ b/test/Sema/moveonly_enum.swift @@ -22,7 +22,7 @@ enum Foo3 { } func test_switch(x: consuming Foo3) { - switch x { // expected-warning{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{12-12=consume }} + switch x { // expected-error{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{12-12=consume }} default: break } @@ -32,7 +32,7 @@ func test_switch(x: consuming Foo3) { break } - switch (x) { // expected-warning{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{13-13=consume }} + switch (x) { // expected-error{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{13-13=consume }} default: break } @@ -43,7 +43,7 @@ func test_switch(x: consuming Foo3) { } let _: () -> () = { - switch x { // expected-warning{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{16-16=consume }} + switch x { // expected-error{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{16-16=consume }} default: break } @@ -57,7 +57,7 @@ func test_switch(x: consuming Foo3) { } let _: () -> () = { - switch (x) { // expected-warning{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{17-17=consume }} + switch (x) { // expected-error{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{17-17=consume }} default: break } @@ -72,9 +72,9 @@ func test_switch(x: consuming Foo3) { } func test_if_case(x: consuming Foo3) { - if case .bar(let y) = x { _ = y } // expected-warning{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{27-27=consume }} + if case .bar(let y) = x { _ = y } // expected-error{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{27-27=consume }} - guard case .bar(let y) = x else { return } // expected-warning{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{30-30=consume }} + guard case .bar(let y) = x else { return } // expected-error{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{30-30=consume }} _ = y if case .bar(let z) = consume x { _ = z } @@ -82,9 +82,9 @@ func test_if_case(x: consuming Foo3) { guard case .bar(let z) = consume x else { return } _ = z - if case .bar(let a) = (x) { _ = a } // expected-warning{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{28-28=consume }} + if case .bar(let a) = (x) { _ = a } // expected-error{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{28-28=consume }} - guard case .bar(let a) = (x) else { return } // expected-warning{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{31-31=consume }} + guard case .bar(let a) = (x) else { return } // expected-error{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{31-31=consume }} _ = a if case .bar(let b) = (consume x) { _ = b } @@ -93,11 +93,11 @@ func test_if_case(x: consuming Foo3) { _ = b let _: () -> () = { - if case .bar(let y) = x { _ = y } // expected-warning{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{31-31=consume }} + if case .bar(let y) = x { _ = y } // expected-error{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{31-31=consume }} } let _: () -> () = { - guard case .bar(let y) = x else { return } // expected-warning{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{34-34=consume }} + guard case .bar(let y) = x else { return } // expected-error{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{34-34=consume }} _ = y } @@ -111,11 +111,11 @@ func test_if_case(x: consuming Foo3) { } let _: () -> () = { - if case .bar(let a) = (x) { _ = a } // expected-warning{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{32-32=consume }} + if case .bar(let a) = (x) { _ = a } // expected-error{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{32-32=consume }} } let _: () -> () = { - guard case .bar(let a) = (x) else { return } // expected-warning{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{35-35=consume }} + guard case .bar(let a) = (x) else { return } // expected-error{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{35-35=consume }} _ = a } @@ -130,7 +130,7 @@ func test_if_case(x: consuming Foo3) { } func test_switch_b(x: __owned Foo3) { - switch x { // expected-warning{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{12-12=consume }} + switch x { // expected-error{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{12-12=consume }} default: break } @@ -140,7 +140,7 @@ func test_switch_b(x: __owned Foo3) { break } - switch (x) { // expected-warning{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{13-13=consume }} + switch (x) { // expected-error{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{13-13=consume }} default: break } @@ -151,7 +151,7 @@ func test_switch_b(x: __owned Foo3) { } let _: () -> () = { - switch x { // expected-warning{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{16-16=consume }} + switch x { // expected-error{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{16-16=consume }} default: break } @@ -165,7 +165,7 @@ func test_switch_b(x: __owned Foo3) { } let _: () -> () = { - switch (x) { // expected-warning{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{17-17=consume }} + switch (x) { // expected-error{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{17-17=consume }} default: break } @@ -180,9 +180,9 @@ func test_switch_b(x: __owned Foo3) { } func test_if_case_b(x: __owned Foo3) { - if case .bar(let y) = x { _ = y } // expected-warning{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{27-27=consume }} + if case .bar(let y) = x { _ = y } // expected-error{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{27-27=consume }} - guard case .bar(let y) = x else { return } // expected-warning{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{30-30=consume }} + guard case .bar(let y) = x else { return } // expected-error{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{30-30=consume }} _ = y if case .bar(let z) = consume x { _ = z } @@ -190,9 +190,9 @@ func test_if_case_b(x: __owned Foo3) { guard case .bar(let z) = consume x else { return } _ = z - if case .bar(let a) = (x) { _ = a } // expected-warning{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{28-28=consume }} + if case .bar(let a) = (x) { _ = a } // expected-error{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{28-28=consume }} - guard case .bar(let a) = (x) else { return } // expected-warning{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{31-31=consume }} + guard case .bar(let a) = (x) else { return } // expected-error{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{31-31=consume }} _ = a if case .bar(let b) = (consume x) { _ = b } @@ -201,11 +201,11 @@ func test_if_case_b(x: __owned Foo3) { _ = b let _: () -> () = { - if case .bar(let y) = x { _ = y } // expected-warning{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{31-31=consume }} + if case .bar(let y) = x { _ = y } // expected-error{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{31-31=consume }} } let _: () -> () = { - guard case .bar(let y) = x else { return } // expected-warning{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{34-34=consume }} + guard case .bar(let y) = x else { return } // expected-error{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{34-34=consume }} _ = y } @@ -219,11 +219,11 @@ func test_if_case_b(x: __owned Foo3) { } let _: () -> () = { - if case .bar(let a) = (x) { _ = a } // expected-warning{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{32-32=consume }} + if case .bar(let a) = (x) { _ = a } // expected-error{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{32-32=consume }} } let _: () -> () = { - guard case .bar(let a) = (x) else { return } // expected-warning{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{35-35=consume }} + guard case .bar(let a) = (x) else { return } // expected-error{{noncopyable binding being pattern-matched must have the 'consume' operator applied}} {{35-35=consume }} _ = a } From 874b5772803895b0bf9aec7940e1af0cbba84dba Mon Sep 17 00:00:00 2001 From: Dario Rexin Date: Fri, 16 Jun 2023 18:14:48 -0700 Subject: [PATCH 36/41] =?UTF-8?q?[IRGen]=20Use=20EnumImplStrategy=20to=20g?= =?UTF-8?q?enerate=20getEnumTag=20function=20for=20layo=E2=80=A6=20(#66707?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [IRGen] Use EnumImplStrategy to generate getEnumTag function for layout strings rdar://110794898 The implementation in TypeLayout seems to have a bug causing wrong tags to be returned on 32 bit systems. * Don't use unsupported types in tests --- lib/IRGen/TypeLayout.cpp | 4 +++- test/Interpreter/Inputs/layout_string_witnesses_types.swift | 2 +- test/Interpreter/layout_string_witnesses_static.swift | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/IRGen/TypeLayout.cpp b/lib/IRGen/TypeLayout.cpp index 5ef1e9fbd1f60..45d9b515c88eb 100644 --- a/lib/IRGen/TypeLayout.cpp +++ b/lib/IRGen/TypeLayout.cpp @@ -15,6 +15,7 @@ #include "FixedTypeInfo.h" #include "GenOpaque.h" #include "IRGen.h" +#include "GenEnum.h" #include "GenExistential.h" #include "GenericArguments.h" #include "IRGenFunction.h" @@ -510,7 +511,8 @@ llvm::Function *createFixedEnumLoadTag(IRGenModule &IGM, auto castEnumPtr = IGF.Builder.CreateBitCast(enumPtr, enumType); auto enumAddr = typeInfo->getAddressForPointer(castEnumPtr); - auto tag = entry.getEnumTag(IGF, enumAddr); + auto &strategy = getEnumImplStrategy(IGM, entry.ty); + auto tag = strategy.emitGetEnumTag(IGF, entry.ty, enumAddr); IGF.Builder.CreateRet(tag); }); diff --git a/test/Interpreter/Inputs/layout_string_witnesses_types.swift b/test/Interpreter/Inputs/layout_string_witnesses_types.swift index 1eb45df5b93d2..0be7f7c54ca90 100644 --- a/test/Interpreter/Inputs/layout_string_witnesses_types.swift +++ b/test/Interpreter/Inputs/layout_string_witnesses_types.swift @@ -454,7 +454,7 @@ public enum SinglePayloadEnumManyXI { case empty4 case empty5 case empty6 - case nonEmpty(Builtin.Int127, SimpleClass) + case nonEmpty(Builtin.Int63, SimpleClass) } public struct PrespecializedStruct { diff --git a/test/Interpreter/layout_string_witnesses_static.swift b/test/Interpreter/layout_string_witnesses_static.swift index b90a89623334a..c612445152503 100644 --- a/test/Interpreter/layout_string_witnesses_static.swift +++ b/test/Interpreter/layout_string_witnesses_static.swift @@ -1,8 +1,8 @@ // RUN: %empty-directory(%t) -// RUN: %target-swift-frontend -enable-experimental-feature LayoutStringValueWitnesses -enable-layout-string-value-witnesses -enable-type-layout -parse-stdlib -emit-module -emit-module-path=%t/layout_string_witnesses_types.swiftmodule %S/Inputs/layout_string_witnesses_types.swift +// RUN: %target-swift-frontend -enable-experimental-feature LayoutStringValueWitnesses -enable-layout-string-value-witnesses -parse-stdlib -emit-module -emit-module-path=%t/layout_string_witnesses_types.swiftmodule %S/Inputs/layout_string_witnesses_types.swift // NOTE: We have to build this as dylib to turn private external symbols into local symbols, so we can observe potential issues with linkage -// RUN: %target-build-swift-dylib(%t/%target-library-name(layout_string_witnesses_types)) -Xfrontend -enable-experimental-feature -Xfrontend LayoutStringValueWitnesses -Xfrontend -enable-layout-string-value-witnesses -Xfrontend -enable-type-layout -Xfrontend -parse-stdlib -parse-as-library %S/Inputs/layout_string_witnesses_types.swift +// RUN: %target-build-swift-dylib(%t/%target-library-name(layout_string_witnesses_types)) -Xfrontend -enable-experimental-feature -Xfrontend LayoutStringValueWitnesses -Xfrontend -enable-layout-string-value-witnesses -Xfrontend -parse-stdlib -parse-as-library %S/Inputs/layout_string_witnesses_types.swift // RUN: %target-codesign %t/%target-library-name(layout_string_witnesses_types) // RUN: %target-swift-frontend -enable-experimental-feature LayoutStringValueWitnesses -enable-layout-string-value-witnesses -enable-library-evolution -emit-module -emit-module-path=%t/layout_string_witnesses_types_resilient.swiftmodule %S/Inputs/layout_string_witnesses_types_resilient.swift // RUN: %target-build-swift -g -Xfrontend -enable-experimental-feature -Xfrontend LayoutStringValueWitnesses -Xfrontend -enable-layout-string-value-witnesses -Xfrontend -enable-library-evolution -c -parse-as-library -o %t/layout_string_witnesses_types_resilient.o %S/Inputs/layout_string_witnesses_types_resilient.swift From f4e3292a2ff236ffb370ad343e7cb29d73507ca4 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Fri, 16 Jun 2023 15:21:36 -0700 Subject: [PATCH 37/41] [FieldSensitivePL] Fix vectorization. FieldSensitivePrunedLiveness is used as a vectorization of PrunedLiveness. An instance of FSPL with N elements needs to be able to represent the same states as N instances of PL. Previously, it failed to do that in two significant ways: (1) It attempted to save space for which elements were live by using a range. This failed to account for instructions which are users of non-contiguous fields of an aggregate. apply( @owned (struct_element_addr %s, #S.f1), @owned (struct_element_addr %s, #S.f3) ) (2) It used a single bit to represent whether the instruction was consuming. This failed to account for instructions which consumed some fields and borrowed others. apply( @owned (struct_element_addr %s, #S.f1), @guaranteed (struct_element_addr %s, #S.f2) ) The fix for (1) is to use a bit vector to represent which elements are used by the instruction. The fix for (2) is to use a second bit vector to represent which elements are _consumed_ by the instruction. Adapted the move-checker to use the new representation. rdar://110909290 --- .../swift/SIL/FieldSensitivePrunedLiveness.h | 151 ++++++++++------- .../Utils/FieldSensitivePrunedLiveness.cpp | 13 +- .../Mandatory/MoveOnlyAddressCheckerUtils.cpp | 158 ++++++++++-------- .../MoveOnlyBorrowToDestructureUtils.cpp | 28 ++-- test/SILOptimizer/moveonly_addresschecker.sil | 117 +++++++++++++ 5 files changed, 319 insertions(+), 148 deletions(-) diff --git a/include/swift/SIL/FieldSensitivePrunedLiveness.h b/include/swift/SIL/FieldSensitivePrunedLiveness.h index 1728e0955bd3d..456ba6c387bee 100644 --- a/include/swift/SIL/FieldSensitivePrunedLiveness.h +++ b/include/swift/SIL/FieldSensitivePrunedLiveness.h @@ -358,6 +358,13 @@ struct TypeTreeLeafTypeRange { endEltOffset >= range.endEltOffset; } + /// Sets each bit in \p bits corresponding to an element of this range. + void setBits(SmallBitVector &bits) { + for (auto element : getRange()) { + bits.set(element); + } + } + IntRange getRange() const { return range(startEltOffset, endEltOffset); } @@ -666,17 +673,60 @@ class FieldSensitivePrunedLiveness { FieldSensitivePrunedLiveBlocks liveBlocks; public: + enum IsInterestingUser { NonUser, NonLifetimeEndingUse, LifetimeEndingUse }; + struct InterestingUser { - TypeTreeLeafTypeRange subEltSpan; - bool isConsuming; + SmallBitVector liveBits; + SmallBitVector consumingBits; - InterestingUser() : subEltSpan(), isConsuming(false) {} - InterestingUser(TypeTreeLeafTypeRange subEltSpan, bool isConsuming) - : subEltSpan(subEltSpan), isConsuming(isConsuming) {} + InterestingUser(unsigned bitCount) + : liveBits(bitCount), consumingBits(bitCount) {} - InterestingUser &operator&=(bool otherValue) { - isConsuming &= otherValue; - return *this; + InterestingUser(unsigned bitCount, TypeTreeLeafTypeRange range, + bool lifetimeEnding) + : liveBits(bitCount), consumingBits(bitCount) { + addUses(range, lifetimeEnding); + } + + /// Record that the instruction uses the bits of the value in \p range. + void addUses(TypeTreeLeafTypeRange range, bool lifetimeEnding) { + range.setBits(liveBits); + if (lifetimeEnding) { + range.setBits(consumingBits); + } + } + + /// Populates the provided vector with contiguous ranges of bits which are + /// users of the same sort. + void getContiguousRanges( + SmallVectorImpl> + &ranges) const { + if (liveBits.size() == 0) + return; + + assert(ranges.empty()); + Optional> current = llvm::None; + for (unsigned bit = 0, size = liveBits.size(); bit < size; ++bit) { + auto interesting = isInterestingUser(bit); + if (!current) { + current = {bit, interesting}; + continue; + } + if (current->second != interesting) { + ranges.push_back( + {TypeTreeLeafTypeRange(current->first, bit), current->second}); + current = {bit, interesting}; + } + } + ranges.push_back({TypeTreeLeafTypeRange(current->first, liveBits.size()), + current->second}); + } + + IsInterestingUser isInterestingUser(unsigned element) const { + if (!liveBits.test(element)) + return NonUser; + return consumingBits.test(element) ? LifetimeEndingUse + : NonLifetimeEndingUse; } }; @@ -758,42 +808,6 @@ class FieldSensitivePrunedLiveness { return llvm::make_range(users.begin(), users.end()); } - using LifetimeEndingUserRange = OptionalTransformRange< - UserRange, - function_ref>( - const std::pair &)>>; - LifetimeEndingUserRange getAllLifetimeEndingUses() const { - assert(isInitialized()); - function_ref>( - const std::pair &)> - op; - op = [](const std::pair &pair) - -> Optional> { - if (pair.second.isConsuming) - return {{pair.first, pair.second.subEltSpan}}; - return None; - }; - return LifetimeEndingUserRange(getAllUsers(), op); - } - - using NonLifetimeEndingUserRange = OptionalTransformRange< - UserRange, - function_ref>( - const std::pair &)>>; - NonLifetimeEndingUserRange getAllNonLifetimeEndingUses() const { - assert(isInitialized()); - function_ref>( - const std::pair &)> - op; - op = [](const std::pair &pair) - -> Optional> { - if (!pair.second.isConsuming) - return {{pair.first, pair.second.subEltSpan}}; - return None; - }; - return NonLifetimeEndingUserRange(getAllUsers(), op); - } - using UserBlockRange = TransformRange< UserRange, function_ref &)>>; @@ -848,19 +862,37 @@ class FieldSensitivePrunedLiveness { SmallBitVector &liveOutBits, SmallBitVector &deadBits) const; - enum IsInterestingUser { NonUser, NonLifetimeEndingUse, LifetimeEndingUse }; + /// If \p user has had uses recored, return a pointer to the InterestingUser + /// where they've been recorded. + InterestingUser const *getInterestingUser(SILInstruction *user) const { + auto iter = users.find(user); + if (iter == users.end()) + return nullptr; + return &iter->second; + } - /// Return a result indicating whether the given user was identified as an - /// interesting use of the current def and whether it ends the lifetime. - std::pair> - isInterestingUser(SILInstruction *user) const { + /// How \p user uses the field at \p element. + IsInterestingUser isInterestingUser(SILInstruction *user, + unsigned element) const { assert(isInitialized()); - auto useIter = users.find(user); - if (useIter == users.end()) - return {NonUser, None}; - auto isInteresting = - useIter->second.isConsuming ? LifetimeEndingUse : NonLifetimeEndingUse; - return {isInteresting, useIter->second.subEltSpan}; + auto *record = getInterestingUser(user); + if (!record) + return NonUser; + return record->isInterestingUser(element); + } + + /// Whether \p user uses the fields in \p range as indicated by \p kind. + bool isInterestingUserOfKind(SILInstruction *user, IsInterestingUser kind, + TypeTreeLeafTypeRange range) const { + auto *record = getInterestingUser(user); + if (!record) + return kind == IsInterestingUser::NonUser; + + for (auto element : range.getRange()) { + if (isInterestingUser(user, element) != kind) + return false; + } + return true; } unsigned getNumSubElements() const { return liveBlocks.getNumBitsToTrack(); } @@ -886,10 +918,11 @@ class FieldSensitivePrunedLiveness { /// argument must be copied. void addInterestingUser(SILInstruction *user, TypeTreeLeafTypeRange range, bool lifetimeEnding) { - auto iterAndSuccess = - users.insert({user, InterestingUser(range, lifetimeEnding)}); - if (!iterAndSuccess.second) - iterAndSuccess.first->second &= lifetimeEnding; + auto iter = users.find(user); + if (iter == users.end()) { + iter = users.insert({user, InterestingUser(getNumSubElements())}).first; + } + iter->second.addUses(range, lifetimeEnding); } }; diff --git a/lib/SIL/Utils/FieldSensitivePrunedLiveness.cpp b/lib/SIL/Utils/FieldSensitivePrunedLiveness.cpp index 93d1893a6f4c7..e80dbac5946d0 100644 --- a/lib/SIL/Utils/FieldSensitivePrunedLiveness.cpp +++ b/lib/SIL/Utils/FieldSensitivePrunedLiveness.cpp @@ -705,9 +705,7 @@ bool FieldSensitivePrunedLiveRange::isWithinBoundary( // If we are not live and have an interesting user that maps to our bit, // mark this bit as being live again. if (!isLive) { - auto interestingUser = isInterestingUser(&blockInst); - bool isInteresting = - interestingUser.first && interestingUser.second->contains(bit); + bool isInteresting = isInterestingUser(&blockInst, bit); PRUNED_LIVENESS_LOG(llvm::dbgs() << " Inst was dead... Is InterestingUser: " << (isInteresting ? "true" : "false") << '\n'); @@ -838,8 +836,7 @@ void findBoundaryInNonDefBlock(SILBasicBlock *block, unsigned bitNo, PRUNED_LIVENESS_LOG(llvm::dbgs() << "Looking for boundary in non-def block\n"); for (SILInstruction &inst : llvm::reverse(*block)) { PRUNED_LIVENESS_LOG(llvm::dbgs() << "Visiting: " << inst); - auto interestingUser = liveness.isInterestingUser(&inst); - if (interestingUser.first && interestingUser.second->contains(bitNo)) { + if (liveness.isInterestingUser(&inst, bitNo)) { PRUNED_LIVENESS_LOG(llvm::dbgs() << " Is interesting user for this bit!\n"); boundary.getLastUserBits(&inst).set(bitNo); return; @@ -869,8 +866,7 @@ void findBoundaryInSSADefBlock(SILNode *ssaDef, unsigned bitNo, boundary.getDeadDefsBits(cast(&inst)).set(bitNo); return; } - auto interestingUser = liveness.isInterestingUser(&inst); - if (interestingUser.first && interestingUser.second->contains(bitNo)) { + if (liveness.isInterestingUser(&inst, bitNo)) { PRUNED_LIVENESS_LOG(llvm::dbgs() << " Found interesting user: " << inst); boundary.getLastUserBits(&inst).set(bitNo); return; @@ -1005,8 +1001,7 @@ void FieldSensitiveMultiDefPrunedLiveRange::findBoundariesInBlock( PRUNED_LIVENESS_LOG(llvm::dbgs() << " Checking if this inst is also a last user...\n"); if (!isLive) { - auto interestingUser = isInterestingUser(&inst); - if (interestingUser.first && interestingUser.second->contains(bitNo)) { + if (isInterestingUser(&inst, bitNo)) { PRUNED_LIVENESS_LOG( llvm::dbgs() << " Was interesting user! Moving from dead -> live!\n"); diff --git a/lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp b/lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp index 330931afa0507..bb9ab67d4bcb2 100644 --- a/lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp +++ b/lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp @@ -1150,9 +1150,8 @@ namespace { struct ConsumeInfo { /// Map blocks on the lifetime boundary to the last consuming instruction. - llvm::MapVector< - SILBasicBlock *, - SmallVector, 1>> + llvm::MapVector, 1>> finalBlockConsumes; bool isFrozen = false; @@ -1167,8 +1166,7 @@ struct ConsumeInfo { if (!inst) continue; os << "Inst: " << *inst; - os << "Range: "; - instRangePairVector.second.dump(); + os << "Range: " << instRangePairVector.second; os << '\n'; } } @@ -1191,13 +1189,15 @@ struct ConsumeInfo { return foundAny; } - void recordFinalConsume(SILInstruction *inst, TypeTreeLeafTypeRange span) { + void recordFinalConsume(SILInstruction *inst, SmallBitVector const &bits) { assert(!isFrozen); - auto iter = finalBlockConsumes.insert({inst->getParent(), {{inst, span}}}); - if (iter.second) - return; + auto *block = inst->getParent(); + auto iter = finalBlockConsumes.find(block); + if (iter == finalBlockConsumes.end()) { + iter = finalBlockConsumes.insert({block, {}}).first; + } LLVM_DEBUG(llvm::dbgs() << "Recorded Final Consume: " << *inst); - iter.first->second.emplace_back(inst, span); + iter->second.emplace_back(inst, bits); } void finishRecordingFinalConsumes() { @@ -1205,8 +1205,8 @@ struct ConsumeInfo { for (auto &pair : finalBlockConsumes) { llvm::stable_sort( pair.second, - [](const std::pair &lhs, - const std::pair &rhs) { + [](const std::pair &lhs, + const std::pair &rhs) { return lhs.first < rhs.first; }); } @@ -1222,7 +1222,7 @@ struct ConsumeInfo { // operands. // // Can only be used once frozen. - bool claimConsume(SILInstruction *inst, TypeTreeLeafTypeRange range) { + bool claimConsume(SILInstruction *inst, SmallBitVector const &bits) { assert(isFrozen); bool claimedConsume = false; @@ -1230,7 +1230,7 @@ struct ConsumeInfo { auto &iter = finalBlockConsumes[inst->getParent()]; for (unsigned i : indices(iter)) { auto &instRangePair = iter[i]; - if (instRangePair.first == inst && instRangePair.second == range) { + if (instRangePair.first == inst && instRangePair.second == bits) { instRangePair.first = nullptr; claimedConsume = true; LLVM_DEBUG(llvm::dbgs() << "Claimed consume: " << *inst); @@ -2183,9 +2183,9 @@ bool GlobalLivenessChecker::testInstVectorLiveness( // array and emit an error on those instead since it would be a better // error than using end_borrow here. { - auto pair = liveness.isInterestingUser(&*ii); - if (pair.first == FieldSensitivePrunedLiveness::NonLifetimeEndingUse && - pair.second->contains(errorSpan)) { + if (liveness.isInterestingUserOfKind( + &*ii, FieldSensitivePrunedLiveness::NonLifetimeEndingUse, + errorSpan)) { diagnosticEmitter.emitAddressDiagnostic( addressUseState.address, &*ii, errorUser, false /*is consuming*/, addressUseState.isInOutTermUser(&*ii)); @@ -2361,7 +2361,7 @@ static void insertDestroyBeforeInstruction(UseState &addressUseState, // claim that destroy instead of inserting another destroy_addr. if (auto *dai = dyn_cast(nextInstruction)) { if (dai->getOperand() == baseAddress) { - consumes.recordFinalConsume(dai, TypeTreeLeafTypeRange(0, bv.size())); + consumes.recordFinalConsume(dai, bv); return; } } @@ -2371,7 +2371,7 @@ static void insertDestroyBeforeInstruction(UseState &addressUseState, auto loc = RegularLocation::getAutoGeneratedLocation(nextInstruction->getLoc()); auto *dai = builder.createDestroyAddr(loc, baseAddress); - consumes.recordFinalConsume(dai, TypeTreeLeafTypeRange(0, bv.size())); + consumes.recordFinalConsume(dai, bv); addressUseState.destroys.insert({dai, TypeTreeLeafTypeRange(0, bv.size())}); return; } @@ -2389,7 +2389,9 @@ static void insertDestroyBeforeInstruction(UseState &addressUseState, if (pair.first->getType().isTrivial(*nextInstruction->getFunction())) continue; auto *dai = builder.createDestroyAddr(loc, pair.first); - consumes.recordFinalConsume(dai, pair.second); + SmallBitVector consumedBits(bv.size()); + pair.second.setBits(consumedBits); + consumes.recordFinalConsume(dai, consumedBits); addressUseState.destroys.insert({dai, pair.second}); } } @@ -2437,52 +2439,67 @@ void MoveOnlyAddressCheckerPImpl::insertDestroysOnBoundary( LLVM_DEBUG(llvm::dbgs() << " User: " << *inst); - auto interestingUse = liveness.isInterestingUser(inst); - switch (interestingUse.first) { - case IsInterestingUser::LifetimeEndingUse: { - LLVM_DEBUG(llvm::dbgs() - << " Lifetime ending use! Recording final consume!\n"); - // If we have a consuming use, when we stop at the consuming use we want - // the value to still be around. We only want the value to be invalidated - // once the consume operation has occured. Thus we always place the - // debug_value undef strictly after the consuming operation. - if (auto *ti = dyn_cast(inst)) { - for (auto *succBlock : ti->getSuccessorBlocks()) { - insertUndefDebugValue(&succBlock->front()); - } - } else { - insertUndefDebugValue(inst->getNextInstruction()); - } - consumes.recordFinalConsume(inst, *interestingUse.second); - continue; + auto interestingUser = liveness.getInterestingUser(inst); + SmallVector, 4> ranges; + if (interestingUser) { + interestingUser->getContiguousRanges(ranges); } - case IsInterestingUser::NonLifetimeEndingUse: - case IsInterestingUser::NonUser: - LLVM_DEBUG(llvm::dbgs() << " NoneUser or NonLifetimeEndingUse! " - "inserting destroy before instruction!\n"); - // If we are dealing with an inout parameter, we will have modeled our - // last use by treating a return inst as a last use. Since it doesn't have - // any successors, this results in us not inserting any destroy_addr. - if (isa(inst)) { - auto *block = inst->getParent(); - for (auto *succBlock : block->getSuccessorBlocks()) { - auto *insertPt = &*succBlock->begin(); - insertDestroyBeforeInstruction(addressUseState, insertPt, - liveness.getRootValue(), bv, consumes); - // We insert the debug_value undef /after/ the last use since we want - // the value to be around when we stop at the last use instruction. - insertUndefDebugValue(insertPt); + + for (auto rangePair : ranges) { + SmallBitVector bits(bv.size()); + rangePair.first.setBits(bits); + switch (rangePair.second) { + case IsInterestingUser::LifetimeEndingUse: { + LLVM_DEBUG( + llvm::dbgs() + << " Lifetime ending use! Recording final consume!\n"); + // If we have a consuming use, when we stop at the consuming use we want + // the value to still be around. We only want the value to be + // invalidated once the consume operation has occured. Thus we always + // place the debug_value undef strictly after the consuming operation. + if (auto *ti = dyn_cast(inst)) { + for (auto *succBlock : ti->getSuccessorBlocks()) { + insertUndefDebugValue(&succBlock->front()); + } + } else { + insertUndefDebugValue(inst->getNextInstruction()); } + consumes.recordFinalConsume(inst, bits); continue; } + case IsInterestingUser::NonUser: + break; + case IsInterestingUser::NonLifetimeEndingUse: + LLVM_DEBUG(llvm::dbgs() << " NonLifetimeEndingUse! " + "inserting destroy before instruction!\n"); + // If we are dealing with an inout parameter, we will have modeled our + // last use by treating a return inst as a last use. Since it doesn't + // have any successors, this results in us not inserting any + // destroy_addr. + if (isa(inst)) { + auto *block = inst->getParent(); + for (auto *succBlock : block->getSuccessorBlocks()) { + + auto *insertPt = &*succBlock->begin(); + insertDestroyBeforeInstruction(addressUseState, insertPt, + liveness.getRootValue(), bits, + consumes); + // We insert the debug_value undef /after/ the last use since we + // want the value to be around when we stop at the last use + // instruction. + insertUndefDebugValue(insertPt); + } + continue; + } - auto *insertPt = inst->getNextInstruction(); - insertDestroyBeforeInstruction(addressUseState, insertPt, - liveness.getRootValue(), bv, consumes); - // We insert the debug_value undef /after/ the last use since we want - // the value to be around when we stop at the last use instruction. - insertUndefDebugValue(insertPt); - continue; + auto *insertPt = inst->getNextInstruction(); + insertDestroyBeforeInstruction(addressUseState, insertPt, + liveness.getRootValue(), bits, consumes); + // We insert the debug_value undef /after/ the last use since we want + // the value to be around when we stop at the last use instruction. + insertUndefDebugValue(insertPt); + continue; + } } } @@ -2545,8 +2562,9 @@ void MoveOnlyAddressCheckerPImpl::rewriteUses( // Process destroys for (auto destroyPair : addressUseState.destroys) { /// Is this destroy instruction a final consuming use? - bool isFinalConsume = - consumes.claimConsume(destroyPair.first, destroyPair.second); + SmallBitVector bits(liveness.getNumSubElements()); + destroyPair.second.setBits(bits); + bool isFinalConsume = consumes.claimConsume(destroyPair.first, bits); // Remove destroys that are not the final consuming use. if (!isFinalConsume) { @@ -2583,22 +2601,26 @@ void MoveOnlyAddressCheckerPImpl::rewriteUses( for (auto reinitPair : addressUseState.reinitInsts) { if (!isReinitToInitConvertibleInst(reinitPair.first)) continue; - if (!consumes.claimConsume(reinitPair.first, reinitPair.second)) + SmallBitVector bits(liveness.getNumSubElements()); + reinitPair.second.setBits(bits); + if (!consumes.claimConsume(reinitPair.first, bits)) convertMemoryReinitToInitForm(reinitPair.first, debugVar); } // Check all takes. for (auto takeInst : addressUseState.takeInsts) { - bool claimedConsume = - consumes.claimConsume(takeInst.first, takeInst.second); + SmallBitVector bits(liveness.getNumSubElements()); + takeInst.second.setBits(bits); + bool claimedConsume = consumes.claimConsume(takeInst.first, bits); (void)claimedConsume; assert(claimedConsume && "Should claim all copies?!"); } // Then rewrite all copy insts to be takes and claim them. for (auto copyInst : addressUseState.copyInsts) { - bool claimedConsume = - consumes.claimConsume(copyInst.first, copyInst.second); + SmallBitVector bits(liveness.getNumSubElements()); + copyInst.second.setBits(bits); + bool claimedConsume = consumes.claimConsume(copyInst.first, bits); if (!claimedConsume) { llvm::errs() << "Found consume that was not recorded as a 'claimed consume'!\n"; diff --git a/lib/SILOptimizer/Mandatory/MoveOnlyBorrowToDestructureUtils.cpp b/lib/SILOptimizer/Mandatory/MoveOnlyBorrowToDestructureUtils.cpp index 9f01ba50013d9..b328701d6fcbb 100644 --- a/lib/SILOptimizer/Mandatory/MoveOnlyBorrowToDestructureUtils.cpp +++ b/lib/SILOptimizer/Mandatory/MoveOnlyBorrowToDestructureUtils.cpp @@ -317,9 +317,10 @@ bool Implementation::gatherUses(SILValue value) { } LLVM_DEBUG(llvm::dbgs() << " Found non lifetime ending use!\n"); - blocksToUses.insert( - nextUse->getParentBlock(), - {nextUse, {*leafRange, false /*is lifetime ending*/}}); + blocksToUses.insert(nextUse->getParentBlock(), + {nextUse, + {liveness.getNumSubElements(), *leafRange, + false /*is lifetime ending*/}}); liveness.updateForUse(nextUse->getUser(), *leafRange, false /*is lifetime ending*/); instToInterestingOperandIndexMap.insert(nextUse->getUser(), nextUse); @@ -344,7 +345,9 @@ bool Implementation::gatherUses(SILValue value) { LLVM_DEBUG(llvm::dbgs() << " Found lifetime ending use!\n"); destructureNeedingUses.push_back(nextUse); blocksToUses.insert(nextUse->getParentBlock(), - {nextUse, {*leafRange, true /*is lifetime ending*/}}); + {nextUse, + {liveness.getNumSubElements(), *leafRange, + true /*is lifetime ending*/}}); liveness.updateForUse(nextUse->getUser(), *leafRange, true /*is lifetime ending*/); instToInterestingOperandIndexMap.insert(nextUse->getUser(), nextUse); @@ -381,9 +384,10 @@ bool Implementation::gatherUses(SILValue value) { // Otherwise, treat it as a normal use. LLVM_DEBUG(llvm::dbgs() << " Treating non-begin_borrow borrow as " "a non lifetime ending use!\n"); - blocksToUses.insert( - nextUse->getParentBlock(), - {nextUse, {*leafRange, false /*is lifetime ending*/}}); + blocksToUses.insert(nextUse->getParentBlock(), + {nextUse, + {liveness.getNumSubElements(), *leafRange, + false /*is lifetime ending*/}}); liveness.updateForUse(nextUse->getUser(), *leafRange, false /*is lifetime ending*/); instToInterestingOperandIndexMap.insert(nextUse->getUser(), nextUse); @@ -989,13 +993,13 @@ void Implementation::rewriteUses(InstructionDeleter *deleter) { if (auto operandList = blocksToUses.find(block)) { // If we do, gather up the bits that we need. for (auto operand : *operandList) { - auto &subEltSpan = operand.second.subEltSpan; + auto &liveBits = operand.second.liveBits; LLVM_DEBUG(llvm::dbgs() << " Found need operand " << operand.first->getOperandNumber() - << " of inst: " << *operand.first->getUser() - << " Needs bits: " << subEltSpan << '\n'); - bitsNeededInBlock.set(subEltSpan.startEltOffset, - subEltSpan.endEltOffset); + << " of inst: " << *operand.first->getUser()); + for (auto bit : liveBits.set_bits()) { + bitsNeededInBlock.set(bit); + } seenOperands.insert(operand.first); } } diff --git a/test/SILOptimizer/moveonly_addresschecker.sil b/test/SILOptimizer/moveonly_addresschecker.sil index 65b098e7c3418..da86665e997b7 100644 --- a/test/SILOptimizer/moveonly_addresschecker.sil +++ b/test/SILOptimizer/moveonly_addresschecker.sil @@ -575,3 +575,120 @@ bb0(%0 : @owned $NonTrivialStruct): %9999 = tuple() return %9999 : $() } + +@_moveOnly +struct M { + deinit {} +} +@_moveOnly +struct M2 { + let s1: M + let s2: M +} + +sil @get_M2 : $@convention(thin) () -> @owned M2 +sil @end_addr_see_addr : $@convention(thin) (@in M, @in_guaranteed M) -> () + +/// A single instruction, apply @end_addr_see_addr, consumes one field and +/// borrows another. + +/// Varify that the consumed value isn't destroyed twice and that the borrowed +/// value isn't destroyed before it's used. +/// +/// Note: This test case doesn't have valid SIL (#M2.s1 is consumed twice), but +/// the invalidity wasn't the cause of the miscompile. With the fix, this +/// is transformed into valid SIL. +/// +/// Once verification is enabled, feel free to modify this test case to +/// have a destroy_addr of %second_addr instead, though not that this will +/// no longer verify the fix. +// CHECK-LABEL: sil [ossa] @rdar110909290 : {{.*}} { +// CHECK: [[STACK:%[^,]+]] = alloc_stack $M2 +// CHECK: [[GET_M2:%[^,]+]] = function_ref @get_M2 +// CHECK: [[M2:%[^,]+]] = apply [[GET_M2]]() +// CHECK: store [[M2]] to [init] [[STACK]] : $*M2 +// CHECK-NOT: destroy_addr +// CHECK: [[S1_ADDR:%[^,]+]] = struct_element_addr [[STACK]] : $*M2, #M2.s1 +// CHECK: [[S2_ADDR:%[^,]+]] = struct_element_addr [[STACK]] : $*M2, #M2.s2 +// CHECK: [[END_ADDR_SEE_ADDR:%[^,]+]] = function_ref @end_addr_see_addr +// CHECK: apply [[END_ADDR_SEE_ADDR]]([[S1_ADDR]], [[S2_ADDR]]) +// CHECK-NOT: struct_element_addr [[STACK]] : $*M2, #M2.s1 +// CHECK: [[S2_ADDR_2:%[^,]+]] = struct_element_addr [[STACK]] : $*M2, #M2.s2 +// CHECK: destroy_addr [[S2_ADDR_2]] : $*M +// CHECK-LABEL: } // end sil function 'rdar110909290' +sil [ossa] @rdar110909290 : $@convention(thin) () -> () { +bb0: + %0 = alloc_stack $M2 + %1 = mark_must_check [consumable_and_assignable] %0 : $*M2 + %3 = function_ref @get_M2 : $@convention(thin) () -> @owned M2 + %4 = apply %3() : $@convention(thin) () -> @owned M2 + store %4 to [init] %1 : $*M2 + %first_addr = struct_element_addr %1 : $*M2, #M2.s1 + %second_addr = struct_element_addr %1 : $*M2, #M2.s2 + %end_addr_see_addr = function_ref @end_addr_see_addr : $@convention(thin) (@in M, @in_guaranteed M) -> () + apply %end_addr_see_addr(%first_addr, %second_addr) : $@convention(thin) (@in M, @in_guaranteed M) -> () + destroy_addr %1 : $*M2 + dealloc_stack %0 : $*M2 + %22 = tuple () + return %22 : $() +} + +@_moveOnly +struct M4 { + let s1: M + let s2: M + let s3: M + let s4: M +} + +sil @get_M4 : $@convention(thin) () -> @owned M4 +sil @end_2 : $@convention(thin) (@owned M, @owned M) -> () +sil @see_addr_2 : $@convention(thin) (@in_guaranteed M, @in_guaranteed M) -> () + + +/// Two non-contiguous fields (#M4.s2, #M4.s4) are borrowed by @see_addr_2. +/// Two non-contiguous fields (#M4.s1, #M$.s3) are consumed by @end_2. +/// +/// Verify that #M4.s2 and #M4.s4 both survive past the apply of @see_addr_2. +// CHECK-LABEL: sil [ossa] @rdar110676577 : {{.*}} { +// CHECK: [[STACK:%[^,]+]] = alloc_stack $M4 +// CHECK: [[GET_M4:%[^,]+]] = function_ref @get_M4 +// CHECK: [[M4:%[^,]+]] = apply [[GET_M4]]() : $@convention(thin) () -> @owned M4 +// CHECK: store [[M4]] to [init] [[STACK]] : $*M4 +// CHECK: [[M4_S2_ADDR:%[^,]+]] = struct_element_addr [[STACK]] : $*M4, #M4.s2 +// CHECK: [[M4_S4_ADDR:%[^,]+]] = struct_element_addr [[STACK]] : $*M4, #M4.s4 +// CHECK: [[SEE_ADDR_2:%[^,]+]] = function_ref @see_addr_2 +// CHECK: apply [[SEE_ADDR_2]]([[M4_S2_ADDR]], [[M4_S4_ADDR]]) +// HECK: [[M4_S4_ADDR_2:%[^,]+]] = struct_element_addr [[STACK]] : $*M4, #M4.s4 +// HECK: destroy_addr [[M4_S4_ADDR_2]] +// CHECK: [[M4_S2_ADDR_2:%[^,]+]] = struct_element_addr [[STACK]] : $*M4, #M4.s2 +// CHECK: destroy_addr [[M4_S2_ADDR_2]] +// CHECK: [[M4_S1_ADDR:%[^,]+]] = struct_element_addr [[STACK]] : $*M4, #M4.s1 +// CHECK: [[M4_S1:%[^,]+]] = load [take] [[M4_S1_ADDR]] : $*M +// CHECK: [[M4_S3_ADDR:%[^,]+]] = struct_element_addr [[STACK]] : $*M4, #M4.s3 +// CHECK: [[M4_S3:%[^,]+]] = load [take] [[M4_S3_ADDR]] : $*M +// CHECK: [[END_2:%[^,]+]] = function_ref @end_2 +// CHECK: apply [[END_2]]([[M4_S1]], [[M4_S3]]) +// CHECK-LABEL: } // end sil function 'rdar110676577' +sil [ossa] @rdar110676577 : $@convention(thin) () -> () { +bb0: + %0 = alloc_stack $M4 + %1 = mark_must_check [consumable_and_assignable] %0 : $*M4 + %3 = function_ref @get_M4 : $@convention(thin) () -> @owned M4 + %4 = apply %3() : $@convention(thin) () -> @owned M4 + store %4 to [init] %1 : $*M4 + %6 = struct_element_addr %1 : $*M4, #M4.s2 + %6a = struct_element_addr %1 : $*M4, #M4.s4 + %see_addr_2 = function_ref @see_addr_2 : $@convention(thin) (@in_guaranteed M, @in_guaranteed M) -> () + apply %see_addr_2(%6, %6a) : $@convention(thin) (@in_guaranteed M, @in_guaranteed M) -> () + %12 = struct_element_addr %1 : $*M4, #M4.s1 + %13 = load [copy] %12 : $*M + %14 = struct_element_addr %1 : $*M4, #M4.s3 + %15 = load [copy] %14 : $*M + %16 = function_ref @end_2 : $@convention(thin) (@owned M, @owned M) -> () + %17 = apply %16(%13, %15) : $@convention(thin) (@owned M, @owned M) -> () + destroy_addr %1 : $*M4 + dealloc_stack %0 : $*M4 + %22 = tuple () + return %22 : $() +} From b97712c422637590937acf8b4e41e5c3dbf9e767 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Thu, 8 Jun 2023 10:58:42 -0700 Subject: [PATCH 38/41] [MoveOnlyAddressChecker] NFC: Promoted assertion. Dumped more info and called llvm_unreachable on bad state. --- lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp b/lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp index bb9ab67d4bcb2..1c82a3000bc49 100644 --- a/lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp +++ b/lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp @@ -2613,7 +2613,12 @@ void MoveOnlyAddressCheckerPImpl::rewriteUses( takeInst.second.setBits(bits); bool claimedConsume = consumes.claimConsume(takeInst.first, bits); (void)claimedConsume; - assert(claimedConsume && "Should claim all copies?!"); + if (!claimedConsume) { + llvm::errs() + << "Found consume that was not recorded as a 'claimed consume'!\n"; + llvm::errs() << "Unrecorded consume: " << *takeInst.first; + llvm_unreachable("Standard compiler abort?!"); + } } // Then rewrite all copy insts to be takes and claim them. From eaf4560cd7c2dea4a1f1ed20a1c811760082fbba Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Mon, 12 Jun 2023 15:45:25 -0700 Subject: [PATCH 39/41] [MoveOnlyAddressChecker] Maximize lifetimes. Previously, the checker inserted destroys after each last use. Here, extend the lifetimes of fields as far as possible within their original (unchecked) limits. rdar://99681073 --- .../Mandatory/MoveOnlyAddressCheckerUtils.cpp | 320 +++++ .../moveonly_address_maximize.swift | 307 +++++ test/Interpreter/moveonly_maximize.swift | 33 + test/SILOptimizer/discard_checking.swift | 45 +- test/SILOptimizer/moveonly_addresschecker.sil | 46 +- .../moveonly_addresschecker_debuginfo.sil | 6 +- .../moveonly_addresschecker_maximize.sil | 1130 +++++++++++++++++ test/SILOptimizer/moveonly_lifetime.swift | 9 +- 8 files changed, 1842 insertions(+), 54 deletions(-) create mode 100644 test/Interpreter/moveonly_address_maximize.swift create mode 100644 test/Interpreter/moveonly_maximize.swift create mode 100644 test/SILOptimizer/moveonly_addresschecker_maximize.sil diff --git a/lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp b/lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp index 1c82a3000bc49..8675e82417bee 100644 --- a/lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp +++ b/lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp @@ -642,6 +642,15 @@ namespace { struct UseState { MarkMustCheckInst *address; + /// The number of fields in the exploded type. Set in initializeLiveness. + unsigned fieldCount = UINT_MAX; + + /// The blocks that consume fields of the value. + /// + /// A map from blocks to a bit vector recording which fields were destroyed + /// in each. + llvm::SmallMapVector consumingBlocks; + /// A map from destroy_addr to the part of the type that it destroys. llvm::SmallMapVector destroys; @@ -750,6 +759,7 @@ struct UseState { void clear() { address = nullptr; + consumingBlocks.clear(); destroys.clear(); livenessUses.clear(); borrows.clear(); @@ -806,6 +816,14 @@ struct UseState { } } + void recordConsumingBlock(SILBasicBlock *block, TypeTreeLeafTypeRange range) { + auto iter = consumingBlocks.find(block); + if (iter == consumingBlocks.end()) { + iter = consumingBlocks.insert({block, SmallBitVector(fieldCount)}).first; + } + range.setBits(iter->second); + } + void initializeLiveness(FieldSensitiveMultiDefPrunedLiveRange &prunedLiveness); @@ -907,6 +925,8 @@ struct UseState { void UseState::initializeLiveness( FieldSensitiveMultiDefPrunedLiveRange &liveness) { + fieldCount = liveness.getNumSubElements(); + // We begin by initializing all of our init uses. for (auto initInstAndValue : initInsts) { LLVM_DEBUG(llvm::dbgs() << "Found def: " << *initInstAndValue.first); @@ -1019,6 +1039,8 @@ void UseState::initializeLiveness( if (!isReinitToInitConvertibleInst(reinitInstAndValue.first)) { liveness.updateForUse(reinitInstAndValue.first, reinitInstAndValue.second, false /*lifetime ending*/); + recordConsumingBlock(reinitInstAndValue.first->getParent(), + reinitInstAndValue.second); LLVM_DEBUG(llvm::dbgs() << "Added liveness for reinit: " << *reinitInstAndValue.first; liveness.print(llvm::dbgs())); @@ -1030,6 +1052,8 @@ void UseState::initializeLiveness( for (auto takeInstAndValue : takeInsts) { liveness.updateForUse(takeInstAndValue.first, takeInstAndValue.second, true /*lifetime ending*/); + recordConsumingBlock(takeInstAndValue.first->getParent(), + takeInstAndValue.second); LLVM_DEBUG(llvm::dbgs() << "Added liveness for take: " << *takeInstAndValue.first; liveness.print(llvm::dbgs())); @@ -1037,11 +1061,18 @@ void UseState::initializeLiveness( for (auto copyInstAndValue : copyInsts) { liveness.updateForUse(copyInstAndValue.first, copyInstAndValue.second, true /*lifetime ending*/); + recordConsumingBlock(copyInstAndValue.first->getParent(), + copyInstAndValue.second); LLVM_DEBUG(llvm::dbgs() << "Added liveness for copy: " << *copyInstAndValue.first; liveness.print(llvm::dbgs())); } + for (auto destroyInstAndValue : destroys) { + recordConsumingBlock(destroyInstAndValue.first->getParent(), + destroyInstAndValue.second); + } + // Do the same for our borrow and liveness insts. for (auto livenessInstAndValue : borrows) { liveness.updateForUse(livenessInstAndValue.first, @@ -1321,6 +1352,44 @@ struct MoveOnlyAddressCheckerPImpl { void handleSingleBlockDestroy(SILInstruction *destroy, bool isReinit); }; +class ExtendUnconsumedLiveness { + UseState addressUseState; + FieldSensitiveMultiDefPrunedLiveRange &liveness; + FieldSensitivePrunedLivenessBoundary &boundary; + + enum class DestroyKind { + Destroy, + Take, + Reinit, + }; + using DestroysCollection = + llvm::SmallMapVector; + using ConsumingBlocksCollection = SmallPtrSetVector; + +public: + ExtendUnconsumedLiveness(UseState addressUseState, + FieldSensitiveMultiDefPrunedLiveRange &liveness, + FieldSensitivePrunedLivenessBoundary &boundary) + : addressUseState(addressUseState), liveness(liveness), + boundary(boundary) {} + + void run(); + + void runOnField(unsigned element, DestroysCollection &destroys, + ConsumingBlocksCollection &consumingBlocks); + +private: + bool hasDefAfter(SILInstruction *inst, unsigned element); + + bool + shouldAddDestroyToLiveness(SILInstruction *destroy, unsigned element, + BasicBlockSet const &consumedAtExitBlocks, + BasicBlockSetVector const &consumedAtEntryBlocks); + + void addPreviousInstructionToLiveness(SILInstruction *inst, unsigned element, + bool lifetimeEnding); +}; + } // namespace //===----------------------------------------------------------------------===// @@ -2433,6 +2502,9 @@ void MoveOnlyAddressCheckerPImpl::insertDestroysOnBoundary( }); }; + // Control flow merge blocks used as insertion points. + llvm::DenseMap mergeBlocks; + for (auto &pair : boundary.getLastUsers()) { auto *inst = pair.first; auto &bv = pair.second; @@ -2479,6 +2551,16 @@ void MoveOnlyAddressCheckerPImpl::insertDestroysOnBoundary( if (isa(inst)) { auto *block = inst->getParent(); for (auto *succBlock : block->getSuccessorBlocks()) { + auto iter = mergeBlocks.find(succBlock); + if (iter == mergeBlocks.end()) + iter = mergeBlocks.insert({succBlock, bits}).first; + else { + SmallBitVector &alreadySetBits = iter->second; + bool hadCommon = alreadySetBits.anyCommon(bits); + alreadySetBits &= bits; + if (hadCommon) + continue; + } auto *insertPt = &*succBlock->begin(); insertDestroyBeforeInstruction(addressUseState, insertPt, @@ -2771,6 +2853,240 @@ void MoveOnlyAddressCheckerPImpl::checkForReinitAfterDiscard() { } } +void ExtendUnconsumedLiveness::run() { + ConsumingBlocksCollection consumingBlocks; + DestroysCollection destroys; + for (unsigned element = 0, count = liveness.getNumSubElements(); + element < count; ++element) { + + for (auto pair : addressUseState.consumingBlocks) { + if (pair.second.test(element)) { + consumingBlocks.insert(pair.first); + } + } + + for (auto pair : addressUseState.destroys) { + if (pair.second.contains(element)) { + destroys[pair.first] = DestroyKind::Destroy; + } + } + for (auto pair : addressUseState.takeInsts) { + if (pair.second.contains(element)) { + destroys[pair.first] = DestroyKind::Take; + } + } + for (auto pair : addressUseState.reinitInsts) { + if (pair.second.contains(element)) { + destroys[pair.first] = DestroyKind::Reinit; + } + } + + runOnField(element, destroys, consumingBlocks); + + consumingBlocks.clear(); + destroys.clear(); + } +} + +/// Extend liveness of each field as far as possible within the original live +/// range as far as possible without incurring any copies. +/// +/// The strategy has two parts. +/// +/// (1) The global analysis: +/// - Collect the blocks in which the field was live before canonicalization. +/// These are the "original" live blocks (originalLiveBlocks). +/// [Color these blocks green.] +/// - From within that collection, collect the blocks which contain a _final_ +/// consuming, non-destroy use, and their iterative successors. +/// These are the "consumed" blocks (consumedAtExitBlocks). +/// [Color these blocks red.] +/// - Extend liveness down to the boundary between originalLiveBlocks and +/// consumedAtExitBlocks blocks. +/// [Extend liveness down to the boundary between green blocks and red.] +/// - In particular, in regions of originalLiveBlocks which have no boundary +/// with consumedAtExitBlocks, liveness should be extended to its original +/// extent. +/// [Extend liveness down to the boundary between green blocks and uncolored.] +/// +/// (2) The local analysis: +/// - For in-block lifetimes, extend liveness forward from non-consuming uses +/// and dead defs to the original destroy. +void ExtendUnconsumedLiveness::runOnField( + unsigned element, DestroysCollection &destroys, + ConsumingBlocksCollection &consumingBlocks) { + SILValue currentDef = addressUseState.address; + + // First, collect the blocks that were _originally_ live. We can't use + // liveness here because it doesn't include blocks that occur before a + // destroy_addr. + BasicBlockSet originalLiveBlocks(currentDef->getFunction()); + { + // Some of the work here was already done by initializeLiveness. + // Specifically, it already discovered all blocks containing (transitive) + // uses and blocks that appear between them and the def. + // + // Seed the set with what it already discovered. + for (auto *discoveredBlock : liveness.getDiscoveredBlocks()) + originalLiveBlocks.insert(discoveredBlock); + + // Start the walk from the consuming blocks (which includes destroys as well + // as the other consuming uses). + BasicBlockWorklist worklist(currentDef->getFunction()); + for (auto *consumingBlock : consumingBlocks) { + worklist.push(consumingBlock); + } + + // Walk backwards from consuming blocks. + while (auto *block = worklist.pop()) { + if (!originalLiveBlocks.insert(block)) { + continue; + } + for (auto *predecessor : block->getPredecessorBlocks()) { + // If the block was discovered by liveness, we already added it to the + // set. + if (originalLiveBlocks.contains(predecessor)) + continue; + worklist.pushIfNotVisited(predecessor); + } + } + } + + // Second, collect the blocks which occur after a consuming use. + BasicBlockSet consumedAtExitBlocks(currentDef->getFunction()); + BasicBlockSetVector consumedAtEntryBlocks(currentDef->getFunction()); + { + // Start the forward walk from blocks which contain non-destroy consumes not + // followed by defs. + // + // Because they contain a consume not followed by a def, these are + // consumed-at-exit. + BasicBlockWorklist worklist(currentDef->getFunction()); + for (auto iterator : boundary.getLastUsers()) { + if (!iterator.second.test(element)) + continue; + auto *instruction = iterator.first; + // Skip over destroys on the boundary. + auto iter = destroys.find(instruction); + if (iter != destroys.end() && iter->second != DestroyKind::Take) { + continue; + } + // Skip over non-consuming users. + auto interestingUser = liveness.isInterestingUser(instruction, element); + assert(interestingUser != + FieldSensitivePrunedLiveness::IsInterestingUser::NonUser); + if (interestingUser != + FieldSensitivePrunedLiveness::IsInterestingUser::LifetimeEndingUse) { + continue; + } + // A consume with a subsequent def doesn't cause the block to be + // consumed-at-exit. + if (hasDefAfter(instruction, element)) + continue; + worklist.push(instruction->getParent()); + } + while (auto *block = worklist.pop()) { + consumedAtExitBlocks.insert(block); + for (auto *successor : block->getSuccessorBlocks()) { + if (!originalLiveBlocks.contains(successor)) + continue; + worklist.pushIfNotVisited(successor); + consumedAtEntryBlocks.insert(successor); + } + } + } + + // Third, find the blocks on the boundary between the originally-live blocks + // and the originally-live-but-consumed blocks. Extend liveness "to the end" + // of these blocks. + for (auto *block : consumedAtEntryBlocks) { + for (auto *predecessor : block->getPredecessorBlocks()) { + if (consumedAtExitBlocks.contains(predecessor)) + continue; + // Add "the instruction(s) before the terminator" of the predecessor to + // liveness. + addPreviousInstructionToLiveness(predecessor->getTerminator(), element, + /*lifetimeEnding*/ false); + } + } + + // Finally, preserve the destroys which weren't in the consumed region in + // place: hoisting such destroys would not avoid copies. + for (auto pair : destroys) { + auto *destroy = pair.first; + if (!shouldAddDestroyToLiveness(destroy, element, consumedAtExitBlocks, + consumedAtEntryBlocks)) + continue; + addPreviousInstructionToLiveness(destroy, element, + /*lifetimeEnding*/ false); + } +} + +bool ExtendUnconsumedLiveness::shouldAddDestroyToLiveness( + SILInstruction *destroy, unsigned element, + BasicBlockSet const &consumedAtExitBlocks, + BasicBlockSetVector const &consumedAtEntryBlocks) { + auto *block = destroy->getParent(); + bool followedByDef = hasDefAfter(destroy, element); + if (!followedByDef) { + // This destroy is the last write to the field in the block. + // + // If the block is consumed-at-exit, then there is some other consuming use + // before this destroy. Liveness can't be extended. + return !consumedAtExitBlocks.contains(block); + } + for (auto *inst = destroy->getPreviousInstruction(); inst; + inst = inst->getPreviousInstruction()) { + if (liveness.isDef(inst, element)) { + // Found the corresponding def with no intervening users. Liveness + // can be extended to the destroy. + return true; + } + auto interestingUser = liveness.isInterestingUser(inst, element); + switch (interestingUser) { + case FieldSensitivePrunedLiveness::IsInterestingUser::NonUser: + break; + case FieldSensitivePrunedLiveness::IsInterestingUser::NonLifetimeEndingUse: + // The first use seen is non-consuming. Liveness can be extended to the + // destroy. + return true; + break; + case FieldSensitivePrunedLiveness::IsInterestingUser::LifetimeEndingUse: + // Found a consuming use. Liveness can't be extended to the destroy + // (without creating a copy and triggering a diagnostic). + return false; + break; + } + } + // Found no uses or defs between the destroy and the top of the block. If the + // block was not consumed at entry, liveness can be extended to the destroy. + return !consumedAtEntryBlocks.contains(block); +} + +bool ExtendUnconsumedLiveness::hasDefAfter(SILInstruction *start, + unsigned element) { + // NOTE: Start iteration at \p start, not its sequel, because + // it might be both a consuming use and a def. + for (auto *inst = start; inst; inst = inst->getNextInstruction()) { + if (liveness.isDef(inst, element)) + return true; + } + return false; +} + +void ExtendUnconsumedLiveness::addPreviousInstructionToLiveness( + SILInstruction *inst, unsigned element, bool lifetimeEnding) { + auto range = TypeTreeLeafTypeRange(element, element + 1); + if (auto *previous = inst->getPreviousInstruction()) { + liveness.updateForUse(previous, range, lifetimeEnding); + } else { + for (auto *predecessor : inst->getParent()->getPredecessorBlocks()) { + liveness.updateForUse(predecessor->getTerminator(), range, + lifetimeEnding); + } + } +} + bool MoveOnlyAddressCheckerPImpl::performSingleCheck( MarkMustCheckInst *markedAddress) { SWIFT_DEFER { diagnosticEmitter.clearUsesWithDiagnostic(); }; @@ -2865,6 +3181,10 @@ bool MoveOnlyAddressCheckerPImpl::performSingleCheck( FieldSensitivePrunedLivenessBoundary boundary(liveness.getNumSubElements()); liveness.computeBoundary(boundary); + ExtendUnconsumedLiveness extension(addressUseState, liveness, boundary); + extension.run(); + boundary.clear(); + liveness.computeBoundary(boundary); insertDestroysOnBoundary(markedAddress, liveness, boundary); checkForReinitAfterDiscard(); rewriteUses(markedAddress, liveness, boundary); diff --git a/test/Interpreter/moveonly_address_maximize.swift b/test/Interpreter/moveonly_address_maximize.swift new file mode 100644 index 0000000000000..8ec5548ba3738 --- /dev/null +++ b/test/Interpreter/moveonly_address_maximize.swift @@ -0,0 +1,307 @@ +// RUN: %target-run-simple-swift(-Xfrontend -sil-verify-all) | %FileCheck %s +// RUN: %target-run-simple-swift(-O -Xfrontend -sil-verify-all) | %FileCheck %s + +struct S : ~Copyable { + let s: String + init(_ s: String) { self.s = s } + deinit { + print("destroying \(s)") + } +} +struct S2 : ~Copyable { + var s1: S + var s2: S + init(_ s: String) { + self.s1 = S("\(s).s1") + self.s2 = S("\(s).s2") + } +} +struct S3 : ~Copyable { + var s1: S + var s2: S + var s3: S + init(_ s: String) { + self.s1 = S("\(s).s1") + self.s2 = S("\(s).s2") + self.s3 = S("\(s).s3") + } +} + +func consumeVal(_ s: consuming S) {} +func consumeVal(_ s: consuming S2) {} +func borrowVal(_ s: borrowing S) {} +func borrowVal(_ s: borrowing S2) {} + +func marker(_ s: String) { + print("\(#function): \(s)") +} + +// Simple test that makes sure that we still after we consume have the lifetime +// of s be completely consumed by consumeVal. +// CHECK: destroying simpleTestVar().first.s1 +// CHECK: destroying simpleTestVar().first.s2 +// CHECK: destroying simpleTestVar().second.s1 +// CHECK: destroying simpleTestVar().second.s2 +// CHECK: marker(_:): simpleTestVar().1 +@_silgen_name("simpleTestVar") +func simpleTestVar() { + var s = S2("\(#function).first") + s = S2("\(#function).second") + consumeVal(s) // Lifetime of s should end here before end of scope. + marker("\(#function).1") +} + +// Simple test that proves that we can maximize lifetimes in a field sensitive +// manner. Since we only consume s.s1, s.s2's lifetime should still be maximized +// and be at end of scope. +// CHECK: destroying simpleTestVar2().first.s1 +// CHECK: destroying simpleTestVar2().first.s2 +// CHECK: destroying simpleTestVar2().second.s1 +// CHECK: marker(_:): simpleTestVar2().1 +// CHECK: destroying simpleTestVar2().second.s2 +func simpleTestVar2() { + var s = S2("\(#function).first") + s = S2("\(#function).second") + consumeVal(s.s1) // Lifetime of s1 should end here. + marker("\(#function).1") + // Lifetime of s2 should end at end of scope after marker. +} + +// In this case, we consume all of s by consuming s.s1 and s.s2 separately, so +// all lifetimes should be done before marker. +// CHECK: destroying simpleTestVar3().first.s1 +// CHECK: destroying simpleTestVar3().first.s2 +// CHECK: destroying simpleTestVar3().second.s1 +// CHECK: destroying simpleTestVar3().second.s2 +// CHECK: marker(_:): simpleTestVar3().1 +func simpleTestVar3() { + var s = S2("\(#function).first") + s = S2("\(#function).second") + consumeVal(s.s1) + consumeVal(s.s2) + marker("\(#function).1") // Lifetimes should end before marker. +} + +// In this case, we completely consume s and then reinitialize s implying we +// need to deal with two disjoint lifetimes. The second lifetime of s should end +// after marker. +// CHECK: destroying simpleTestVar3a().first.s1 +// CHECK: destroying simpleTestVar3a().first.s2 +// CHECK: destroying simpleTestVar3a().second.s1 +// CHECK: destroying simpleTestVar3a().second.s2 +// CHECK: marker(_:): simpleTestVar3a().1 +// CHECK: marker(_:): simpleTestVar3a().2 +// CHECK: destroying simpleTestVar3a().third.s1 +// CHECK: destroying simpleTestVar3a().third.s2 +func simpleTestVar3a() { + var s = S2("\(#function).first") + s = S2("\(#function).second") + consumeVal(s.s1) + consumeVal(s.s2) + + marker("\(#function).1") + + s = S2("\(#function).third") + marker("\(#function).2") +} + +// In this case, we have another borrowVal of s.s2. That should still let s.s2's +// lifetime end after marker. +// CHECK: destroying simpleTestVar3b().first.s1 +// CHECK: destroying simpleTestVar3b().first.s2 +// CHECK: destroying simpleTestVar3b().second.s1 +// CHECK: marker(_:): simpleTestVar3b().1 +// CHECK: destroying simpleTestVar3b().second.s2 +func simpleTestVar3b() { + var s = S2("\(#function).first") + s = S2("\(#function).second") + consumeVal(s.s1) + borrowVal(s.s2) + marker("\(#function).1") // s2 should end its lifetime after marker. +} + +// In this case, we are testing reinitialization and making sure that we can +// handle two initializations properly. We also are testing conditional merge +// logic. Since in both cases below s is completely consumed in b, s's lifetime +// would end at marker. + +// CHECK: destroying simpleTestVar4(_:_:)[false, false)].first.s1 +// CHECK: destroying simpleTestVar4(_:_:)[false, false)].first.s2 +// CHECK: marker(_:): simpleTestVar4(_:_:)[false, false)].1 +// CHECK: destroying simpleTestVar4(_:_:)[false, false)].second.s1 +// CHECK: destroying simpleTestVar4(_:_:)[false, false)].second.s2 +// CHECK: destroying simpleTestVar4(_:_:)[false, false)].third.s1 +// CHECK: destroying simpleTestVar4(_:_:)[false, false)].third.s2 +// CHECK: marker(_:): simpleTestVar4(_:_:)[false, false)].2 + +// CHECK: destroying simpleTestVar4(_:_:)[false, true)].first.s1 +// CHECK: destroying simpleTestVar4(_:_:)[false, true)].first.s2 +// CHECK: marker(_:): simpleTestVar4(_:_:)[false, true)].1 +// CHECK: destroying simpleTestVar4(_:_:)[false, true)].second.s1 +// CHECK: destroying simpleTestVar4(_:_:)[false, true)].second.s2 +// CHECK: destroying simpleTestVar4(_:_:)[false, true)].third.s1 +// CHECK: destroying simpleTestVar4(_:_:)[false, true)].third.s2 + +// CHECK: destroying simpleTestVar4(_:_:)[true, false)].first.s1 +// CHECK: destroying simpleTestVar4(_:_:)[true, false)].first.s2 +// CHECK: destroying simpleTestVar4(_:_:)[true, false)].second.s1 +// CHECK: destroying simpleTestVar4(_:_:)[true, false)].second.s2 +// CHECK: destroying simpleTestVar4(_:_:)[true, false)].third.s1 +// CHECK: destroying simpleTestVar4(_:_:)[true, false)].third.s2 +// CHECK: marker(_:): simpleTestVar4(_:_:)[true, false)].2 + +// CHECK: destroying simpleTestVar4(_:_:)[true, true)].first.s1 +// CHECK: destroying simpleTestVar4(_:_:)[true, true)].first.s2 +// CHECK: destroying simpleTestVar4(_:_:)[true, true)].second.s1 +// CHECK: destroying simpleTestVar4(_:_:)[true, true)].second.s2 +// CHECK: destroying simpleTestVar4(_:_:)[true, true)].third.s1 +// CHECK: destroying simpleTestVar4(_:_:)[true, true)].third.s2 +func simpleTestVar4(_ b1: Bool, _ b2: Bool) { + var s = S2("\(#function)[\(b1), \(b2))].first") + s = S2("\(#function)[\(b1), \(b2))].second") + + if b1 { + consumeVal(s) + } else { + marker("\(#function)[\(b1), \(b2))].1") + // S's lifetime should end after marker in this block. + } + + s = S2("\(#function)[\(b1), \(b2))].third") + + if b2 { + consumeVal(s) + } else { + marker("\(#function)[\(b1), \(b2))].2") + // S's 2nd lifetime should end after marker in this block. + } +} + +// This test is similar to the previous, except we are consuming different +// values along the if/else branch that completely covers the value. As a result +// of this, we need to end the lifetime of s in the branches. +// CHECK: destroying simpleTestVar6(_:)[false].first.s1 +// CHECK: destroying simpleTestVar6(_:)[false].first.s2 +// CHECK: destroying simpleTestVar6(_:)[false].second.s2 +// CHECK: marker(_:): simpleTestVar6(_:)[false].2 +// CHECK: destroying simpleTestVar6(_:)[false].second.s1 +// CHECK: destroying simpleTestVar6(_:)[false].third.s1 +// CHECK: destroying simpleTestVar6(_:)[false].third.s2 + +// CHECK: destroying simpleTestVar6(_:)[true].first.s1 +// CHECK: destroying simpleTestVar6(_:)[true].first.s2 +// CHECK: destroying simpleTestVar6(_:)[true].second.s1 +// CHECK: marker(_:): simpleTestVar6(_:)[true].1 +// CHECK: destroying simpleTestVar6(_:)[true].second.s2 +// CHECK: destroying simpleTestVar6(_:)[true].third.s1 +// CHECK: destroying simpleTestVar6(_:)[true].third.s2 +func simpleTestVar6(_ b: Bool) { + var s = S2("\(#function)[\(b)].first") + s = S2("\(#function)[\(b)].second") + + if b { + consumeVal(s.s1) // end of s.s1's lifetime. + marker("\(#function)[\(b)].1") + // s.s2 should end here. + } else { + consumeVal(s.s2) // end of s.s2's lifetime + marker("\(#function)[\(b)].2") + // end of s.s1's lifetime should end after marker. + } + + s = S2("\(#function)[\(b)].third") +} + +// In this case, we are using S3 implying we have three fields. So despite the +// fact that we are deleting these two values in the if-else branches, s3's +// lifetime needs to end at end of scope. +// CHECK: destroying simpleTestVar6a(_:)[false].first.s1 +// CHECK: destroying simpleTestVar6a(_:)[false].first.s2 +// CHECK: destroying simpleTestVar6a(_:)[false].first.s3 +// CHECK: destroying simpleTestVar6a(_:)[false].second.s2 +// CHECK: marker(_:): simpleTestVar6a(_:)[false].2 +// CHECK: destroying simpleTestVar6a(_:)[false].second.s1 +// CHECK: marker(_:): simpleTestVar6a(_:)[false].3 +// CHECK: destroying simpleTestVar6a(_:)[false].second.s3 + +// CHECK: destroying simpleTestVar6a(_:)[true].first.s1 +// CHECK: destroying simpleTestVar6a(_:)[true].first.s2 +// CHECK: destroying simpleTestVar6a(_:)[true].first.s3 +// CHECK: destroying simpleTestVar6a(_:)[true].second.s1 +// CHECK: marker(_:): simpleTestVar6a(_:)[true].1 +// CHECK: destroying simpleTestVar6a(_:)[true].second.s2 +// CHECK: marker(_:): simpleTestVar6a(_:)[true].3 +// CHECK: destroying simpleTestVar6a(_:)[true].second.s3 +func simpleTestVar6a(_ b: Bool) { + var s = S3("\(#function)[\(b)].first") + s = S3("\(#function)[\(b)].second") + + if b { + consumeVal(s.s1) // end of s.s1's lifetime. + marker("\(#function)[\(b)].1") + // s.s2 should end here. + } else { + consumeVal(s.s2) // end of s.s2's lifetime + marker("\(#function)[\(b)].2") + // end of s.s1's lifetime should end after marker. + } + + marker("\(#function)[\(b)].3") + // s.s3's lifetime should end here. +} + +// In this case, we are using S3, but we are consuming two disjoint parts of S +// in the if statement so we cover again completely. +// CHECK: destroying simpleTestVar6b(_:)[false].first.s1 +// CHECK: destroying simpleTestVar6b(_:)[false].first.s2 +// CHECK: destroying simpleTestVar6b(_:)[false].first.s3 +// CHECK: destroying simpleTestVar6b(_:)[false].second.s2 +// CHECK: marker(_:): simpleTestVar6b(_:)[false].2 +// CHECK: destroying simpleTestVar6b(_:)[false].second.s3 +// CHECK: destroying simpleTestVar6b(_:)[false].second.s1 +// CHECK: marker(_:): simpleTestVar6b(_:)[false].3 + +// CHECK: destroying simpleTestVar6b(_:)[true].first.s1 +// CHECK: destroying simpleTestVar6b(_:)[true].first.s2 +// CHECK: destroying simpleTestVar6b(_:)[true].first.s3 +// CHECK: destroying simpleTestVar6b(_:)[true].second.s1 +// CHECK: destroying simpleTestVar6b(_:)[true].second.s3 +// CHECK: marker(_:): simpleTestVar6b(_:)[true].1 +// CHECK: destroying simpleTestVar6b(_:)[true].second.s2 +// CHECK: marker(_:): simpleTestVar6b(_:)[true].3 +func simpleTestVar6b(_ b: Bool) { + var s = S3("\(#function)[\(b)].first") + s = S3("\(#function)[\(b)].second") + + if b { + consumeVal(s.s1) // end of s.s1's lifetime. + consumeVal(s.s3) // end of s.s3's lifetime + marker("\(#function)[\(b)].1") + // s.s2 should end here. + } else { + consumeVal(s.s2) // end of s.s2's lifetime + marker("\(#function)[\(b)].2") + // end of s.s1's lifetime should end after marker. + // end of s.s3's lifetime should end after marker. + } + + marker("\(#function)[\(b)].3") +} + + +simpleTestVar() +simpleTestVar2() +simpleTestVar3() +simpleTestVar3a() +simpleTestVar3b() +simpleTestVar4(false, false) +simpleTestVar4(false, true) +simpleTestVar4(true, false) +simpleTestVar4(true, true) +simpleTestVar6(false) +simpleTestVar6(true) +simpleTestVar6a(false) +simpleTestVar6a(true) +simpleTestVar6b(false) +simpleTestVar6b(true) + diff --git a/test/Interpreter/moveonly_maximize.swift b/test/Interpreter/moveonly_maximize.swift new file mode 100644 index 0000000000000..d313c5d501a19 --- /dev/null +++ b/test/Interpreter/moveonly_maximize.swift @@ -0,0 +1,33 @@ +// RUN: %target-run-simple-swift(-Xfrontend -sil-verify-all) | %FileCheck %s +// RUN: %target-run-simple-swift(-O -Xfrontend -sil-verify-all) | %FileCheck %s + +// REQUIRES: executable_test +struct Alice: ~Copyable { + var age: Int + + init(age: Int) { + print("INIT"); + self.age = age + } + + deinit { print("DEINIT") } +} + +func eatMe(_ alice: consuming Alice) { + print(" start") + print(" age:", alice.age) + print(" end") +} + +func doit() { + let alice = Alice(age: 10) + eatMe(alice) +} + +doit() + +// CHECK: INIT +// CHECK: start +// CHECK: age: 10 +// CHECK: end +// CHECK: DEINIT diff --git a/test/SILOptimizer/discard_checking.swift b/test/SILOptimizer/discard_checking.swift index 322c1eb66487c..fbbd5d180a5af 100644 --- a/test/SILOptimizer/discard_checking.swift +++ b/test/SILOptimizer/discard_checking.swift @@ -125,8 +125,8 @@ struct Basics: ~Copyable { if case .red = c { discard self // expected-note {{discarded self here}} } else { - mutator() // expected-error {{must consume 'self' before exiting method that discards self}} - throw E.someError // <- better spot + mutator() + throw E.someError // expected-error {{must consume 'self' before exiting method that discards self}} } } @@ -165,7 +165,7 @@ struct Basics: ~Copyable { } } - consuming func test8_stillMissingAConsume1(_ c: Color) throws { + consuming func test8_stillMissingAConsume1(_ c: Color) throws { // expected-error {{must consume 'self' before exiting method that discards self}} if case .red = c { discard self // expected-note {{discarded self here}} return @@ -174,7 +174,7 @@ struct Basics: ~Copyable { _ = consume self fatalError("hi") } - } // expected-error {{must consume 'self' before exiting method that discards self}} + } consuming func test8_stillMissingAConsume2(_ c: Color) throws { if case .red = c { @@ -212,10 +212,10 @@ struct Basics: ~Copyable { return } catch { print("hi") - return // <- better spot!! + return // expected-error {{must consume 'self' before exiting method that discards self}} } _ = consume self // expected-warning {{will never be executed}} - } // expected-error {{must consume 'self' before exiting method that discards self}} + } consuming func test9_fixed(_ c: Color) throws { if case .red = c { @@ -238,20 +238,20 @@ struct Basics: ~Copyable { consuming func test10(_ c: Color) throws { if case .red = c { - discard self // expected-note {{discarded self here}} + discard self // expected-note 2{{discarded self here}} return } do { - throw E.someError // expected-error {{must consume 'self' before exiting method that discards self}} + throw E.someError } catch E.someError { - return // <- better spot + return // expected-error {{must consume 'self' before exiting method that discards self}} } catch { - return // <- ok spot + return // expected-error {{must consume 'self' before exiting method that discards self}} } } - consuming func test11(_ c: Color) { + consuming func test11(_ c: Color) { // expected-error {{must consume 'self' before exiting method that discards self}} guard case .red = c else { discard self // expected-note {{discarded self here}} return @@ -263,7 +263,7 @@ struct Basics: ~Copyable { borrower() let x = self self = x - mutator() // expected-error {{must consume 'self' before exiting method that discards self}} + mutator() } consuming func test11_fixed(_ c: Color) { @@ -334,7 +334,7 @@ struct Basics: ~Copyable { return } await asyncer() - } // <- better spot + } consuming func test13_fixed(_ c: Color) async { guard case .red = c else { @@ -345,16 +345,16 @@ struct Basics: ~Copyable { _ = consume self } - consuming func test14(_ c: Color) async { + consuming func test14(_ c: Color) async { // expected-error {{must consume 'self' before exiting method that discards self}} guard case .red = c else { discard self // expected-note {{discarded self here}} return } - await withCheckedContinuation { cont in // expected-error {{must consume 'self' before exiting method that discards self}} + await withCheckedContinuation { cont in cont.resume() } print("back!") - } // <- better spot + } consuming func test14_fixed(_ c: Color) async { guard case .red = c else { @@ -402,7 +402,7 @@ struct Basics: ~Copyable { case 0: fallthrough case 1: - throw E.someError // expected-error 2{{must consume 'self' before exiting method that discards self}} + throw E.someError // expected-error {{must consume 'self' before exiting method that discards self}} case 2: return // expected-error {{must consume 'self' before exiting method that discards self}} case 3: @@ -410,22 +410,21 @@ struct Basics: ~Copyable { case 4: globalConsumingFn(self) default: - discard self // expected-note 4{{discarded self here}} + discard self // expected-note 3{{discarded self here}} } } consuming func loopyExit_bad(_ i: Int) { if i < 0 { - discard self // expected-note 2{{discarded self here}} + discard self // expected-note {{discarded self here}} return } - // TODO: rdar://110239087 (avoid duplicate consume-before-exit diagnostics for loop in discarding method) - for _ in 0.. () { // CHECK: [[STACK:%.*]] = alloc_stack [lexical] $Klass, var, name "x2" // CHECK: store {{%.*}} to [init] [[STACK]] -// CHECK: destroy_addr [[STACK]] // CHECK: [[ACCESS:%.*]] = begin_access [modify] [static] [[STACK]] +// CHECK: destroy_addr [[STACK]] // CHECK: store {{%.*}} to [init] [[ACCESS]] // CHECK: end_access [[ACCESS]] // CHECK: [[ACCESS:%.*]] = begin_access [read] [static] [[STACK]] @@ -659,16 +659,16 @@ sil @see_addr_2 : $@convention(thin) (@in_guaranteed M, @in_guaranteed M) -> () // CHECK: [[M4_S4_ADDR:%[^,]+]] = struct_element_addr [[STACK]] : $*M4, #M4.s4 // CHECK: [[SEE_ADDR_2:%[^,]+]] = function_ref @see_addr_2 // CHECK: apply [[SEE_ADDR_2]]([[M4_S2_ADDR]], [[M4_S4_ADDR]]) -// HECK: [[M4_S4_ADDR_2:%[^,]+]] = struct_element_addr [[STACK]] : $*M4, #M4.s4 -// HECK: destroy_addr [[M4_S4_ADDR_2]] -// CHECK: [[M4_S2_ADDR_2:%[^,]+]] = struct_element_addr [[STACK]] : $*M4, #M4.s2 -// CHECK: destroy_addr [[M4_S2_ADDR_2]] // CHECK: [[M4_S1_ADDR:%[^,]+]] = struct_element_addr [[STACK]] : $*M4, #M4.s1 // CHECK: [[M4_S1:%[^,]+]] = load [take] [[M4_S1_ADDR]] : $*M // CHECK: [[M4_S3_ADDR:%[^,]+]] = struct_element_addr [[STACK]] : $*M4, #M4.s3 // CHECK: [[M4_S3:%[^,]+]] = load [take] [[M4_S3_ADDR]] : $*M // CHECK: [[END_2:%[^,]+]] = function_ref @end_2 // CHECK: apply [[END_2]]([[M4_S1]], [[M4_S3]]) +// CHECK: [[M4_S4_ADDR_2:%[^,]+]] = struct_element_addr [[STACK]] : $*M4, #M4.s4 +// CHECK: destroy_addr [[M4_S4_ADDR_2]] +// CHECK: [[M4_S2_ADDR_2:%[^,]+]] = struct_element_addr [[STACK]] : $*M4, #M4.s2 +// CHECK: destroy_addr [[M4_S2_ADDR_2]] // CHECK-LABEL: } // end sil function 'rdar110676577' sil [ossa] @rdar110676577 : $@convention(thin) () -> () { bb0: diff --git a/test/SILOptimizer/moveonly_addresschecker_debuginfo.sil b/test/SILOptimizer/moveonly_addresschecker_debuginfo.sil index 65b8c312f5a80..13a8ce0f0126f 100644 --- a/test/SILOptimizer/moveonly_addresschecker_debuginfo.sil +++ b/test/SILOptimizer/moveonly_addresschecker_debuginfo.sil @@ -50,13 +50,13 @@ bb1: // CHECK: [[BORROW:%.*]] = load_borrow [[STACK]] // CHECK: apply {{%.*}}([[BORROW]]) // CHECK-NEXT: end_borrow [[BORROW]] -// CHECK-NEXT: destroy_addr [[STACK]] -// CHECK-NEXT: debug_value undef : $*NonTrivialStruct, let, name "v" // {{.*}}; line:[[DEBUG_LOC]] // CHECK: br bb3 // // CHECK: bb2: -// CHECK-NEXT: destroy_addr [[STACK]] +// CHECK-NEXT: br bb3 +// CHECK: bb3: // CHECK-NEXT: debug_value undef : $*NonTrivialStruct, let, name "v" // {{.*}}; line:[[DEBUG_LOC]] +// CHECK-NEXT: destroy_addr [[STACK]] // CHECK: } // end sil function 'non_lifetime_ending_use_test_boundary_edge' sil [ossa] @non_lifetime_ending_use_test_boundary_edge : $@convention(thin) () -> () { %f = function_ref @get_nontrivial_struct : $@convention(thin) () -> @owned NonTrivialStruct diff --git a/test/SILOptimizer/moveonly_addresschecker_maximize.sil b/test/SILOptimizer/moveonly_addresschecker_maximize.sil new file mode 100644 index 0000000000000..e47ba09276d66 --- /dev/null +++ b/test/SILOptimizer/moveonly_addresschecker_maximize.sil @@ -0,0 +1,1130 @@ +// RUN: %target-sil-opt -sil-move-only-address-checker -enable-sil-verify-all %s | %FileCheck %s +sil_stage raw + +import Builtin + +// ############################################################################# +// ############################################################################# +// SCALAR STORAGE {{ +// ############################################################################# +// ############################################################################# + +sil [ossa] @condition : $@convention(thin) () -> Builtin.Int1 + +@_moveOnly struct S { + deinit +} + +sil [ossa] @get : $@convention(thin) () -> @out S +sil [ossa] @get_value : $@convention(thin) () -> @owned S + +sil [ossa] @see : $@convention(thin) (@guaranteed S) -> () +sil [ossa] @see_addr : $@convention(thin) (@in_guaranteed S) -> () + +sil [ossa] @end : $@convention(thin) (@owned S) -> () +sil [ossa] @end_addr : $@convention(thin) (@in S) -> () + +sil [ossa] @other : $@convention(thin) () -> () + +// ============================================================================= +// ============================================================================= +// Single def {{ +// ============================================================================= +// ============================================================================= + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Single block {{ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// A load-copy of the value is passed to a value-consuming function, and the +// storage is destroyed at function end. +// +// Ensure that there is no copy and the lifetime ends at the value-consume. +// CHECK-LABEL: sil [ossa] @singleblock_consume_value_before_other : {{.*}} { +// CHECK: [[OTHER:%[^,]+]] = function_ref @other +// CHECK: [[GET_VALUE:%[^,]+]] = function_ref @get_value +// CHECK: [[END:%[^,]+]] = function_ref @end +// CHECK: [[STACK:%[^,]+]] = alloc_stack +// CHECK: [[INSTANCE:%[^,]+]] = apply [[GET_VALUE]]() +// CHECK: store [[INSTANCE]] to [init] [[STACK]] +// CHECK: [[ACCESS:%[^,]+]] = begin_access [modify] [static] [[STACK]] +// CHECK: [[INSTANCE_RELOAD:%[^,]+]] = load [take] [[ACCESS]] +// CHECK: apply [[END]]([[INSTANCE_RELOAD]]) +// CHECK: end_access [[ACCESS]] +// CHECK: apply [[OTHER]]() +// CHECK: dealloc_stack [[STACK]] +// CHECK-LABEL: } // end sil function 'singleblock_consume_value_before_other' +sil [ossa] @singleblock_consume_value_before_other : $@convention(thin) () -> () { +bb0: + %other = function_ref @other : $@convention(thin) () -> () + %get_value = function_ref @get_value : $@convention(thin) () -> @owned S + %end = function_ref @end : $@convention(thin) (@owned S) -> () + + %stack_addr = alloc_stack $S + %stack = mark_must_check [consumable_and_assignable] %stack_addr : $*S + %instance = apply %get_value() : $@convention(thin) () -> @owned S + store %instance to [init] %stack : $*S + %access = begin_access [deinit] [static] %stack : $*S + %instance_reload = load [copy] %access : $*S + apply %end(%instance_reload) : $@convention(thin) (@owned S) -> () + end_access %access : $*S + %18 = apply %other() : $@convention(thin) () -> () + destroy_addr %stack : $*S + dealloc_stack %stack_addr : $*S + %retval = tuple () + return %retval : $() +} + +// A load-copy of the value is passed to a value-borrowing function then +// destroyed, and the storage is destroyed at function end. +// +// Ensure that there is no copy and the lifetime ends at function end. +// CHECK-LABEL: sil [ossa] @singleblock_borrow_before_other : {{.*}} { +// CHECK: [[OTHER:%[^,]+]] = function_ref @other +// CHECK: [[GET_VALUE:%[^,]+]] = function_ref @get_value +// CHECK: [[SEE:%[^,]+]] = function_ref @see +// CHECK: [[STACK:%[^,]+]] = alloc_stack +// CHECK: [[INSTANCE:%[^,]+]] = apply [[GET_VALUE]]() +// CHECK: store [[INSTANCE]] to [init] [[STACK]] +// CHECK: [[ACCESS:%[^,]+]] = begin_access [deinit] [static] [[STACK]] +// CHECK: [[BORROW:%[^,]+]] = load_borrow [[ACCESS]] +// CHECK: apply [[SEE]]([[BORROW]]) +// CHECK: end_borrow [[BORROW]] +// CHECK: end_access [[ACCESS]] +// CHECK: apply [[OTHER]]() +// CHECK: destroy_addr [[STACK]] +// CHECK: dealloc_stack [[STACK]] +// CHECK-LABEL: } // end sil function 'singleblock_borrow_before_other' +sil [ossa] @singleblock_borrow_before_other : $@convention(thin) () -> () { +bb0: + %other = function_ref @other : $@convention(thin) () -> () + %get_value = function_ref @get_value : $@convention(thin) () -> @owned S + %see = function_ref @see : $@convention(thin) (@guaranteed S) -> () + %end = function_ref @end : $@convention(thin) (@owned S) -> () + + %stack_addr = alloc_stack $S + %stack = mark_must_check [consumable_and_assignable] %stack_addr : $*S + %instance = apply %get_value() : $@convention(thin) () -> @owned S + store %instance to [init] %stack : $*S + %access = begin_access [deinit] [static] %stack : $*S + %instance_reload = load [copy] %access : $*S + apply %see(%instance_reload) : $@convention(thin) (@guaranteed S) -> () + destroy_value %instance_reload : $S + end_access %access : $*S + %18 = apply %other() : $@convention(thin) () -> () + destroy_addr %stack : $*S + dealloc_stack %stack_addr : $*S + %retval = tuple () + return %retval : $() +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// }} Single block +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Multiple blocks {{ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// There is a consuming use in right. So bottom is a consumed block. Liveness +// is retracted up to the consume in right and up to the bottom of left. +// CHECK-LABEL: sil [ossa] @diamond__consume_r__use_l__destroy_b : {{.*}} { +// CHECK: [[STACK:%[^,]+]] = alloc_stack +// CHECK: [[GET:%[^,]+]] = function_ref @get +// CHECK: [[OTHER:%[^,]+]] = function_ref @other +// CHECK: [[SEE_ADDR:%[^,]+]] = function_ref @see_addr +// CHECK: [[END:%[^,]+]] = function_ref @end +// CHECK: apply [[GET]]([[STACK]]) +// CHECK: cond_br undef, [[LEFT:bb[0-9]+]], [[RIGHT:bb[0-9]+]] +// CHECK: [[LEFT:bb[0-9]+]]: +// CHECK: apply [[SEE_ADDR]]([[STACK]]) +// CHECK: apply [[OTHER]]() +// CHECK: destroy_addr [[STACK]] +// CHECK: br [[BOTTOM:bb[0-9]+]] +// CHECK: [[RIGHT:bb[0-9]+]]: +// CHECK: [[INSTANCE:%[^,]+]] = load [take] [[STACK]] +// CHECK: apply [[END]]([[INSTANCE]]) +// CHECK: br [[BOTTOM]] +// CHECK: [[BOTTOM]]: +// CHECK-LABEL: } // end sil function 'diamond__consume_r__use_l__destroy_b' +sil [ossa] @diamond__consume_r__use_l__destroy_b : $@convention(thin) () -> () { +top: + %stack_addr = alloc_stack $S + %stack = mark_must_check [consumable_and_assignable] %stack_addr : $*S + %get = function_ref @get : $@convention(thin) () -> @out S + %other = function_ref @other : $@convention(thin) () -> () + %see = function_ref @see : $@convention(thin) (@guaranteed S) -> () + %see_addr = function_ref @see_addr : $@convention(thin) (@in_guaranteed S) -> () + %end = function_ref @end : $@convention(thin) (@owned S) -> () + %end_addr = function_ref @end_addr : $@convention(thin) (@in S) -> () + apply %get(%stack) : $@convention(thin) () -> @out S + cond_br undef, left, right +left: + apply %see_addr(%stack) : $@convention(thin) (@in_guaranteed S) -> () + apply %other() : $@convention(thin) () -> () + br bottom +right: + %copy = load [copy] %stack : $*S + apply %end(%copy) : $@convention(thin) (@owned S) -> () + br bottom +bottom: + destroy_addr %stack : $*S + dealloc_stack %stack_addr : $*S + %retval = tuple () + return %retval : $() +} + +// Only bottom is consumedAtEntry. +// CHECK-LABEL: sil [ossa] @diamond_2r__consume_r1r2__use_l__destroy_b : {{.*}} { +// CHECK: [[STACK:%[^,]+]] = alloc_stack +// CHECK: [[GET:%[^,]+]] = function_ref @get +// CHECK: [[SEE:%[^,]+]] = function_ref @see +// CHECK: [[END:%[^,]+]] = function_ref @end +// CHECK: apply [[GET]]([[STACK]]) +// CHECK: cond_br undef, [[LEFT:bb[0-9]+]], [[RIGHT:bb[0-9]+]] +// CHECK: [[LEFT]]: +// CHECK: [[BORROW:%[^,]+]] = load_borrow [[STACK]] +// CHECK: apply [[SEE]]([[BORROW]]) +// CHECK: end_borrow [[BORROW]] +// CHECK: destroy_addr [[STACK]] +// CHECK: br [[BOTTOM:bb[0-9]+]] +// CHECK: [[RIGHT]]: +// CHECK: [[BORROW_2:%[^,]+]] = load_borrow [[STACK]] +// CHECK: apply [[SEE]]([[BORROW_2]]) +// CHECK: end_borrow [[BORROW_2]] +// CHECK: br [[RIGHT_2:bb[0-9]+]] +// CHECK: [[RIGHT_2]]: +// CHECK: [[TAKE:%[^,]+]] = load [take] [[STACK]] +// CHECK: apply [[END]]([[TAKE]]) +// CHECK: br [[BOTTOM]] +// CHECK: [[BOTTOM]]: +// CHECK-LABEL: } // end sil function 'diamond_2r__consume_r1r2__use_l__destroy_b' +sil [ossa] @diamond_2r__consume_r1r2__use_l__destroy_b : $@convention(thin) () -> () { +top: + %stack_addr = alloc_stack $S + %stack = mark_must_check [consumable_and_assignable] %stack_addr : $*S + %get = function_ref @get : $@convention(thin) () -> @out S + %other = function_ref @other : $@convention(thin) () -> () + %see = function_ref @see : $@convention(thin) (@guaranteed S) -> () + %see_addr = function_ref @see_addr : $@convention(thin) (@in_guaranteed S) -> () + %end = function_ref @end : $@convention(thin) (@owned S) -> () + %end_addr = function_ref @end_addr : $@convention(thin) (@in S) -> () + apply %get(%stack) : $@convention(thin) () -> @out S + cond_br undef, left, right +left: + %copy3 = load [copy] %stack : $*S + apply %see(%copy3) : $@convention(thin) (@guaranteed S) -> () + destroy_value %copy3 : $S + br bottom +right: + %copy = load [copy] %stack : $*S + apply %see(%copy) : $@convention(thin) (@guaranteed S) -> () + destroy_value %copy : $S + br right2 +right2: + %copy2 = load [copy] %stack : $*S + apply %end(%copy2) : $@convention(thin) (@owned S) -> () + br bottom +bottom: + destroy_addr %stack : $*S + dealloc_stack %stack_addr : $*S + %retval = tuple () + return %retval : $() +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// }} Multiple blocks +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ============================================================================= +// ============================================================================= +// }} Single def +// ============================================================================= +// ============================================================================= + +// ============================================================================= +// ============================================================================= +// Multiple defs {{ +// ============================================================================= +// ============================================================================= + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Multiple blocks {{ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Like diamond__consume_r__use_l__destroy_b but with a copy_addr [take] reinit +// in left. The reinit is after an apply of other. +// +// Ensure that the destroy from that deinit remains at the same location--it +// will be split into a separate instruction. +// +// TODO: Avoid the unnecessary churn of that splitting. +// CHECK-LABEL: sil [ossa] @diamond__consume_r__reinit_l__use_l__destroy_b : {{.*}} { +// CHECK: [[STACK:%[^,]+]] = alloc_stack +// CHECK: [[GET:%[^,]+]] = function_ref @get +// CHECK: [[OTHER:%[^,]+]] = function_ref @other +// CHECK: [[SEE_ADDR:%[^,]+]] = function_ref @see_addr +// CHECK: [[END:%[^,]+]] = function_ref @end +// CHECK: apply [[GET]]([[STACK]]) +// CHECK: cond_br undef, [[LEFT:bb[0-9]+]], [[RIGHT:bb[0-9]+]] +// CHECK: [[LEFT:bb[0-9]+]]: +// CHECK: apply [[OTHER]]() +// CHECK: destroy_addr [[STACK]] +// CHECK: apply [[SEE_ADDR]]([[STACK]]) +// CHECK: apply [[OTHER]]() +// CHECK: destroy_addr [[STACK]] +// CHECK: br [[BOTTOM:bb[0-9]+]] +// CHECK: [[RIGHT:bb[0-9]+]]: +// CHECK: [[INSTANCE:%[^,]+]] = load [take] [[STACK]] +// CHECK: apply [[END]]([[INSTANCE]]) +// CHECK: br [[BOTTOM]] +// CHECK: [[BOTTOM]]: +// CHECK-LABEL: } // end sil function 'diamond__consume_r__reinit_l__use_l__destroy_b' +sil [ossa] @diamond__consume_r__reinit_l__use_l__destroy_b : $@convention(thin) () -> () { +top: + %stack_addr = alloc_stack $S + %stack = mark_must_check [consumable_and_assignable] %stack_addr : $*S + %get = function_ref @get : $@convention(thin) () -> @out S + %other = function_ref @other : $@convention(thin) () -> () + %see = function_ref @see : $@convention(thin) (@guaranteed S) -> () + %see_addr = function_ref @see_addr : $@convention(thin) (@in_guaranteed S) -> () + %end = function_ref @end : $@convention(thin) (@owned S) -> () + %end_addr = function_ref @end_addr : $@convention(thin) (@in S) -> () + apply %get(%stack) : $@convention(thin) () -> @out S + cond_br undef, left, right +left: + apply %other() : $@convention(thin) () -> () + %stack2 = alloc_stack $S + apply %get(%stack2) : $@convention(thin) () -> @out S + copy_addr [take] %stack2 to %stack : $*S + dealloc_stack %stack2 : $*S + apply %see_addr(%stack) : $@convention(thin) (@in_guaranteed S) -> () + apply %other() : $@convention(thin) () -> () + br bottom +right: + %copy = load [copy] %stack : $*S + apply %end(%copy) : $@convention(thin) (@owned S) -> () + br bottom +bottom: + destroy_addr %stack : $*S + dealloc_stack %stack_addr : $*S + %retval = tuple () + return %retval : $() +} + +// Like diamond__consume_r__reinit_l__use_l__destroy_b with a store [assign] +// reinit in left. The reinit is after an apply of other. +// +// Ensure that the destroy from that deinit remains at the same location--it +// will be split into a separate instruction. +// +// TODO: Avoid the unnecessary churn of that splitting. +// CHECK-LABEL: sil [ossa] @diamond__consume_r__reinit_l__use_l__destroy_b2 : {{.*}} { +// CHECK: [[STACK:%[^,]+]] = alloc_stack +// CHECK: [[GET:%[^,]+]] = function_ref @get +// CHECK: [[OTHER:%[^,]+]] = function_ref @other +// CHECK: [[SEE_ADDR:%[^,]+]] = function_ref @see_addr +// CHECK: [[END:%[^,]+]] = function_ref @end +// CHECK: apply [[GET]]([[STACK]]) +// CHECK: cond_br undef, [[LEFT:bb[0-9]+]], [[RIGHT:bb[0-9]+]] +// CHECK: [[LEFT:bb[0-9]+]]: +// CHECK: apply [[OTHER]]() +// CHECK: destroy_addr [[STACK]] +// CHECK: apply [[SEE_ADDR]]([[STACK]]) +// CHECK: apply [[OTHER]]() +// CHECK: destroy_addr [[STACK]] +// CHECK: br [[BOTTOM:bb[0-9]+]] +// CHECK: [[RIGHT:bb[0-9]+]]: +// CHECK: [[INSTANCE:%[^,]+]] = load [take] [[STACK]] +// CHECK: apply [[END]]([[INSTANCE]]) +// CHECK: br [[BOTTOM]] +// CHECK: [[BOTTOM]]: +// CHECK-LABEL: } // end sil function 'diamond__consume_r__reinit_l__use_l__destroy_b2' +sil [ossa] @diamond__consume_r__reinit_l__use_l__destroy_b2 : $@convention(thin) () -> () { +top: + %stack_addr = alloc_stack $S + %stack = mark_must_check [consumable_and_assignable] %stack_addr : $*S + %get = function_ref @get : $@convention(thin) () -> @out S + %get_value = function_ref @get_value : $@convention(thin) () -> @owned S + %other = function_ref @other : $@convention(thin) () -> () + %see = function_ref @see : $@convention(thin) (@guaranteed S) -> () + %see_addr = function_ref @see_addr : $@convention(thin) (@in_guaranteed S) -> () + %end = function_ref @end : $@convention(thin) (@owned S) -> () + %end_addr = function_ref @end_addr : $@convention(thin) (@in S) -> () + apply %get(%stack) : $@convention(thin) () -> @out S + cond_br undef, left, right +left: + apply %other() : $@convention(thin) () -> () + %new = apply %get_value() : $@convention(thin) () -> @owned S + store %new to [assign] %stack : $*S + apply %see_addr(%stack) : $@convention(thin) (@in_guaranteed S) -> () + apply %other() : $@convention(thin) () -> () + br bottom +right: + %copy = load [copy] %stack : $*S + apply %end(%copy) : $@convention(thin) (@owned S) -> () + br bottom +bottom: + destroy_addr %stack : $*S + dealloc_stack %stack_addr : $*S + %retval = tuple () + return %retval : $() +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// }} Multiple blocks +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ============================================================================= +// ============================================================================= +// }} Multiple defs +// ============================================================================= +// ============================================================================= + +// ############################################################################# +// ############################################################################# +// }} SCALAR STORAGE +// ############################################################################# +// ############################################################################# + +// ############################################################################# +// ############################################################################# +// AGGREGATE STORAGE {{ +// ############################################################################# +// ############################################################################# + +@_moveOnly struct S2 { + var s1: S + var s2: S +} + +sil [ossa] @get_value_S2 : $@convention(thin) () -> @owned S2 +sil [ossa] @end_S2 : $@convention(thin) (@owned S2) -> () + +@_moveOnly struct S3 { + var s1: S + var s2: S + var s3: S +} + +sil [ossa] @get_value_S3 : $@convention(thin) () -> @owned S3 +sil [ossa] @end_S3 : $@convention(thin) (@owned S3) -> () + +// ============================================================================= +// ============================================================================= +// Single def {{ +// ============================================================================= +// ============================================================================= + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Single block {{ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// The apply of other remains before the destroy_addr. +// CHECK-LABEL: sil [ossa] @aggregate_1 : {{.*}} { +// CHECK: [[OTHER:%[^,]+]] = function_ref @other +// CHECK: [[STACK:%[^,]+]] = alloc_stack +// CHECK: apply [[OTHER]]() +// CHECK: destroy_addr [[STACK]] +// CHECK-LABEL: } // end sil function 'aggregate_1' +sil [ossa] @aggregate_1 : $@convention(thin) () -> () { +bb0: + %get_value_S2 = function_ref @get_value_S2 : $@convention(thin) () -> @owned S2 + %end = function_ref @end : $@convention(thin) (@owned S) -> () + %other = function_ref @other : $@convention(thin) () -> () + + %stack_addr = alloc_stack $S2 + %stack = mark_must_check [consumable_and_assignable] %stack_addr : $*S2 + %instance_1 = apply %get_value_S2() : $@convention(thin) () -> @owned S2 + store %instance_1 to [init] %stack : $*S2 + apply %other() : $@convention(thin) () -> () + destroy_addr %stack : $*S2 + dealloc_stack %stack_addr : $*S2 + %retval = tuple () + return %retval : $() +} + + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// }} Single block +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ============================================================================= +// ============================================================================= +// }} Single def +// ============================================================================= +// ============================================================================= + +// ============================================================================= +// ============================================================================= +// Multiple defs {{ +// ============================================================================= +// ============================================================================= + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Single block {{ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Calls to other before each destroy remain before. +// CHECK-LABEL: sil [ossa] @aggregate_2 : {{.*}} { +// CHECK: [[OTHER:%[^,]+]] = function_ref @other +// CHECK: [[STACK:%[^,]+]] = alloc_stack +// CHECK: apply [[OTHER]]() +// CHECK: destroy_addr [[STACK]] : $*S2 +// CHECK: apply [[OTHER]]() +// CHECK: destroy_addr [[STACK]] : $*S2 +// CHECK-LABEL: } // end sil function 'aggregate_2' +sil [ossa] @aggregate_2 : $@convention(thin) () -> () { +bb0: + %get_value_S2 = function_ref @get_value_S2 : $@convention(thin) () -> @owned S2 + %end = function_ref @end : $@convention(thin) (@owned S) -> () + %other = function_ref @other : $@convention(thin) () -> () + + %stack_addr = alloc_stack $S2 + %stack = mark_must_check [consumable_and_assignable] %stack_addr : $*S2 + %instance_1 = apply %get_value_S2() : $@convention(thin) () -> @owned S2 + store %instance_1 to [init] %stack : $*S2 + %instance_2 = apply %get_value_S2() : $@convention(thin) () -> @owned S2 + apply %other() : $@convention(thin) () -> () + store %instance_2 to [assign] %stack : $*S2 + apply %other() : $@convention(thin) () -> () + destroy_addr %stack : $*S2 + dealloc_stack %stack_addr : $*S2 + %retval = tuple () + return %retval : $() +} + +// s1 is consumed but s2 is not and so is not destroyed until function end, after +// other. + +// CHECK-LABEL: sil [ossa] @simpleTestVar2 : {{.*}} { +// CHECK: [[OTHER:%[^,]+]] = function_ref @other +// CHECK: [[STACK:%[^,]+]] = alloc_stack +// CHECK: apply [[OTHER]]() +// CHECK: [[S2_ADDR:%[^,]+]] = struct_element_addr [[STACK]] : $*S2, #S2.s2 +// CHECK: destroy_addr [[S2_ADDR]] +// CHECK-LABEL: } // end sil function 'simpleTestVar2' +sil [ossa] @simpleTestVar2 : $@convention(thin) () -> () { +bb0: + %get_value_S2 = function_ref @get_value_S2 : $@convention(thin) () -> @owned S2 + %end = function_ref @end : $@convention(thin) (@owned S) -> () + %other = function_ref @other : $@convention(thin) () -> () + + %stack_addr = alloc_stack $S2 + %stack = mark_must_check [consumable_and_assignable] %stack_addr : $*S2 + %instance_1 = apply %get_value_S2() : $@convention(thin) () -> @owned S2 + store %instance_1 to [init] %stack : $*S2 + %instance_2 = apply %get_value_S2() : $@convention(thin) () -> @owned S2 + %access = begin_access [modify] [static] %stack : $*S2 + store %instance_2 to [assign] %access : $*S2 + end_access %access : $*S2 + %access_2 = begin_access [deinit] [static] %stack : $*S2 + %s1_addr = struct_element_addr %access_2 : $*S2, #S2.s1 + %s1 = load [copy] %s1_addr : $*S + apply %end(%s1) : $@convention(thin) (@owned S) -> () + end_access %access_2 : $*S2 + apply %other() : $@convention(thin) () -> () + destroy_addr %stack : $*S2 + dealloc_stack %stack_addr : $*S2 + %retval = tuple () + return %retval : $() +} + +// Both fields (#S2.s1, #S2.s2) are consumed before other. +// CHECK-LABEL: sil [ossa] @simpleTestVar3 : {{.*}} { +// CHECK: [[END:%[^,]+]] = function_ref @end +// CHECK: [[OTHER:%[^,]+]] = function_ref @other +// CHECK: [[STACK:%[^,]+]] = alloc_stack +// CHECK: begin_access +// CHECK: [[ACCESS_1:%[^,]+]] = begin_access [modify] [static] [[STACK]] +// CHECK: [[S1_ADDR:%[^,]+]] = struct_element_addr [[ACCESS_1]] : $*S2, #S2.s1 +// CHECK: [[S1:%[^,]+]] = load [take] [[S1_ADDR]] +// CHECK: apply [[END]]([[S1]]) +// CHECK: [[ACCESS_2:%[^,]+]] = begin_access [modify] [static] [[STACK]] +// CHECK: [[S2_ADDR:%[^,]+]] = struct_element_addr [[ACCESS_2]] : $*S2, #S2.s2 +// CHECK: [[S2:%[^,]+]] = load [take] [[S2_ADDR]] +// CHECK: apply [[END]]([[S2]]) +// CHECK: apply [[OTHER]]() +// CHECK-LABEL: } // end sil function 'simpleTestVar3' +sil [ossa] @simpleTestVar3 : $@convention(thin) () -> () { +bb0: + %get_value_S2 = function_ref @get_value_S2 : $@convention(thin) () -> @owned S2 + %end = function_ref @end : $@convention(thin) (@owned S) -> () + %other = function_ref @other : $@convention(thin) () -> () + + %stack_addr = alloc_stack $S2 + %stack = mark_must_check [consumable_and_assignable] %stack_addr : $*S2 + %instance_1 = apply %get_value_S2() : $@convention(thin) () -> @owned S2 + store %instance_1 to [init] %stack : $*S2 + %instance_2 = apply %get_value_S2() : $@convention(thin) () -> @owned S2 + %access = begin_access [modify] [static] %stack : $*S2 + store %instance_2 to [assign] %access : $*S2 + end_access %access : $*S2 + %access_2 = begin_access [deinit] [static] %stack : $*S2 + %s1_addr = struct_element_addr %access_2 : $*S2, #S2.s1 + %s1 = load [copy] %s1_addr : $*S + apply %end(%s1) : $@convention(thin) (@owned S) -> () + end_access %access_2 : $*S2 + %access_3 = begin_access [deinit] [static] %stack : $*S2 + %s2_addr = struct_element_addr %access_3 : $*S2, #S2.s2 + %s2 = load [copy] %s2_addr : $*S + apply %end(%s2) : $@convention(thin) (@owned S) -> () + end_access %access_3 : $*S2 + apply %other() : $@convention(thin) () -> () + destroy_addr %stack : $*S2 + dealloc_stack %stack_addr : $*S2 + %retval = tuple () + return %retval : $() +} + +// Addr is initialized, then both fields are individually consumed before other. +// Then addr is initialized again and neither field is consumed; then other is +// applied again. +// +// Ensure that the reinitialized fields survive to function end. +// +// CHECK-LABEL: sil [ossa] @simpleTestVar3a : {{.*}} { +// CHECK: [[GET_VALUE_S2:%[^,]+]] = function_ref @get_value_S2 +// CHECK: [[OTHER:%[^,]+]] = function_ref @other +// CHECK: [[STACK:%[^,]+]] = alloc_stack +// CHECK: apply [[OTHER]]() +// CHECK: [[INSTANCE_3:%[^,]+]] = apply [[GET_VALUE_S2]]() +// CHECK: [[ACCESS:%[^,]+]] = begin_access [modify] [static] [[STACK]] +// CHECK: store [[INSTANCE_3]] to [init] [[ACCESS]] +// CHECK: end_access [[ACCESS]] +// CHECK: apply [[OTHER]]() : $@convention(thin) () -> () +// CHECK: destroy_addr [[STACK]] +// CHECK-LABEL: } // end sil function 'simpleTestVar3a' +sil [ossa] @simpleTestVar3a : $@convention(thin) () -> () { +bb0: + %get_value_S2 = function_ref @get_value_S2 : $@convention(thin) () -> @owned S2 + %end = function_ref @end : $@convention(thin) (@owned S) -> () + %other = function_ref @other : $@convention(thin) () -> () + + %stack_addr = alloc_stack $S2 + %stack = mark_must_check [consumable_and_assignable] %stack_addr : $*S2 + %instance_1 = apply %get_value_S2() : $@convention(thin) () -> @owned S2 + store %instance_1 to [init] %stack : $*S2 + %instance_2 = apply %get_value_S2() : $@convention(thin) () -> @owned S2 + %access_1 = begin_access [modify] [static] %stack : $*S2 + store %instance_2 to [assign] %access_1 : $*S2 + end_access %access_1 : $*S2 + %access_2 = begin_access [deinit] [static] %stack : $*S2 + %s1_addr = struct_element_addr %access_2 : $*S2, #S2.s1 + %s1 = load [copy] %s1_addr : $*S + apply %end(%s1) : $@convention(thin) (@owned S) -> () + end_access %access_2 : $*S2 + %access_3 = begin_access [deinit] [static] %stack : $*S2 + %s2_addr = struct_element_addr %access_3 : $*S2, #S2.s2 + %s2 = load [copy] %s2_addr : $*S + apply %end(%s2) : $@convention(thin) (@owned S) -> () + end_access %access_3 : $*S2 + apply %other() : $@convention(thin) () -> () + %instance_3 = apply %get_value_S2() : $@convention(thin) () -> @owned S2 + %access_4 = begin_access [modify] [static] %stack : $*S2 + store %instance_3 to [assign] %access_4 : $*S2 + end_access %access_4 : $*S2 + apply %other() : $@convention(thin) () -> () + destroy_addr %stack : $*S2 + dealloc_stack %stack_addr : $*S2 + %retval = tuple () + return %retval : $() +} + +// Like simpleTestVar3a but without access scopes and the original init. +// CHECK-LABEL: sil [ossa] @simpleTestVar3a_simplified : {{.*}} { +// CHECK: [[GET_VALUE_S2:%[^,]+]] = function_ref @get_value_S2 +// CHECK: [[OTHER:%[^,]+]] = function_ref @other +// CHECK: [[STACK:%[^,]+]] = alloc_stack +// CHECK: apply [[OTHER]]() +// CHECK: [[INSTANCE_2:%[^,]+]] = apply [[GET_VALUE_S2]]() +// CHECK: store [[INSTANCE_2]] to [init] [[STACK]] +// CHECK: apply [[OTHER]]() : $@convention(thin) () -> () +// CHECK: destroy_addr [[STACK]] +// CHECK-LABEL: } // end sil function 'simpleTestVar3a_simplified' +sil [ossa] @simpleTestVar3a_simplified : $@convention(thin) () -> () { +bb0: + %get_value_S2 = function_ref @get_value_S2 : $@convention(thin) () -> @owned S2 + %end = function_ref @end : $@convention(thin) (@owned S) -> () + %other = function_ref @other : $@convention(thin) () -> () + + %stack_addr = alloc_stack $S2 + %stack = mark_must_check [consumable_and_assignable] %stack_addr : $*S2 + %instance_1 = apply %get_value_S2() : $@convention(thin) () -> @owned S2 + store %instance_1 to [init] %stack : $*S2 + %s1_addr = struct_element_addr %stack : $*S2, #S2.s1 + %s1 = load [copy] %s1_addr : $*S + apply %end(%s1) : $@convention(thin) (@owned S) -> () + %s2_addr = struct_element_addr %stack : $*S2, #S2.s2 + %s2 = load [copy] %s2_addr : $*S + apply %end(%s2) : $@convention(thin) (@owned S) -> () + apply %other() : $@convention(thin) () -> () + %instance_2 = apply %get_value_S2() : $@convention(thin) () -> @owned S2 + store %instance_2 to [assign] %stack : $*S2 + apply %other() : $@convention(thin) () -> () + destroy_addr %stack : $*S2 + dealloc_stack %stack_addr : $*S2 + %retval = tuple () + return %retval : $() +} + +// Ensure that first initialized liveness remains until original destroy. +// And ensure that reinitialized fields live until function exit. +// CHECK-LABEL: sil [ossa] @simpleTestVar3a_simplified_vary2 : {{.*}} { +// CHECK: [[GET_VALUE:%[^,]+]] = function_ref @get_value +// CHECK: [[SEE:%[^,]+]] = function_ref @see +// CHECK: [[OTHER:%[^,]+]] = function_ref @other +// CHECK: [[STACK:%[^,]+]] = alloc_stack $S +// CHECK: [[INSTANCE_1:%[^,]+]] = apply [[GET_VALUE]]() +// CHECK: store [[INSTANCE_1]] to [init] [[STACK]] +// CHECK: [[BORROW:%[^,]+]] = load_borrow [[STACK]] +// CHECK: apply [[SEE]]([[BORROW]]) +// CHECK: end_borrow [[BORROW]] +// CHECK: apply [[OTHER]]() +// CHECK: [[INSTANCE_2:%[^,]+]] = apply [[GET_VALUE]]() +// CHECK: destroy_addr [[STACK]] +// CHECK: store [[INSTANCE_2]] to [init] [[STACK]] +// CHECK: apply [[OTHER]]() +// CHECK: destroy_addr [[STACK]] +// CHECK-LABEL: } // end sil function 'simpleTestVar3a_simplified_vary2' +sil [ossa] @simpleTestVar3a_simplified_vary2 : $@convention(thin) () -> () { +bb0: + %get_value = function_ref @get_value : $@convention(thin) () -> @owned S + %see = function_ref @see : $@convention(thin) (@guaranteed S) -> () + %other = function_ref @other : $@convention(thin) () -> () + + %stack_addr = alloc_stack $S + %stack = mark_must_check [consumable_and_assignable] %stack_addr : $*S + %instance_1 = apply %get_value() : $@convention(thin) () -> @owned S + store %instance_1 to [init] %stack : $*S + %s = load_borrow %stack : $*S + apply %see(%s) : $@convention(thin) (@guaranteed S) -> () + end_borrow %s : $S + apply %other() : $@convention(thin) () -> () + %instance_2 = apply %get_value() : $@convention(thin) () -> @owned S + store %instance_2 to [assign] %stack : $*S + apply %other() : $@convention(thin) () -> () + destroy_addr %stack : $*S + dealloc_stack %stack_addr : $*S + %retval = tuple () + return %retval : $() +} + +// s1 is consumed at @end. s2 is never consumed so it's destroyed at function +// end. +// CHECK-LABEL: sil [ossa] @simpleTestVar3b : {{.*}} { +// CHECK: [[END:%[^,]+]] = function_ref @end +// CHECK: [[OTHER:%[^,]+]] = function_ref @other +// CHECK: [[STACK:%[^,]+]] = alloc_stack +// CHECK: begin_access +// CHECK: [[ACCESS:%[^,]+]] = begin_access [modify] [static] [[STACK]] +// CHECK: [[S1_ADDR:%[^,]+]] = struct_element_addr [[ACCESS]] : $*S2, #S2.s1 +// CHECK: [[S1:%[^,]+]] = load [take] [[S1_ADDR]] +// CHECK: apply [[END]]([[S1]]) +// CHECK: apply [[OTHER]]() +// CHECK: [[S2_ADDR:%[^,]+]] = struct_element_addr [[STACK]] : $*S2, #S2.s2 +// CHECK: destroy_addr [[S2_ADDR]] +// CHECK-LABEL: } // end sil function 'simpleTestVar3b' +sil [ossa] @simpleTestVar3b : $@convention(thin) () -> () { +bb0: + %get_value_S2 = function_ref @get_value_S2 : $@convention(thin) () -> @owned S2 + %end = function_ref @end : $@convention(thin) (@owned S) -> () + %see = function_ref @see : $@convention(thin) (@guaranteed S) -> () + %other = function_ref @other : $@convention(thin) () -> () + + %stack_addr = alloc_stack $S2 + %stack = mark_must_check [consumable_and_assignable] %stack_addr : $*S2 + %instance_1 = apply %get_value_S2() : $@convention(thin) () -> @owned S2 + store %instance_1 to [init] %stack : $*S2 + %instance_2 = apply %get_value_S2() : $@convention(thin) () -> @owned S2 + %access_1 = begin_access [modify] [static] %stack : $*S2 + store %instance_2 to [assign] %access_1 : $*S2 + end_access %access_1 : $*S2 + %access_2 = begin_access [deinit] [static] %stack : $*S2 + %s1_addr = struct_element_addr %access_2 : $*S2, #S2.s1 + %s1 = load [copy] %s1_addr : $*S + apply %end(%s1) : $@convention(thin) (@owned S) -> () + end_access %access_2 : $*S2 + %access_3 = begin_access [read] [static] %stack : $*S2 + %s2_addr = struct_element_addr %access_3 : $*S2, #S2.s2 + %s2 = load [copy] %s2_addr : $*S + apply %see(%s2) : $@convention(thin) (@guaranteed S) -> () + destroy_value %s2 : $S + end_access %access_3 : $*S2 + apply %other() : $@convention(thin) () -> () + destroy_addr %stack : $*S2 + dealloc_stack %stack_addr : $*S2 + %retval = tuple () + return %retval : $() +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// }} Single block +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// {{ Multiple blocks +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Ensure that liveness extends to destroy in live-at-entry block where no def +// precedes destroy. And ensure that the reinit stack stays live until +// function exit. +// CHECK-LABEL: sil [ossa] @simpleTestVar3a_simplified_vary : {{.*}} { +// CHECK: [[GET_VALUE_S2:%[^,]+]] = function_ref @get_value_S2 +// CHECK: [[SEE:%[^,]+]] = function_ref @see +// CHECK: [[OTHER:%[^,]+]] = function_ref @other +// CHECK: [[STACK:%[^,]+]] = alloc_stack $S2 +// CHECK: [[INSTANCE_1:%[^,]+]] = apply [[GET_VALUE_S2]]() +// CHECK: store [[INSTANCE_1]] to [init] [[STACK]] +// CHECK: [[S1_ADDR:%[^,]+]] = struct_element_addr [[STACK]] +// CHECK: [[S1:%[^,]+]] = load_borrow [[S1_ADDR]] +// CHECK: apply [[SEE]]([[S1]]) +// CHECK: end_borrow [[S1]] +// CHECK: [[S2_ADDR:%[^,]+]] = struct_element_addr [[STACK]] +// CHECK: [[S2:%[^,]+]] = load_borrow [[S2_ADDR]] +// CHECK: apply [[SEE]]([[S2]]) +// CHECK: end_borrow [[S2]] +// CHECK: apply [[OTHER]]() +// CHECK: [[INSTANCE_2:%[^,]+]] = apply [[GET_VALUE_S2]]() +// CHECK: br bb1 +// CHECK: bb1: +// CHECK: destroy_addr [[STACK]] +// CHECK: store [[INSTANCE_2]] to [init] [[STACK]] +// CHECK: apply [[OTHER]]() +// CHECK: destroy_addr [[STACK]] +// CHECK-LABEL: } // end sil function 'simpleTestVar3a_simplified_vary' +sil [ossa] @simpleTestVar3a_simplified_vary : $@convention(thin) () -> () { +bb0: + %get_value_S2 = function_ref @get_value_S2 : $@convention(thin) () -> @owned S2 + %see = function_ref @see : $@convention(thin) (@guaranteed S) -> () + %other = function_ref @other : $@convention(thin) () -> () + + %stack_addr = alloc_stack $S2 + %stack = mark_must_check [consumable_and_assignable] %stack_addr : $*S2 + %instance_1 = apply %get_value_S2() : $@convention(thin) () -> @owned S2 + store %instance_1 to [init] %stack : $*S2 + %s1_addr = struct_element_addr %stack : $*S2, #S2.s1 + %s1 = load_borrow %s1_addr : $*S + apply %see(%s1) : $@convention(thin) (@guaranteed S) -> () + end_borrow %s1 : $S + %s2_addr = struct_element_addr %stack : $*S2, #S2.s2 + %s2 = load_borrow %s2_addr : $*S + apply %see(%s2) : $@convention(thin) (@guaranteed S) -> () + end_borrow %s2 : $S + apply %other() : $@convention(thin) () -> () + %instance_3 = apply %get_value_S2() : $@convention(thin) () -> @owned S2 + br bb1 +bb1: + store %instance_3 to [assign] %stack : $*S2 + apply %other() : $@convention(thin) () -> () + destroy_addr %stack : $*S2 + dealloc_stack %stack_addr : $*S2 + %retval = tuple () + return %retval : $() +} + +// Stack is initialized twice, in entry and middle. In each case, it is passed +// to a consuming function on the left block and unused on the right block; and +// each right block contains an apply of other. +// +// Verify that the destroy in each right block is after the apply of other. +// CHECK-LABEL: sil [ossa] @simpleTestVar4 : {{.*}} { +// CHECK: [[OTHER:%[^,]+]] = function_ref @other +// CHECK: [[STACK:%[^,]+]] = alloc_stack +// CHECK: cond_br {{%[^,]+}}, [[LEFT_1:bb[0-9]+]], [[RIGHT_1:bb[0-9]+]] +// CHECK: [[LEFT_1]]: +// CHECK: br [[MIDDLE:bb[0-9]+]] +// CHECK: [[RIGHT_1]]: +// CHECK: apply [[OTHER]]() +// CHECK: destroy_addr [[STACK]] +// CHECK: br [[MIDDLE]] +// CHECK: [[MIDDLE]]: +// CHECK: cond_br {{%[^,]+}}, [[LEFT_2:bb[0-9]+]], [[RIGHT_2:bb[0-9]+]] +// CHECK: [[LEFT_2]]: +// CHECK: br [[EXIT:bb[0-9]+]] +// CHECK: [[RIGHT_2]]: +// CHECK: destroy_addr [[STACK]] +// CHECK: apply [[OTHER]]() : $@convention(thin) () -> () +// CHECK: br [[EXIT]] +// CHECK-LABEL: } // end sil function 'simpleTestVar4' +sil [ossa] @simpleTestVar4 : $@convention(thin) () -> () { +entry: + %get_value_S2 = function_ref @get_value_S2 : $@convention(thin) () -> @owned S2 + %condition = function_ref @condition : $@convention(thin) () -> Builtin.Int1 + %end_S2 = function_ref @end_S2 : $@convention(thin) (@owned S2) -> () + %other = function_ref @other : $@convention(thin) () -> () + + %stack_addr = alloc_stack $S2 + %stack = mark_must_check [consumable_and_assignable] %stack_addr : $*S2 + %instance_1 = apply %get_value_S2() : $@convention(thin) () -> @owned S2 + store %instance_1 to [init] %stack : $*S2 + %instance_2 = apply %get_value_S2() : $@convention(thin) () -> @owned S2 + %access_1 = begin_access [modify] [static] %stack : $*S2 + store %instance_2 to [assign] %access_1 : $*S2 + end_access %access_1 : $*S2 + %which_1 = apply %condition() : $@convention(thin) () -> Builtin.Int1 + cond_br %which_1, left_1, right_1 + +left_1: + %access_2 = begin_access [deinit] [static] %stack : $*S2 + %reload_1 = load [copy] %access_2 : $*S2 + apply %end_S2(%reload_1) : $@convention(thin) (@owned S2) -> () + end_access %access_2 : $*S2 + br middle + +right_1: + apply %other() : $@convention(thin) () -> () + br middle + +middle: + %instance_3 = apply %get_value_S2() : $@convention(thin) () -> @owned S2 + %access_3 = begin_access [modify] [static] %stack : $*S2 + store %instance_3 to [assign] %access_3 : $*S2 + end_access %access_3 : $*S2 + %which_2 = apply %condition() : $@convention(thin) () -> Builtin.Int1 + cond_br %which_2, left_2, right_2 + +left_2: + %access_4 = begin_access [deinit] [static] %stack : $*S2 + %reload_2 = load [copy] %access_4 : $*S2 + apply %end_S2(%reload_2) : $@convention(thin) (@owned S2) -> () + end_access %access_4 : $*S2 + br end + +right_2: + apply %other() : $@convention(thin) () -> () + br end + +end: + %retval = tuple () + destroy_addr %stack : $*S2 + dealloc_stack %stack_addr : $*S2 + return %retval : $() +} + +// One field is consumed in either branch: s1 in left, s2 in right. The other +// field should live until the end of the block. +// CHECK-LABEL: sil [ossa] @simpleTestVar6 : $@convention(thin) () -> () { +// CHECK: [[OTHER:%[^,]+]] = function_ref @other +// CHECK: [[STACK:%[^,]+]] = alloc_stack +// CHECK: cond_br {{%[^,]+}}, [[LEFT:bb[0-9]+]], [[RIGHT:bb[0-9]+]] +// CHECK: [[LEFT]]: +// CHECK: apply [[OTHER]]() +// CHECK: [[S2_ADDR:%[^,]+]] = struct_element_addr [[STACK]] : $*S2, #S2.s2 +// CHECK: destroy_addr [[S2_ADDR]] : $*S +// CHECK: br [[EXIT:bb[0-9]+]] +// CHECK: [[RIGHT]]: +// CHECK: apply [[OTHER]]() +// CHECK: [[S1_ADDR:%[^,]+]] = struct_element_addr [[STACK]] : $*S2, #S2.s1 +// CHECK: destroy_addr [[S1_ADDR]] : $*S +// CHECK: br [[EXIT]] +// CHECK: [[EXIT]]: +// CHECK-LABEL: } // end sil function 'simpleTestVar6' +sil [ossa] @simpleTestVar6 : $@convention(thin) () -> () { +entry: + %get_value_S2 = function_ref @get_value_S2 : $@convention(thin) () -> @owned S2 + %condition = function_ref @condition : $@convention(thin) () -> Builtin.Int1 + %other = function_ref @other : $@convention(thin) () -> () + %end = function_ref @end : $@convention(thin) (@owned S) -> () + + %stack_addr = alloc_stack $S2 + %stack = mark_must_check [consumable_and_assignable] %stack_addr : $*S2 + %instance_1 = apply %get_value_S2() : $@convention(thin) () -> @owned S2 + store %instance_1 to [init] %stack : $*S2 + %instance_2 = apply %get_value_S2() : $@convention(thin) () -> @owned S2 + %access_1 = begin_access [modify] [static] %stack : $*S2 + store %instance_2 to [assign] %access_1 : $*S2 + end_access %access_1 : $*S2 + %which = apply %condition() : $@convention(thin) () -> Builtin.Int1 + cond_br %which, left, right + +left: + %access_2 = begin_access [deinit] [static] %stack : $*S2 + %s1_addr = struct_element_addr %access_2 : $*S2, #S2.s1 + %s1 = load [copy] %s1_addr : $*S + apply %end(%s1) : $@convention(thin) (@owned S) -> () + end_access %access_2 : $*S2 + apply %other() : $@convention(thin) () -> () + br exit + +right: + %access_3 = begin_access [deinit] [static] %stack : $*S2 + %s2_addr = struct_element_addr %access_3 : $*S2, #S2.s2 + %s2 = load [copy] %s2_addr : $*S + apply %end(%s2) : $@convention(thin) (@owned S) -> () + end_access %access_3 : $*S2 + apply %other() : $@convention(thin) () -> () + br exit + +exit: + %instance_3 = apply %get_value_S2() : $@convention(thin) () -> @owned S2 + %access_4 = begin_access [modify] [static] %stack : $*S2 + store %instance_3 to [assign] %access_4 : $*S2 + end_access %access_4 : $*S2 + destroy_addr %stack : $*S2 + dealloc_stack %stack_addr : $*S2 + %retval = tuple () + return %retval : $() +} + +// The struct has three fields: +// s1 is consumed in left but not right +// s2 is consumed in right but not left +// s3 is not consumed +// There is an apply of other after the consumes and at the beginning of exit. +// +// Ensure that the not-consumed-on-this-branch field (s2 in left, s1 in right) +// is destroyed after the apply of other in each branch block. Ensure that the +// unconsumed field is destroyed at function exit--after the apply of other in +// exit. +// CHECK-LABEL: sil [ossa] @simpleTestVar6a : $@convention(thin) () -> () { +// CHECK: [[OTHER:%[^,]+]] = function_ref @other : $@convention(thin) () -> () +// CHECK: [[STACK:%[^,]+]] = alloc_stack $S3 +// CHECK: cond_br {{%[^,]+}}, [[LEFT:bb[0-9]+]], [[RIGHT:bb[0-9]+]] +// CHECK: [[LEFT]]: +// CHECK: apply [[OTHER]]() : $@convention(thin) () -> () +// CHECK: [[S2_ADDR:%[^,]+]] = struct_element_addr [[STACK]] : $*S3, #S3.s2 +// CHECK: destroy_addr [[S2_ADDR]] : $*S +// CHECK: br [[EXIT:bb[0-9]+]] +// CHECK: [[RIGHT]]: +// CHECK: apply [[OTHER]]() : $@convention(thin) () -> () +// CHECK: [[S1_ADDR:%[^,]+]] = struct_element_addr [[STACK]] : $*S3, #S3.s1 +// CHECK: destroy_addr [[S1_ADDR]] : $*S +// CHECK: br [[EXIT]] +// CHECK: [[EXIT]]: +// CHECK: apply [[OTHER]]() : $@convention(thin) () -> () +// CHECK: [[S3_ADDR:%[^,]+]] = struct_element_addr [[STACK]] : $*S3, #S3.s3 +// CHECK: destroy_addr [[S3_ADDR]] : $*S +// CHECK-LABEL: } // end sil function 'simpleTestVar6a' +sil [ossa] @simpleTestVar6a : $@convention(thin) () -> () { +bb0: + %condition = function_ref @condition : $@convention(thin) () -> Builtin.Int1 + %end = function_ref @end : $@convention(thin) (@owned S) -> () + %get_value_S3 = function_ref @get_value_S3 : $@convention(thin) () -> @owned S3 + %other = function_ref @other : $@convention(thin) () -> () + + %stack_addr = alloc_stack $S3 + %stack = mark_must_check [consumable_and_assignable] %stack_addr : $*S3 + %instance_1 = apply %get_value_S3() : $@convention(thin) () -> @owned S3 + store %instance_1 to [init] %stack : $*S3 + %instance_2 = apply %get_value_S3() : $@convention(thin) () -> @owned S3 + %access_1 = begin_access [modify] [static] %stack : $*S3 + store %instance_2 to [assign] %access_1 : $*S3 + end_access %access_1 : $*S3 + %which = apply %condition() : $@convention(thin) () -> Builtin.Int1 + cond_br %which, left, right + +left: + %access_2 = begin_access [deinit] [static] %stack : $*S3 + %s1_addr = struct_element_addr %access_2 : $*S3, #S3.s1 + %s1 = load [copy] %s1_addr : $*S + apply %end(%s1) : $@convention(thin) (@owned S) -> () + end_access %access_2 : $*S3 + apply %other() : $@convention(thin) () -> () + br exit + +right: + %access_3 = begin_access [deinit] [static] %stack : $*S3 + %s2_addr = struct_element_addr %access_3 : $*S3, #S3.s2 + %s2 = load [copy] %s2_addr : $*S + apply %end(%s2) : $@convention(thin) (@owned S) -> () + end_access %access_3 : $*S3 + apply %other() : $@convention(thin) () -> () + br exit + +exit: + apply %other() : $@convention(thin) () -> () + destroy_addr %stack : $*S3 + dealloc_stack %stack_addr : $*S3 + %retval = tuple () + return %retval : $() +} + +/// The fields #S3.s1 and #S3.s3 are consumed in left but not right. +/// So they should be live until the end of right. +/// The field #S3.s2 is consumed in right but not left. +/// So it should be live until the end of left. +/// +// CHECK-LABEL: sil [ossa] @simpleTestVar6b : {{.*}} { +// CHECK: {{bb[0-9]+}}: +// CHECK: [[OTHER:%[^,]+]] = function_ref @other +// CHECK: [[STACK:%[^,]+]] = alloc_stack +// CHECK: cond_br {{%[^,]+}}, [[LEFT:bb[0-9]+]], [[RIGHT:bb[0-9]+]] +// CHECK: [[LEFT]]: +// CHECK: apply [[OTHER]]() +// CHECK: [[S2_ADDR:%[^,]+]] = struct_element_addr [[STACK]] : $*S3, #S3.s2 +// CHECK: destroy_addr [[S2_ADDR]] +// CHECK: br [[EXIT:bb[0-9]+]] +// CHECK: [[RIGHT]]: +// CHECK: apply [[OTHER]]() +// CHECK: [[S3_ADDR:%[^,]+]] = struct_element_addr [[STACK]] : $*S3, #S3.s3 +// CHECK: destroy_addr [[S3_ADDR]] +// CHECK: [[S1_ADDR:%[^,]+]] = struct_element_addr [[STACK]] : $*S3, #S3.s1 +// CHECK: destroy_addr [[S1_ADDR]] +// CHECK: br [[EXIT]] +// CHECK: [[EXIT]]: +// CHECK-LABEL: } // end sil function 'simpleTestVar6b' +sil [ossa] @simpleTestVar6b : $@convention(thin) () -> () { +entry: + %condition = function_ref @condition : $@convention(thin) () -> Builtin.Int1 + %end = function_ref @end : $@convention(thin) (@owned S) -> () + %get_value_S3 = function_ref @get_value_S3 : $@convention(thin) () -> @owned S3 + %other = function_ref @other : $@convention(thin) () -> () + + %stack_addr = alloc_stack $S3 + %stack = mark_must_check [consumable_and_assignable] %stack_addr : $*S3 + %instance_1 = apply %get_value_S3() : $@convention(thin) () -> @owned S3 + store %instance_1 to [init] %stack : $*S3 + %instance_2 = apply %get_value_S3() : $@convention(thin) () -> @owned S3 + %access_1 = begin_access [modify] [static] %stack : $*S3 + store %instance_2 to [assign] %access_1 : $*S3 + end_access %access_1 : $*S3 + %which = apply %condition() : $@convention(thin) () -> Builtin.Int1 + cond_br %which, left, right + +left: + %access_2 = begin_access [deinit] [static] %stack : $*S3 + %s1_addr = struct_element_addr %access_2 : $*S3, #S3.s1 + %s1 = load [copy] %s1_addr : $*S + apply %end(%s1) : $@convention(thin) (@owned S) -> () + end_access %access_2 : $*S3 + %access_3 = begin_access [deinit] [static] %stack : $*S3 + %s3_addr = struct_element_addr %access_3 : $*S3, #S3.s3 + %s3 = load [copy] %s3_addr : $*S + apply %end(%s3) : $@convention(thin) (@owned S) -> () + end_access %access_3 : $*S3 + apply %other() : $@convention(thin) () -> () + br exit + +right: + %access_4 = begin_access [deinit] [static] %stack : $*S3 + %s2_addr = struct_element_addr %access_4 : $*S3, #S3.s2 + %s2 = load [copy] %s2_addr : $*S + apply %end(%s2) : $@convention(thin) (@owned S) -> () + end_access %access_4 : $*S3 + apply %other() : $@convention(thin) () -> () + br exit + +exit: + apply %other() : $@convention(thin) () -> () + destroy_addr %stack : $*S3 + dealloc_stack %stack_addr : $*S3 + %retval = tuple () + return %retval : $() +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// }} Multiple blocks +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ============================================================================= +// ============================================================================= +// }} Multiple defs +// ============================================================================= +// ============================================================================= + +// ############################################################################# +// ############################################################################# +// }} AGGREGATE STORAGE +// ############################################################################# +// ############################################################################# diff --git a/test/SILOptimizer/moveonly_lifetime.swift b/test/SILOptimizer/moveonly_lifetime.swift index 46e776ed06003..c553305067ca5 100644 --- a/test/SILOptimizer/moveonly_lifetime.swift +++ b/test/SILOptimizer/moveonly_lifetime.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-emit-sil -sil-verify-all -module-name moveonly_lifetime -o /dev/null -Xllvm -sil-print-canonical-module -Onone -verify -enable-experimental-feature MoveOnlyClasses %s 2>&1 | %FileCheck %s +// RUN: %target-swift-emit-sil -sil-verify-all -module-name moveonly_lifetime -o /dev/null -Xllvm -sil-print-canonical-module -Onone -verify -enable-experimental-feature MoveOnlyClasses %s | %FileCheck %s struct C : ~Copyable { deinit {} @@ -31,17 +31,16 @@ func something() // CHECK: [[INSTANCE:%.*]] = load [take] [[STACK]] // CHECK: [[TAKE_C:%[^,]+]] = function_ref @takeC // CHECK: apply [[TAKE_C]]([[INSTANCE]]) +// CHECK: br [[BOTTOM:bb[0-9]+]] // // CHECK: [[LEFT]]: // CHECK: [[INSTANCE:%.*]] = load_borrow [[STACK]] // CHECK: [[BORROW_C:%[^,]+]] = function_ref @borrowC // CHECK: apply [[BORROW_C]]([[INSTANCE]]) -// -// TODO: Once we maximize lifetimes this should be below something. -// CHECK: destroy_addr [[STACK]] -// // CHECK: [[SOMETHING:%[^,]+]] = function_ref @something // CHECK: apply [[SOMETHING]] +// CHECK: destroy_addr [[STACK]] +// CHECK: br [[BOTTOM]] // CHECK-LABEL: } // end sil function 'test_diamond__consume_r__use_l' @_silgen_name("test_diamond__consume_r__use_l") func test_diamond(_ condition: Bool) { From 11443f26ede77958b51dcaecc40ccc56d3252018 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Fri, 16 Jun 2023 18:36:56 -0700 Subject: [PATCH 40/41] [move-only] Avoid loc from func decl. It's always the first line of the function, so try to do better. --- .../Mandatory/MoveOnlyDiagnostics.cpp | 7 +++++++ test/SILOptimizer/discard_checking.swift | 16 ++++++++-------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/lib/SILOptimizer/Mandatory/MoveOnlyDiagnostics.cpp b/lib/SILOptimizer/Mandatory/MoveOnlyDiagnostics.cpp index 4375ee9631556..db5625c07130a 100644 --- a/lib/SILOptimizer/Mandatory/MoveOnlyDiagnostics.cpp +++ b/lib/SILOptimizer/Mandatory/MoveOnlyDiagnostics.cpp @@ -14,6 +14,7 @@ #include "MoveOnlyDiagnostics.h" +#include "swift/AST/Decl.h" #include "swift/AST/DiagnosticsSIL.h" #include "swift/AST/Stmt.h" #include "swift/Basic/Defer.h" @@ -226,6 +227,12 @@ void DiagnosticEmitter::emitMissingConsumeInDiscardingContext( return true; case SILLocation::RegularKind: { + Decl *decl = loc.getAsASTNode(); + if (decl && isa(decl)) { + // Having the function itself as a location results in a location at the + // first line of the function. Find another location. + return false; + } Stmt *stmt = loc.getAsASTNode(); if (!stmt) return true; // For non-statements, assume it is exiting the func. diff --git a/test/SILOptimizer/discard_checking.swift b/test/SILOptimizer/discard_checking.swift index fbbd5d180a5af..69334b6283c36 100644 --- a/test/SILOptimizer/discard_checking.swift +++ b/test/SILOptimizer/discard_checking.swift @@ -165,7 +165,7 @@ struct Basics: ~Copyable { } } - consuming func test8_stillMissingAConsume1(_ c: Color) throws { // expected-error {{must consume 'self' before exiting method that discards self}} + consuming func test8_stillMissingAConsume1(_ c: Color) throws { if case .red = c { discard self // expected-note {{discarded self here}} return @@ -174,7 +174,7 @@ struct Basics: ~Copyable { _ = consume self fatalError("hi") } - } + } // expected-error {{must consume 'self' before exiting method that discards self}} consuming func test8_stillMissingAConsume2(_ c: Color) throws { if case .red = c { @@ -251,7 +251,7 @@ struct Basics: ~Copyable { } } - consuming func test11(_ c: Color) { // expected-error {{must consume 'self' before exiting method that discards self}} + consuming func test11(_ c: Color) { guard case .red = c else { discard self // expected-note {{discarded self here}} return @@ -264,7 +264,7 @@ struct Basics: ~Copyable { let x = self self = x mutator() - } + } // expected-error {{must consume 'self' before exiting method that discards self}} consuming func test11_fixed(_ c: Color) { guard case .red = c else { @@ -328,13 +328,13 @@ struct Basics: ~Copyable { _ = consume self } - consuming func test13(_ c: Color) async { // expected-error {{must consume 'self' before exiting method that discards self}} + consuming func test13(_ c: Color) async { guard case .red = c else { discard self // expected-note {{discarded self here}} return } await asyncer() - } + } // expected-error {{must consume 'self' before exiting method that discards self}} consuming func test13_fixed(_ c: Color) async { guard case .red = c else { @@ -345,7 +345,7 @@ struct Basics: ~Copyable { _ = consume self } - consuming func test14(_ c: Color) async { // expected-error {{must consume 'self' before exiting method that discards self}} + consuming func test14(_ c: Color) async { guard case .red = c else { discard self // expected-note {{discarded self here}} return @@ -354,7 +354,7 @@ struct Basics: ~Copyable { cont.resume() } print("back!") - } + } // expected-error {{must consume 'self' before exiting method that discards self}} consuming func test14_fixed(_ c: Color) async { guard case .red = c else { From 2bfa723951f440efb651c6fb34ac3c05ad014bc2 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Fri, 16 Jun 2023 18:42:43 -0700 Subject: [PATCH 41/41] [MoveOnlyAddressChecker] Added extension flag. Passing ``` -Xllvm -move-only-address-checker-disable-lifetime-extension=true ``` will skip the maximization of unconsumed field lifetimes. --- .../Mandatory/MoveOnlyAddressCheckerUtils.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp b/lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp index 8675e82417bee..1e52e99d8ae69 100644 --- a/lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp +++ b/lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp @@ -280,6 +280,12 @@ using namespace swift; using namespace swift::siloptimizer; +llvm::cl::opt DisableMoveOnlyAddressCheckerLifetimeExtension( + "move-only-address-checker-disable-lifetime-extension", + llvm::cl::init(false), + llvm::cl::desc("Disable the lifetime extension of non-consumed fields of " + "move-only values.")); + //===----------------------------------------------------------------------===// // MARK: Memory Utilities //===----------------------------------------------------------------------===// @@ -3181,8 +3187,10 @@ bool MoveOnlyAddressCheckerPImpl::performSingleCheck( FieldSensitivePrunedLivenessBoundary boundary(liveness.getNumSubElements()); liveness.computeBoundary(boundary); - ExtendUnconsumedLiveness extension(addressUseState, liveness, boundary); - extension.run(); + if (!DisableMoveOnlyAddressCheckerLifetimeExtension) { + ExtendUnconsumedLiveness extension(addressUseState, liveness, boundary); + extension.run(); + } boundary.clear(); liveness.computeBoundary(boundary); insertDestroysOnBoundary(markedAddress, liveness, boundary);