From fd48f8fa964511e09eb2210a40a12f63790a4719 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Fri, 27 Mar 2020 14:53:22 -0700 Subject: [PATCH 1/4] Squash warnings --- test/Prototypes/PatternMatching.swift | 29 +++++---------------------- 1 file changed, 5 insertions(+), 24 deletions(-) diff --git a/test/Prototypes/PatternMatching.swift b/test/Prototypes/PatternMatching.swift index 138bdd157917e..d98e39eeff4a6 100644 --- a/test/Prototypes/PatternMatching.swift +++ b/test/Prototypes/PatternMatching.swift @@ -35,15 +35,11 @@ protocol Pattern { func matched(atStartOf c: C) -> MatchResult where C.Index == Index, C.Element == Element - // The following requirements go away with upcoming generics features - , C.SubSequence : Collection } extension Pattern { func found(in c: C) -> (extent: Range, data: MatchData)? where C.Index == Index, C.Element == Element - // The following requirements go away with upcoming generics features - , C.SubSequence : Collection { var i = c.startIndex while i != c.endIndex { @@ -72,8 +68,6 @@ where T.Element : Equatable { func matched(atStartOf c: C) -> MatchResult where C.Index == Index, C.Element == Element - // The following requirements go away with upcoming generics features - , C.SubSequence : Collection { var i = c.startIndex for p in pattern { @@ -93,8 +87,6 @@ struct MatchAnyOne : Pattern { func matched(atStartOf c: C) -> MatchResult where C.Index == Index, C.Element == Element - // The following requirements go away with upcoming generics features - , C.SubSequence : Collection { return c.isEmpty ? .notFound(resumeAt: c.endIndex) @@ -126,8 +118,6 @@ where M0.Element == M1.Element, M0.Index == M1.Index { func matched(atStartOf c: C) -> MatchResult where C.Index == Index, C.Element == Element - // The following requirements go away with upcoming generics features - , C.SubSequence : Collection { var src0 = c[c.startIndex.. : Pattern { func matched(atStartOf c: C) -> MatchResult where C.Index == M0.Index, C.Element == M0.Element - // The following requirements go away with upcoming generics features - , C.SubSequence : Collection { var lastEnd = c.startIndex var rest = c.dropFirst(0) @@ -176,11 +164,11 @@ struct RepeatMatch : Pattern { searchLoop: while !rest.isEmpty { switch singlePattern.matched(atStartOf: rest) { - case .found(let x): - data.append(x) - lastEnd = x.end + case .found(let end1, let data1): + data.append((end1, data1)) + lastEnd = end1 if data.count == repeatLimits.upperBound { break } - rest = rest[x.end..(atStartOf c: C) -> MatchResult where C.Index == Index, C.Element == Element - // The following requirements go away with upcoming generics features - , C.SubSequence : Collection { switch matchers.0.matched(atStartOf: c) { case .found(let end, let data): @@ -292,8 +278,6 @@ struct MatchStaticString : Pattern { func matched(atStartOf c: C) -> MatchResult where C.Index == Index, C.Element == Element - // The following requirements go away with upcoming generics features - , C.SubSequence : Collection { return content.withUTF8Buffer { LiteralMatch($0).matched(atStartOf: c) @@ -327,8 +311,7 @@ extension Pattern where Element == UTF8.CodeUnit { in c: C, format: (MatchData)->String = { String(reflecting: $0) }) where C.Index == Index, C.Element == Element - // The following requirements go away with upcoming generics features - , C.SubSequence : Collection { + { print("searching for /\(self)/ in \(c.u8str)...", terminator: "") if let (extent, data) = self.found(in: c) { print( @@ -382,8 +365,6 @@ struct Paired : Pattern { func matched(atStartOf c: C) -> MatchResult where C.Index == Index, C.Element == Element - // The following requirements go away with upcoming generics features - , C.SubSequence : Collection { guard let closer = c.first.flatMap({ pairs[$0] }) else { return .notFound(resumeAt: nil) From f95cabb74539a613e24e3b2b1bf953011f967130 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Mon, 30 Mar 2020 17:48:46 -0700 Subject: [PATCH 2/4] [ConstraintSystem] Allow sequence element mismatch fix to produce new holes Type on the right-hand side of the element conversion/pattern match should be allowed to have holes to be able to diagnose failures with structurally incompatible types. Resolves: rdar://problem/60832876 --- include/swift/AST/DiagnosticsSema.def | 3 +++ lib/Sema/CSDiagnostics.cpp | 27 +++++++++++++++++++++------ lib/Sema/CSSimplify.cpp | 9 +++++++++ test/stmt/foreach.swift | 9 +++++++++ 4 files changed, 42 insertions(+), 6 deletions(-) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index bb4c200acba64..ddc35d89bf5bb 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -184,6 +184,9 @@ ERROR(value_type_comparison_with_nil_illegal,none, ERROR(cannot_match_expr_pattern_with_value,none, "expression pattern of type %0 cannot match values of type %1", (Type, Type)) +ERROR(cannot_match_expr_tuple_pattern_with_nontuple_value,none, + "tuple pattern cannot match values of non-tuple type %0", + (Type)) ERROR(cannot_match_unresolved_expr_pattern_with_value,none, "pattern cannot match values of type %0", (Type)) diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index d850427e850a3..d2b3d80d8ef18 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -4865,12 +4865,27 @@ bool CollectionElementContextualFailure::diagnoseAsError() { } if (locator->isForSequenceElementType()) { - diagnostic.emplace( - emitDiagnostic(anchor->getLoc(), - contextualType->isExistentialType() - ? diag::cannot_convert_sequence_element_protocol - : diag::cannot_convert_sequence_element_value, - eltType, contextualType)); + auto &cs = getConstraintSystem(); + // If this is a conversion failure related to binding of `for-each` + // statement it has to be diagnosed as pattern match if there are + // holes present in the contextual type. + if (cs.getContextualTypePurpose(anchor) == + ContextualTypePurpose::CTP_ForEachStmt && + contextualType->hasHole()) { + diagnostic.emplace(emitDiagnostic( + anchor->getLoc(), + (contextualType->is() && !eltType->is()) + ? diag::cannot_match_expr_tuple_pattern_with_nontuple_value + : diag::cannot_match_unresolved_expr_pattern_with_value, + eltType)); + } else { + diagnostic.emplace( + emitDiagnostic(anchor->getLoc(), + contextualType->isExistentialType() + ? diag::cannot_convert_sequence_element_protocol + : diag::cannot_convert_sequence_element_value, + eltType, contextualType)); + } } if (!diagnostic) diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 8b69ce141324b..a618c15287af3 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -3908,6 +3908,15 @@ bool ConstraintSystem::repairFailures( if (rhs->isExistentialType()) break; + // If the types didn't line up, let's allow right-hand side + // of the conversion (or pattern match) to have holes. This + // helps when conversion if between a type and a tuple e.g. + // `Int` vs. `(_, _)`. + rhs.visit([&](Type type) { + if (auto *typeVar = type->getAs()) + recordPotentialHole(typeVar); + }); + conversionsOrFixes.push_back(CollectionElementContextualMismatch::create( *this, lhs, rhs, getConstraintLocator(locator))); break; diff --git a/test/stmt/foreach.swift b/test/stmt/foreach.swift index c3f81e3135039..b5bc155b3936e 100644 --- a/test/stmt/foreach.swift +++ b/test/stmt/foreach.swift @@ -220,3 +220,12 @@ extension Int : P { } func testRepeated(ri: RepeatedSequence) { for x in ri { _ = x } } + +// SR-12398: Poor pattern matching diagnostic: "for-in loop requires '[Int]' to conform to 'Sequence'" +func sr_12398(arr1: [Int], arr2: [(a: Int, b: String)]) { + for (x, y) in arr1 {} + // expected-error@-1 {{tuple pattern cannot match values of non-tuple type 'Int'}} + + for (x, y, _) in arr2 {} + // expected-error@-1 {{pattern cannot match values of type '(a: Int, b: String)'}} +} From dcd6c6d9fa050b09357c3928e46c3bf872e01354 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 27 Mar 2020 19:42:37 -0400 Subject: [PATCH 3/4] SILOptimizer: Peephole to eliminate closures which just apply a witness_method A partial_apply of a function_ref whose body consists of just an apply of a witness_method can be simplified down to a simple partial_apply of the witness_method: sil @foo: %fn = witness_method ... %result = apply %fn(...) return %result sil @bar: %fn = function_ref @foo %closure = partial_apply %fn(...) ===> sil @bar: %fn = witness_method ... %closure = partial_apply %fn(...) --- .../SILCombiner/SILCombinerApplyVisitors.cpp | 103 +++++++++++ lib/SILOptimizer/Utils/Devirtualize.cpp | 3 +- test/SILOptimizer/sil_combine_curry_thunk.sil | 166 ++++++++++++++++++ .../sil_combine_curry_thunk.swift | 80 +++++++++ .../specialize_opaque_type_archetypes.swift | 4 +- 5 files changed, 353 insertions(+), 3 deletions(-) create mode 100644 test/SILOptimizer/sil_combine_curry_thunk.sil create mode 100644 test/SILOptimizer/sil_combine_curry_thunk.swift diff --git a/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp b/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp index 977a2f7dd7355..74270efef4dc2 100644 --- a/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp +++ b/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp @@ -78,6 +78,104 @@ static bool foldInverseReabstractionThunks(PartialApplyInst *PAI, return true; } +ApplyInst *getSingleApplyInBlock(SILBasicBlock &BB) { + ApplyInst *Result = nullptr; + + for (auto &I : BB) { + if (isa(I) || + isa(I)) + continue; + + // FIXME: Should also support ClassMethodInst + if (isa(I) || + isa(I)) + continue; + + if (auto *TI = dyn_cast(&I)) + if (TI->getElements().empty()) + continue; + + if (auto *AI = dyn_cast(&I)) { + if (Result == nullptr) { + Result = AI; + continue; + } + } + + return nullptr; + } + + return Result; +} + +static bool foldPartialApplyOfTrivialClosure(PartialApplyInst *PAI, + SILCombiner *Combiner) { + auto *FRI = dyn_cast(PAI->getCallee()); + if (FRI == nullptr) + return false; + + auto *F = FRI->getReferencedFunctionOrNull(); + if (F == nullptr) + return false; + + // The referenced function must consist of a single basic block. + if (F->getBlocks().size() != 1) + return false; + + // The referenced function must not throw. + if (F->getLoweredFunctionType()->getOptionalErrorResult()) + return false; + + // The only non-trivial instructions in the function must be an apply + // of a witness_method callee. + auto &BB = *F->getBlocks().begin(); + auto *AI = getSingleApplyInBlock(BB); + if (AI == nullptr) + return false; + + // The apply instruction must have the same number of arguments as the + // function that contains it, and they must be passed in order. + auto InnerArgs = AI->getArguments(); + if (InnerArgs.size() != BB.args_size()) + return false; + + auto ArgsIter = BB.args_begin(); + for (auto Arg : InnerArgs) { + if (Arg != *(ArgsIter++)) + return false; + } + + SILBuilderWithScope B(PAI); + + // FIXME: Should also support ClassMethodInst + auto *WMI = cast(AI->getCallee()); + auto InnerSubs = PAI->getSubstitutionMap(); + auto Subs = AI->getSubstitutionMap().subst(InnerSubs); + auto *NewCallee = B.createWitnessMethod( + WMI->getLoc(), + WMI->getLookupType().subst(InnerSubs)->getCanonicalType(), + WMI->getConformance().subst(WMI->getLookupType(), InnerSubs), + WMI->getMember(), + WMI->getType().subst(F->getModule().Types, InnerSubs)); + + SmallVector NewArgs; + auto Args = PAI->getArguments(); + NewArgs.append(Args.begin(), Args.end()); + + auto *NewPAI = B.createPartialApply( + PAI->getLoc(), + NewCallee, + Subs, + NewArgs, + PAI->getType().getAs()->getCalleeConvention(), + PAI->isOnStack()); + + assert(PAI->getType() == NewPAI->getType()); + PAI->replaceAllUsesWith(NewPAI); + Combiner->eraseInstFromFunction(*PAI); + return true; +} + SILInstruction *SILCombiner::visitPartialApplyInst(PartialApplyInst *PAI) { if (PAI->getFunction()->hasOwnership()) return nullptr; @@ -109,6 +207,11 @@ SILInstruction *SILCombiner::visitPartialApplyInst(PartialApplyInst *PAI) { if (foldInverseReabstractionThunks(PAI, this)) return nullptr; + // partial_apply %function_ref => partial_apply %witness_method if + // the body of the function_ref is just an apply %witness_method + if (foldPartialApplyOfTrivialClosure(PAI, this)) + return nullptr; + bool argsAreKeptAlive = tryOptimizeApplyOfPartialApply( PAI, Builder.getBuilderContext(), getInstModCallbacks()); if (argsAreKeptAlive) diff --git a/lib/SILOptimizer/Utils/Devirtualize.cpp b/lib/SILOptimizer/Utils/Devirtualize.cpp index 32d5c20e1fd52..6654dc8882bfb 100644 --- a/lib/SILOptimizer/Utils/Devirtualize.cpp +++ b/lib/SILOptimizer/Utils/Devirtualize.cpp @@ -589,7 +589,8 @@ replacePartialApplyInst(SILBuilder &builder, SILLocation loc, auto convention = oldPAI->getType().getAs()->getCalleeConvention(); auto *newPAI = - builder.createPartialApply(loc, newFn, newSubs, newArgs, convention); + builder.createPartialApply(loc, newFn, newSubs, newArgs, convention, + oldPAI->isOnStack()); // Check if any casting is required for the partially-applied function. SILValue resultValue = castValueToABICompatibleType( diff --git a/test/SILOptimizer/sil_combine_curry_thunk.sil b/test/SILOptimizer/sil_combine_curry_thunk.sil new file mode 100644 index 0000000000000..c89b1296dec3b --- /dev/null +++ b/test/SILOptimizer/sil_combine_curry_thunk.sil @@ -0,0 +1,166 @@ +// RUN: %target-sil-opt -enable-sil-verify-all %s -sil-combine | %FileCheck %s + +sil_stage canonical + +import Builtin +import Swift +import SwiftShims + +public protocol P { +} + +public struct S : P { + init() +} + +public protocol Curryable { + func concreteRequirement() + func genericRequirement(_: T) where T : P + func concreteRequirementSelf() -> Self + func genericRequirementSelf(_: T) -> Self where T : P + func concreteRequirementInt() -> Int + func genericRequirementInt(_: T) -> Int where T : P +} + +public protocol Q { + associatedtype S : Curryable + associatedtype U : P +} + +// CHECK-LABEL: sil @$concrete_closure : $@convention(thin) (@in_guaranteed T.S) -> @owned @callee_guaranteed () -> () { +// CHECK: [[FN:%.*]] = witness_method $T.S, #Curryable.concreteRequirement : (Self) -> () -> () : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> () +// CHECK: partial_apply [callee_guaranteed] [[FN]](%0) : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> () +// CHECK: return +sil @$concrete_closure : $@convention(thin) (@in_guaranteed T.S) -> @owned @callee_guaranteed () -> () { +bb0(%0 : $*T.S): + %fn = function_ref @$concrete_closure_inner : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.S) -> () + %closure = partial_apply [callee_guaranteed] %fn(%0) : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.S) -> () + return %closure : $@callee_guaranteed () -> () +} + +sil private @$concrete_closure_inner : $@convention(thin) (@in_guaranteed T.S) -> () { +bb0(%0 : $*T.S): + %fn = witness_method $T.S, #Curryable.concreteRequirement : (Self) -> () -> () : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> () + %result = apply %fn(%0) : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> () + %void = tuple () + return %void : $() +} + +// CHECK-LABEL: sil @$generic_closure : $@convention(thin) (@in_guaranteed T.S) -> @owned @callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> () for { +// CHECK: [[FN:%.*]] = witness_method $T.S, #Curryable.genericRequirement : (Self) -> (T) -> () : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable><τ_1_0 where τ_1_0 : P> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> () +// CHECK: partial_apply [callee_guaranteed] [[FN]](%0) : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable><τ_1_0 where τ_1_0 : P> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> () +// CHECK: return +sil @$generic_closure : $@convention(thin) (@in_guaranteed T.S) -> @owned @callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> () for { +bb0(%0 : $*T.S): + %fn = function_ref @$generic_closure_inner : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.U, @in_guaranteed τ_0_0.S) -> () + %closure = partial_apply [callee_guaranteed] %fn(%0) : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.U, @in_guaranteed τ_0_0.S) -> () + %converted = convert_function %closure : $@callee_guaranteed (@in_guaranteed T.U) -> () to $@callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> () for + return %converted : $@callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> () for +} + +sil private @$generic_closure_inner : $@convention(thin) (@in_guaranteed T.U, @in_guaranteed T.S) -> () { +bb0(%0 : $*T.U, %1 : $*T.S): + %fn = witness_method $T.S, #Curryable.genericRequirement : (Self) -> (T) -> () : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable><τ_1_0 where τ_1_0 : P> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> () + %result = apply %fn(%0, %1) : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable><τ_1_0 where τ_1_0 : P> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> () + %void = tuple () + return %void : $() +} + +// CHECK-LABEL: sil @$concrete_self_closure : $@convention(thin) (@in_guaranteed T.S) -> @owned @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for { +// CHECK: [[FN:%.*]] = witness_method $T.S, #Curryable.concreteRequirementSelf : (Self) -> () -> Self : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> @out τ_0_0 +// CHECK: partial_apply [callee_guaranteed] [[FN]](%0) : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> @out τ_0_0 +// CHECK: return +sil @$concrete_self_closure : $@convention(thin) (@in_guaranteed T.S) -> @owned @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for { +bb0(%0 : $*T.S): + %fn = function_ref @$concrete_self_closure_inner : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.S) -> @out τ_0_0.S + %closure = partial_apply [callee_guaranteed] %fn(%0) : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.S) -> @out τ_0_0.S + %converted = convert_function %closure : $@callee_guaranteed () -> @out T.S to $@callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for + return %converted : $@callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for +} + +sil private @$concrete_self_closure_inner : $@convention(thin) (@in_guaranteed T.S) -> @out T.S { +bb0(%0 : $*T.S, %1 : $*T.S): + %fn = witness_method $T.S, #Curryable.concreteRequirementSelf : (Self) -> () -> Self : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> @out τ_0_0 + %result = apply %fn(%0, %1) : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> @out τ_0_0 + %void = tuple () + return %result : $() +} + +// CHECK-LABEL: sil @$generic_self_closure : $@convention(thin) (@in_guaranteed T.S) -> @owned @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for { +// CHECK: [[FN:%.*]] = witness_method $T.S, #Curryable.genericRequirementSelf : (Self) -> (T) -> Self : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable><τ_1_0 where τ_1_0 : P> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> @out τ_0_0 +// CHECK: partial_apply [callee_guaranteed] [[FN]](%0) : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable><τ_1_0 where τ_1_0 : P> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> @out τ_0_0 +// CHECK: return +sil @$generic_self_closure : $@convention(thin) (@in_guaranteed T.S) -> @owned @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for { +bb0(%0 : $*T.S): + %fn = function_ref @$generic_self_closure_inner : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.U, @in_guaranteed τ_0_0.S) -> @out τ_0_0.S + %closure = partial_apply [callee_guaranteed] %fn(%0) : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.U, @in_guaranteed τ_0_0.S) -> @out τ_0_0.S + %converted = convert_function %closure : $@callee_guaranteed (@in_guaranteed T.U) -> @out T.S to $@callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for + return %converted : $@callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for +} + +sil private @$generic_self_closure_inner : $@convention(thin) (@in_guaranteed T.U, @in_guaranteed T.S) -> @out T.S { +bb0(%0 : $*T.S, %1 : $*T.U, %2 : $*T.S): + %fn = witness_method $T.S, #Curryable.genericRequirementSelf : (Self) -> (T) -> Self : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable><τ_1_0 where τ_1_0 : P> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> @out τ_0_0 + %result = apply %fn(%0, %1, %2) : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable><τ_1_0 where τ_1_0 : P> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> @out τ_0_0 + %void = tuple () + return %void : $() +} + +// CHECK-LABEL: sil @$concrete_int_closure : $@convention(thin) (@in_guaranteed T.S) -> @owned @callee_guaranteed () -> Int { +// CHECK: [[FN:%.*]] = witness_method $T.S, #Curryable.concreteRequirementInt : (Self) -> () -> Int : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> Int +// CHECK: partial_apply [callee_guaranteed] [[FN]](%0) : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> Int +// CHECK: return +sil @$concrete_int_closure : $@convention(thin) (@in_guaranteed T.S) -> @owned @callee_guaranteed () -> Int { +bb0(%0 : $*T.S): + %fn = function_ref @$concrete_int_closure_inner : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.S) -> Int + %closure = partial_apply [callee_guaranteed] %fn(%0) : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.S) -> Int + return %closure : $@callee_guaranteed () -> Int +} + +sil private @$concrete_int_closure_inner : $@convention(thin) (@in_guaranteed T.S) -> Int { +bb0(%0 : $*T.S): + %fn = witness_method $T.S, #Curryable.concreteRequirementInt : (Self) -> () -> Int : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> Int + %result = apply %fn(%0) : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> Int + return %result : $Int +} + +// CHECK-LABEL: sil @$generic_int_closure : $@convention(thin) (@in_guaranteed T.S) -> @owned @callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> Int for { +// CHECK: [[FN:%.*]] = witness_method $T.S, #Curryable.genericRequirementInt : (Self) -> (T) -> Int : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable><τ_1_0 where τ_1_0 : P> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> Int +// CHECK: partial_apply [callee_guaranteed] [[FN]](%0) : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable><τ_1_0 where τ_1_0 : P> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> Int +// CHECK: return +sil @$generic_int_closure : $@convention(thin) (@in_guaranteed T.S) -> @owned @callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> Int for { +bb0(%0 : $*T.S): + %fn = function_ref @$generic_int_closure_inner : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.U, @in_guaranteed τ_0_0.S) -> Int + %closure = partial_apply [callee_guaranteed] %fn(%0) : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.U, @in_guaranteed τ_0_0.S) -> Int + %converted = convert_function %closure : $@callee_guaranteed (@in_guaranteed T.U) -> Int to $@callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> Int for + return %converted : $@callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> Int for +} + +sil private @$generic_int_closure_inner : $@convention(thin) (@in_guaranteed T.U, @in_guaranteed T.S) -> Int { +bb0(%0 : $*T.U, %1 : $*T.S): + %fn = witness_method $T.S, #Curryable.genericRequirementInt : (Self) -> (T) -> Int : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable><τ_1_0 where τ_1_0 : P> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> Int + %result = apply %fn(%0, %1) : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable><τ_1_0 where τ_1_0 : P> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> Int + return %result : $Int +} + +// CHECK-LABEL: sil @$concrete_closure_throws : $@convention(thin) (@in_guaranteed T.S) -> @owned @callee_guaranteed () -> @error Error { +// CHECK: [[FN:%.*]] = function_ref @$concrete_closure_inner_throws +// CHECK: partial_apply [callee_guaranteed] [[FN]](%0) : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.S) -> @error Error +// CHECK: return +sil @$concrete_closure_throws : $@convention(thin) (@in_guaranteed T.S) -> @owned @callee_guaranteed () -> @error Error { +bb0(%0 : $*T.S): + %fn = function_ref @$concrete_closure_inner_throws : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.S) -> (@error Error) + %closure = partial_apply [callee_guaranteed] %fn(%0) : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.S) -> (@error Error) + return %closure : $@callee_guaranteed () -> (@error Swift.Error) +} + +sil private @$concrete_closure_inner_throws : $@convention(thin) (@in_guaranteed T.S) -> @error Swift.Error { +bb0(%0 : $*T.S): + %fn = witness_method $T.S, #Curryable.concreteRequirement : (Self) -> () -> () : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> () + %result = apply %fn(%0) : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> () + %void = tuple () + return %void : $() +} + +sil_witness_table [serialized] S: P module sil_combine_curry_thunk { +} \ No newline at end of file diff --git a/test/SILOptimizer/sil_combine_curry_thunk.swift b/test/SILOptimizer/sil_combine_curry_thunk.swift new file mode 100644 index 0000000000000..b485743aaf293 --- /dev/null +++ b/test/SILOptimizer/sil_combine_curry_thunk.swift @@ -0,0 +1,80 @@ +// RUN: %target-swift-frontend -O -emit-sil %s | %FileCheck %s + +public protocol P {} + +public struct S : P {} + +public protocol Curryable { + func concreteRequirement() + func genericRequirement(_: T) + func concreteRequirementSelf() -> Self + func genericRequirementSelf(_: T) -> Self + func concreteRequirementInt() -> Int + func genericRequirementInt(_: T) -> Int +} + +public protocol Q { + associatedtype S : Curryable + associatedtype U : P +} + +@_optimize(none) +public func sinkThrows(_: () throws -> ()) {} + +@_optimize(none) +public func sink0(_: () -> Result) {} + +@_optimize(none) +public func sink1(_: Input.Type, _: (Input) -> Result) {} + +public func abstractCurried(t: T, s: T.S, u: T.U.Type) { + sink0(s.concreteRequirement) + sink1(u, s.genericRequirement) + sink0(s.concreteRequirementSelf) + sink1(u, s.genericRequirementSelf) + sink0(s.concreteRequirementInt) + sink1(u, s.genericRequirementInt) + sinkThrows({ () throws -> () in s.concreteRequirement() }) +} + +// CHECK-LABEL: sil private @$s23sil_combine_curry_thunk15abstractCurried1t1s1uyx_1SQz1UQzmtAA1QRzlFyycAGcfu_ : $@convention(thin) (@in_guaranteed T.S) -> @owned @callee_guaranteed () -> () { +// CHECK: [[ARG:%.*]] = alloc_stack $T.S +// CHECK: copy_addr %0 to [initialization] [[ARG]] : $*T.S +// CHECK: [[FN:%.*]] = witness_method $T.S, #Curryable.concreteRequirement : (Self) -> () -> () : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> () +// CHECK: partial_apply [callee_guaranteed] [[FN]]([[ARG]]) +// CHECK: return + +// CHECK-LABEL: sil private @$s23sil_combine_curry_thunk15abstractCurried1t1s1uyx_1SQz1UQzmtAA1QRzlFyAIcAGcfu1_ : $@convention(thin) (@in_guaranteed T.S) -> @owned @callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> () for { +// CHECK: [[ARG:%.*]] = alloc_stack $T.S +// CHECK: copy_addr %0 to [initialization] [[ARG]] : $*T.S +// CHECK: [[FN:%.*]] = witness_method $T.S, #Curryable.genericRequirement : (Self) -> (T) -> () : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable><τ_1_0 where τ_1_0 : P> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> () +// CHECK: partial_apply [callee_guaranteed] [[FN]]([[ARG]]) +// CHECK: return + +// CHECK-LABEL: sil private @$s23sil_combine_curry_thunk15abstractCurried1t1s1uyx_1SQz1UQzmtAA1QRzlFAGycAGcfu3_ : $@convention(thin) (@in_guaranteed T.S) -> @owned @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for { +// CHECK: [[ARG:%.*]] = alloc_stack $T.S +// CHECK: copy_addr %0 to [initialization] [[ARG]] : $*T.S +// CHECK: [[FN:%.*]] = witness_method $T.S, #Curryable.concreteRequirementSelf : (Self) -> () -> Self : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> @out τ_0_0 +// CHECK: partial_apply [callee_guaranteed] [[FN]]([[ARG]]) +// CHECK: return + +// CHECK-LABEL: sil private @$s23sil_combine_curry_thunk15abstractCurried1t1s1uyx_1SQz1UQzmtAA1QRzlFAgIcAGcfu5_ : $@convention(thin) (@in_guaranteed T.S) -> @owned @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for { +// CHECK: [[ARG:%.*]] = alloc_stack $T.S +// CHECK: copy_addr %0 to [initialization] [[ARG]] : $*T.S +// CHECK: [[FN:%.*]] = witness_method $T.S, #Curryable.genericRequirementSelf : (Self) -> (T) -> Self : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable><τ_1_0 where τ_1_0 : P> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> @out τ_0_0 +// CHECK: partial_apply [callee_guaranteed] [[FN]]([[ARG]]) +// CHECK: return + +// CHECK-LABEL: sil private @$s23sil_combine_curry_thunk15abstractCurried1t1s1uyx_1SQz1UQzmtAA1QRzlFSiycAGcfu7_ : $@convention(thin) (@in_guaranteed T.S) -> @owned @callee_guaranteed () -> Int { +// CHECK: [[ARG:%.*]] = alloc_stack $T.S +// CHECK: copy_addr %0 to [initialization] [[ARG]] : $*T.S +// CHECK: [[FN:%.*]] = witness_method $T.S, #Curryable.concreteRequirementInt : (Self) -> () -> Int : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> Int +// CHECK: partial_apply [callee_guaranteed] %4(%2) : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> Int +// CHECK: return + +// CHECK-LABEL: sil private @$s23sil_combine_curry_thunk15abstractCurried1t1s1uyx_1SQz1UQzmtAA1QRzlFSiAIcAGcfu9_ : $@convention(thin) (@in_guaranteed T.S) -> @owned @callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> Int for { +// CHECK: [[ARG:%.*]] = alloc_stack $T.S +// CHECK: copy_addr %0 to [initialization] [[ARG]] : $*T.S +// CHECK: [[FN:%.*]] = witness_method $T.S, #Curryable.genericRequirementInt : (Self) -> (T) -> Int : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable><τ_1_0 where τ_1_0 : P> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> Int +// CHECK: partial_apply [callee_guaranteed] [[FN]]([[ARG]]) +// CHECK: return \ No newline at end of file diff --git a/test/SILOptimizer/specialize_opaque_type_archetypes.swift b/test/SILOptimizer/specialize_opaque_type_archetypes.swift index c83372ea4bd78..4bbede8502c26 100644 --- a/test/SILOptimizer/specialize_opaque_type_archetypes.swift +++ b/test/SILOptimizer/specialize_opaque_type_archetypes.swift @@ -412,8 +412,8 @@ func testIt(cl: (Int64) throws -> T) { // CHECK-LABEL: sil shared [noinline] @$s1A16testPartialApplyyyxAA2P4RzlFAA2PAV_Tg5 // CHECK: [[PA:%.*]] = alloc_stack $PA // CHECK: store %0 to [[PA]] : $*PA -// CHECK: [[F:%.*]] = function_ref @$s1A16testPartialApplyyyxAA2P4RzlF2ATQzs5Int64Vcxcfu_AeGcfu0_AA2PAV_TG5 : $@convention(thin) (Int64, @in_guaranteed PA) -> @out Int64 -// CHECK: [[C:%.*]] = partial_apply [callee_guaranteed] [[F]]([[PA]]) : $@convention(thin) (Int64, @in_guaranteed PA) -> @out Int64 +// CHECK: [[F:%.*]] = function_ref @$s1A2PAVAA2P4A2aDP3fooy2ATQzs5Int64VFTW : $@convention(witness_method: P4) (Int64, @in_guaranteed PA) -> @out Int64 +// CHECK: [[C:%.*]] = partial_apply [callee_guaranteed] [[F]]([[PA]]) : $@convention(witness_method: P4) (Int64, @in_guaranteed PA) -> @out Int64 // CHECK: convert_function [[C]] : $@callee_guaranteed (Int64) -> @out Int64 to $@callee_guaranteed @substituted <τ_0_0> (Int64) -> (@out τ_0_0, @error Error) for @inline(never) func testPartialApply(_ t: T) { From cf474db442a7a0231eed4136c22a5daaefd9c6b4 Mon Sep 17 00:00:00 2001 From: Mishal Shah Date: Tue, 31 Mar 2020 12:12:40 -0700 Subject: [PATCH 4/4] Revert "SILOptimizer: Peephole to eliminate closures which just apply a witness_method" --- .../SILCombiner/SILCombinerApplyVisitors.cpp | 103 ----------- lib/SILOptimizer/Utils/Devirtualize.cpp | 3 +- test/SILOptimizer/sil_combine_curry_thunk.sil | 166 ------------------ .../sil_combine_curry_thunk.swift | 80 --------- .../specialize_opaque_type_archetypes.swift | 4 +- 5 files changed, 3 insertions(+), 353 deletions(-) delete mode 100644 test/SILOptimizer/sil_combine_curry_thunk.sil delete mode 100644 test/SILOptimizer/sil_combine_curry_thunk.swift diff --git a/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp b/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp index 74270efef4dc2..977a2f7dd7355 100644 --- a/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp +++ b/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp @@ -78,104 +78,6 @@ static bool foldInverseReabstractionThunks(PartialApplyInst *PAI, return true; } -ApplyInst *getSingleApplyInBlock(SILBasicBlock &BB) { - ApplyInst *Result = nullptr; - - for (auto &I : BB) { - if (isa(I) || - isa(I)) - continue; - - // FIXME: Should also support ClassMethodInst - if (isa(I) || - isa(I)) - continue; - - if (auto *TI = dyn_cast(&I)) - if (TI->getElements().empty()) - continue; - - if (auto *AI = dyn_cast(&I)) { - if (Result == nullptr) { - Result = AI; - continue; - } - } - - return nullptr; - } - - return Result; -} - -static bool foldPartialApplyOfTrivialClosure(PartialApplyInst *PAI, - SILCombiner *Combiner) { - auto *FRI = dyn_cast(PAI->getCallee()); - if (FRI == nullptr) - return false; - - auto *F = FRI->getReferencedFunctionOrNull(); - if (F == nullptr) - return false; - - // The referenced function must consist of a single basic block. - if (F->getBlocks().size() != 1) - return false; - - // The referenced function must not throw. - if (F->getLoweredFunctionType()->getOptionalErrorResult()) - return false; - - // The only non-trivial instructions in the function must be an apply - // of a witness_method callee. - auto &BB = *F->getBlocks().begin(); - auto *AI = getSingleApplyInBlock(BB); - if (AI == nullptr) - return false; - - // The apply instruction must have the same number of arguments as the - // function that contains it, and they must be passed in order. - auto InnerArgs = AI->getArguments(); - if (InnerArgs.size() != BB.args_size()) - return false; - - auto ArgsIter = BB.args_begin(); - for (auto Arg : InnerArgs) { - if (Arg != *(ArgsIter++)) - return false; - } - - SILBuilderWithScope B(PAI); - - // FIXME: Should also support ClassMethodInst - auto *WMI = cast(AI->getCallee()); - auto InnerSubs = PAI->getSubstitutionMap(); - auto Subs = AI->getSubstitutionMap().subst(InnerSubs); - auto *NewCallee = B.createWitnessMethod( - WMI->getLoc(), - WMI->getLookupType().subst(InnerSubs)->getCanonicalType(), - WMI->getConformance().subst(WMI->getLookupType(), InnerSubs), - WMI->getMember(), - WMI->getType().subst(F->getModule().Types, InnerSubs)); - - SmallVector NewArgs; - auto Args = PAI->getArguments(); - NewArgs.append(Args.begin(), Args.end()); - - auto *NewPAI = B.createPartialApply( - PAI->getLoc(), - NewCallee, - Subs, - NewArgs, - PAI->getType().getAs()->getCalleeConvention(), - PAI->isOnStack()); - - assert(PAI->getType() == NewPAI->getType()); - PAI->replaceAllUsesWith(NewPAI); - Combiner->eraseInstFromFunction(*PAI); - return true; -} - SILInstruction *SILCombiner::visitPartialApplyInst(PartialApplyInst *PAI) { if (PAI->getFunction()->hasOwnership()) return nullptr; @@ -207,11 +109,6 @@ SILInstruction *SILCombiner::visitPartialApplyInst(PartialApplyInst *PAI) { if (foldInverseReabstractionThunks(PAI, this)) return nullptr; - // partial_apply %function_ref => partial_apply %witness_method if - // the body of the function_ref is just an apply %witness_method - if (foldPartialApplyOfTrivialClosure(PAI, this)) - return nullptr; - bool argsAreKeptAlive = tryOptimizeApplyOfPartialApply( PAI, Builder.getBuilderContext(), getInstModCallbacks()); if (argsAreKeptAlive) diff --git a/lib/SILOptimizer/Utils/Devirtualize.cpp b/lib/SILOptimizer/Utils/Devirtualize.cpp index 6654dc8882bfb..32d5c20e1fd52 100644 --- a/lib/SILOptimizer/Utils/Devirtualize.cpp +++ b/lib/SILOptimizer/Utils/Devirtualize.cpp @@ -589,8 +589,7 @@ replacePartialApplyInst(SILBuilder &builder, SILLocation loc, auto convention = oldPAI->getType().getAs()->getCalleeConvention(); auto *newPAI = - builder.createPartialApply(loc, newFn, newSubs, newArgs, convention, - oldPAI->isOnStack()); + builder.createPartialApply(loc, newFn, newSubs, newArgs, convention); // Check if any casting is required for the partially-applied function. SILValue resultValue = castValueToABICompatibleType( diff --git a/test/SILOptimizer/sil_combine_curry_thunk.sil b/test/SILOptimizer/sil_combine_curry_thunk.sil deleted file mode 100644 index c89b1296dec3b..0000000000000 --- a/test/SILOptimizer/sil_combine_curry_thunk.sil +++ /dev/null @@ -1,166 +0,0 @@ -// RUN: %target-sil-opt -enable-sil-verify-all %s -sil-combine | %FileCheck %s - -sil_stage canonical - -import Builtin -import Swift -import SwiftShims - -public protocol P { -} - -public struct S : P { - init() -} - -public protocol Curryable { - func concreteRequirement() - func genericRequirement(_: T) where T : P - func concreteRequirementSelf() -> Self - func genericRequirementSelf(_: T) -> Self where T : P - func concreteRequirementInt() -> Int - func genericRequirementInt(_: T) -> Int where T : P -} - -public protocol Q { - associatedtype S : Curryable - associatedtype U : P -} - -// CHECK-LABEL: sil @$concrete_closure : $@convention(thin) (@in_guaranteed T.S) -> @owned @callee_guaranteed () -> () { -// CHECK: [[FN:%.*]] = witness_method $T.S, #Curryable.concreteRequirement : (Self) -> () -> () : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> () -// CHECK: partial_apply [callee_guaranteed] [[FN]](%0) : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> () -// CHECK: return -sil @$concrete_closure : $@convention(thin) (@in_guaranteed T.S) -> @owned @callee_guaranteed () -> () { -bb0(%0 : $*T.S): - %fn = function_ref @$concrete_closure_inner : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.S) -> () - %closure = partial_apply [callee_guaranteed] %fn(%0) : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.S) -> () - return %closure : $@callee_guaranteed () -> () -} - -sil private @$concrete_closure_inner : $@convention(thin) (@in_guaranteed T.S) -> () { -bb0(%0 : $*T.S): - %fn = witness_method $T.S, #Curryable.concreteRequirement : (Self) -> () -> () : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> () - %result = apply %fn(%0) : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> () - %void = tuple () - return %void : $() -} - -// CHECK-LABEL: sil @$generic_closure : $@convention(thin) (@in_guaranteed T.S) -> @owned @callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> () for { -// CHECK: [[FN:%.*]] = witness_method $T.S, #Curryable.genericRequirement : (Self) -> (T) -> () : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable><τ_1_0 where τ_1_0 : P> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> () -// CHECK: partial_apply [callee_guaranteed] [[FN]](%0) : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable><τ_1_0 where τ_1_0 : P> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> () -// CHECK: return -sil @$generic_closure : $@convention(thin) (@in_guaranteed T.S) -> @owned @callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> () for { -bb0(%0 : $*T.S): - %fn = function_ref @$generic_closure_inner : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.U, @in_guaranteed τ_0_0.S) -> () - %closure = partial_apply [callee_guaranteed] %fn(%0) : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.U, @in_guaranteed τ_0_0.S) -> () - %converted = convert_function %closure : $@callee_guaranteed (@in_guaranteed T.U) -> () to $@callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> () for - return %converted : $@callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> () for -} - -sil private @$generic_closure_inner : $@convention(thin) (@in_guaranteed T.U, @in_guaranteed T.S) -> () { -bb0(%0 : $*T.U, %1 : $*T.S): - %fn = witness_method $T.S, #Curryable.genericRequirement : (Self) -> (T) -> () : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable><τ_1_0 where τ_1_0 : P> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> () - %result = apply %fn(%0, %1) : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable><τ_1_0 where τ_1_0 : P> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> () - %void = tuple () - return %void : $() -} - -// CHECK-LABEL: sil @$concrete_self_closure : $@convention(thin) (@in_guaranteed T.S) -> @owned @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for { -// CHECK: [[FN:%.*]] = witness_method $T.S, #Curryable.concreteRequirementSelf : (Self) -> () -> Self : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> @out τ_0_0 -// CHECK: partial_apply [callee_guaranteed] [[FN]](%0) : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> @out τ_0_0 -// CHECK: return -sil @$concrete_self_closure : $@convention(thin) (@in_guaranteed T.S) -> @owned @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for { -bb0(%0 : $*T.S): - %fn = function_ref @$concrete_self_closure_inner : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.S) -> @out τ_0_0.S - %closure = partial_apply [callee_guaranteed] %fn(%0) : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.S) -> @out τ_0_0.S - %converted = convert_function %closure : $@callee_guaranteed () -> @out T.S to $@callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for - return %converted : $@callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for -} - -sil private @$concrete_self_closure_inner : $@convention(thin) (@in_guaranteed T.S) -> @out T.S { -bb0(%0 : $*T.S, %1 : $*T.S): - %fn = witness_method $T.S, #Curryable.concreteRequirementSelf : (Self) -> () -> Self : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> @out τ_0_0 - %result = apply %fn(%0, %1) : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> @out τ_0_0 - %void = tuple () - return %result : $() -} - -// CHECK-LABEL: sil @$generic_self_closure : $@convention(thin) (@in_guaranteed T.S) -> @owned @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for { -// CHECK: [[FN:%.*]] = witness_method $T.S, #Curryable.genericRequirementSelf : (Self) -> (T) -> Self : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable><τ_1_0 where τ_1_0 : P> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> @out τ_0_0 -// CHECK: partial_apply [callee_guaranteed] [[FN]](%0) : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable><τ_1_0 where τ_1_0 : P> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> @out τ_0_0 -// CHECK: return -sil @$generic_self_closure : $@convention(thin) (@in_guaranteed T.S) -> @owned @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for { -bb0(%0 : $*T.S): - %fn = function_ref @$generic_self_closure_inner : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.U, @in_guaranteed τ_0_0.S) -> @out τ_0_0.S - %closure = partial_apply [callee_guaranteed] %fn(%0) : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.U, @in_guaranteed τ_0_0.S) -> @out τ_0_0.S - %converted = convert_function %closure : $@callee_guaranteed (@in_guaranteed T.U) -> @out T.S to $@callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for - return %converted : $@callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for -} - -sil private @$generic_self_closure_inner : $@convention(thin) (@in_guaranteed T.U, @in_guaranteed T.S) -> @out T.S { -bb0(%0 : $*T.S, %1 : $*T.U, %2 : $*T.S): - %fn = witness_method $T.S, #Curryable.genericRequirementSelf : (Self) -> (T) -> Self : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable><τ_1_0 where τ_1_0 : P> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> @out τ_0_0 - %result = apply %fn(%0, %1, %2) : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable><τ_1_0 where τ_1_0 : P> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> @out τ_0_0 - %void = tuple () - return %void : $() -} - -// CHECK-LABEL: sil @$concrete_int_closure : $@convention(thin) (@in_guaranteed T.S) -> @owned @callee_guaranteed () -> Int { -// CHECK: [[FN:%.*]] = witness_method $T.S, #Curryable.concreteRequirementInt : (Self) -> () -> Int : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> Int -// CHECK: partial_apply [callee_guaranteed] [[FN]](%0) : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> Int -// CHECK: return -sil @$concrete_int_closure : $@convention(thin) (@in_guaranteed T.S) -> @owned @callee_guaranteed () -> Int { -bb0(%0 : $*T.S): - %fn = function_ref @$concrete_int_closure_inner : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.S) -> Int - %closure = partial_apply [callee_guaranteed] %fn(%0) : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.S) -> Int - return %closure : $@callee_guaranteed () -> Int -} - -sil private @$concrete_int_closure_inner : $@convention(thin) (@in_guaranteed T.S) -> Int { -bb0(%0 : $*T.S): - %fn = witness_method $T.S, #Curryable.concreteRequirementInt : (Self) -> () -> Int : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> Int - %result = apply %fn(%0) : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> Int - return %result : $Int -} - -// CHECK-LABEL: sil @$generic_int_closure : $@convention(thin) (@in_guaranteed T.S) -> @owned @callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> Int for { -// CHECK: [[FN:%.*]] = witness_method $T.S, #Curryable.genericRequirementInt : (Self) -> (T) -> Int : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable><τ_1_0 where τ_1_0 : P> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> Int -// CHECK: partial_apply [callee_guaranteed] [[FN]](%0) : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable><τ_1_0 where τ_1_0 : P> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> Int -// CHECK: return -sil @$generic_int_closure : $@convention(thin) (@in_guaranteed T.S) -> @owned @callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> Int for { -bb0(%0 : $*T.S): - %fn = function_ref @$generic_int_closure_inner : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.U, @in_guaranteed τ_0_0.S) -> Int - %closure = partial_apply [callee_guaranteed] %fn(%0) : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.U, @in_guaranteed τ_0_0.S) -> Int - %converted = convert_function %closure : $@callee_guaranteed (@in_guaranteed T.U) -> Int to $@callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> Int for - return %converted : $@callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> Int for -} - -sil private @$generic_int_closure_inner : $@convention(thin) (@in_guaranteed T.U, @in_guaranteed T.S) -> Int { -bb0(%0 : $*T.U, %1 : $*T.S): - %fn = witness_method $T.S, #Curryable.genericRequirementInt : (Self) -> (T) -> Int : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable><τ_1_0 where τ_1_0 : P> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> Int - %result = apply %fn(%0, %1) : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable><τ_1_0 where τ_1_0 : P> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> Int - return %result : $Int -} - -// CHECK-LABEL: sil @$concrete_closure_throws : $@convention(thin) (@in_guaranteed T.S) -> @owned @callee_guaranteed () -> @error Error { -// CHECK: [[FN:%.*]] = function_ref @$concrete_closure_inner_throws -// CHECK: partial_apply [callee_guaranteed] [[FN]](%0) : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.S) -> @error Error -// CHECK: return -sil @$concrete_closure_throws : $@convention(thin) (@in_guaranteed T.S) -> @owned @callee_guaranteed () -> @error Error { -bb0(%0 : $*T.S): - %fn = function_ref @$concrete_closure_inner_throws : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.S) -> (@error Error) - %closure = partial_apply [callee_guaranteed] %fn(%0) : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.S) -> (@error Error) - return %closure : $@callee_guaranteed () -> (@error Swift.Error) -} - -sil private @$concrete_closure_inner_throws : $@convention(thin) (@in_guaranteed T.S) -> @error Swift.Error { -bb0(%0 : $*T.S): - %fn = witness_method $T.S, #Curryable.concreteRequirement : (Self) -> () -> () : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> () - %result = apply %fn(%0) : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> () - %void = tuple () - return %void : $() -} - -sil_witness_table [serialized] S: P module sil_combine_curry_thunk { -} \ No newline at end of file diff --git a/test/SILOptimizer/sil_combine_curry_thunk.swift b/test/SILOptimizer/sil_combine_curry_thunk.swift deleted file mode 100644 index b485743aaf293..0000000000000 --- a/test/SILOptimizer/sil_combine_curry_thunk.swift +++ /dev/null @@ -1,80 +0,0 @@ -// RUN: %target-swift-frontend -O -emit-sil %s | %FileCheck %s - -public protocol P {} - -public struct S : P {} - -public protocol Curryable { - func concreteRequirement() - func genericRequirement(_: T) - func concreteRequirementSelf() -> Self - func genericRequirementSelf(_: T) -> Self - func concreteRequirementInt() -> Int - func genericRequirementInt(_: T) -> Int -} - -public protocol Q { - associatedtype S : Curryable - associatedtype U : P -} - -@_optimize(none) -public func sinkThrows(_: () throws -> ()) {} - -@_optimize(none) -public func sink0(_: () -> Result) {} - -@_optimize(none) -public func sink1(_: Input.Type, _: (Input) -> Result) {} - -public func abstractCurried(t: T, s: T.S, u: T.U.Type) { - sink0(s.concreteRequirement) - sink1(u, s.genericRequirement) - sink0(s.concreteRequirementSelf) - sink1(u, s.genericRequirementSelf) - sink0(s.concreteRequirementInt) - sink1(u, s.genericRequirementInt) - sinkThrows({ () throws -> () in s.concreteRequirement() }) -} - -// CHECK-LABEL: sil private @$s23sil_combine_curry_thunk15abstractCurried1t1s1uyx_1SQz1UQzmtAA1QRzlFyycAGcfu_ : $@convention(thin) (@in_guaranteed T.S) -> @owned @callee_guaranteed () -> () { -// CHECK: [[ARG:%.*]] = alloc_stack $T.S -// CHECK: copy_addr %0 to [initialization] [[ARG]] : $*T.S -// CHECK: [[FN:%.*]] = witness_method $T.S, #Curryable.concreteRequirement : (Self) -> () -> () : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> () -// CHECK: partial_apply [callee_guaranteed] [[FN]]([[ARG]]) -// CHECK: return - -// CHECK-LABEL: sil private @$s23sil_combine_curry_thunk15abstractCurried1t1s1uyx_1SQz1UQzmtAA1QRzlFyAIcAGcfu1_ : $@convention(thin) (@in_guaranteed T.S) -> @owned @callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> () for { -// CHECK: [[ARG:%.*]] = alloc_stack $T.S -// CHECK: copy_addr %0 to [initialization] [[ARG]] : $*T.S -// CHECK: [[FN:%.*]] = witness_method $T.S, #Curryable.genericRequirement : (Self) -> (T) -> () : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable><τ_1_0 where τ_1_0 : P> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> () -// CHECK: partial_apply [callee_guaranteed] [[FN]]([[ARG]]) -// CHECK: return - -// CHECK-LABEL: sil private @$s23sil_combine_curry_thunk15abstractCurried1t1s1uyx_1SQz1UQzmtAA1QRzlFAGycAGcfu3_ : $@convention(thin) (@in_guaranteed T.S) -> @owned @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for { -// CHECK: [[ARG:%.*]] = alloc_stack $T.S -// CHECK: copy_addr %0 to [initialization] [[ARG]] : $*T.S -// CHECK: [[FN:%.*]] = witness_method $T.S, #Curryable.concreteRequirementSelf : (Self) -> () -> Self : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> @out τ_0_0 -// CHECK: partial_apply [callee_guaranteed] [[FN]]([[ARG]]) -// CHECK: return - -// CHECK-LABEL: sil private @$s23sil_combine_curry_thunk15abstractCurried1t1s1uyx_1SQz1UQzmtAA1QRzlFAgIcAGcfu5_ : $@convention(thin) (@in_guaranteed T.S) -> @owned @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for { -// CHECK: [[ARG:%.*]] = alloc_stack $T.S -// CHECK: copy_addr %0 to [initialization] [[ARG]] : $*T.S -// CHECK: [[FN:%.*]] = witness_method $T.S, #Curryable.genericRequirementSelf : (Self) -> (T) -> Self : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable><τ_1_0 where τ_1_0 : P> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> @out τ_0_0 -// CHECK: partial_apply [callee_guaranteed] [[FN]]([[ARG]]) -// CHECK: return - -// CHECK-LABEL: sil private @$s23sil_combine_curry_thunk15abstractCurried1t1s1uyx_1SQz1UQzmtAA1QRzlFSiycAGcfu7_ : $@convention(thin) (@in_guaranteed T.S) -> @owned @callee_guaranteed () -> Int { -// CHECK: [[ARG:%.*]] = alloc_stack $T.S -// CHECK: copy_addr %0 to [initialization] [[ARG]] : $*T.S -// CHECK: [[FN:%.*]] = witness_method $T.S, #Curryable.concreteRequirementInt : (Self) -> () -> Int : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> Int -// CHECK: partial_apply [callee_guaranteed] %4(%2) : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> Int -// CHECK: return - -// CHECK-LABEL: sil private @$s23sil_combine_curry_thunk15abstractCurried1t1s1uyx_1SQz1UQzmtAA1QRzlFSiAIcAGcfu9_ : $@convention(thin) (@in_guaranteed T.S) -> @owned @callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> Int for { -// CHECK: [[ARG:%.*]] = alloc_stack $T.S -// CHECK: copy_addr %0 to [initialization] [[ARG]] : $*T.S -// CHECK: [[FN:%.*]] = witness_method $T.S, #Curryable.genericRequirementInt : (Self) -> (T) -> Int : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable><τ_1_0 where τ_1_0 : P> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> Int -// CHECK: partial_apply [callee_guaranteed] [[FN]]([[ARG]]) -// CHECK: return \ No newline at end of file diff --git a/test/SILOptimizer/specialize_opaque_type_archetypes.swift b/test/SILOptimizer/specialize_opaque_type_archetypes.swift index 4bbede8502c26..c83372ea4bd78 100644 --- a/test/SILOptimizer/specialize_opaque_type_archetypes.swift +++ b/test/SILOptimizer/specialize_opaque_type_archetypes.swift @@ -412,8 +412,8 @@ func testIt(cl: (Int64) throws -> T) { // CHECK-LABEL: sil shared [noinline] @$s1A16testPartialApplyyyxAA2P4RzlFAA2PAV_Tg5 // CHECK: [[PA:%.*]] = alloc_stack $PA // CHECK: store %0 to [[PA]] : $*PA -// CHECK: [[F:%.*]] = function_ref @$s1A2PAVAA2P4A2aDP3fooy2ATQzs5Int64VFTW : $@convention(witness_method: P4) (Int64, @in_guaranteed PA) -> @out Int64 -// CHECK: [[C:%.*]] = partial_apply [callee_guaranteed] [[F]]([[PA]]) : $@convention(witness_method: P4) (Int64, @in_guaranteed PA) -> @out Int64 +// CHECK: [[F:%.*]] = function_ref @$s1A16testPartialApplyyyxAA2P4RzlF2ATQzs5Int64Vcxcfu_AeGcfu0_AA2PAV_TG5 : $@convention(thin) (Int64, @in_guaranteed PA) -> @out Int64 +// CHECK: [[C:%.*]] = partial_apply [callee_guaranteed] [[F]]([[PA]]) : $@convention(thin) (Int64, @in_guaranteed PA) -> @out Int64 // CHECK: convert_function [[C]] : $@callee_guaranteed (Int64) -> @out Int64 to $@callee_guaranteed @substituted <τ_0_0> (Int64) -> (@out τ_0_0, @error Error) for @inline(never) func testPartialApply(_ t: T) {