Files
swift-mirror/test/SILOptimizer/closure_specialize_loop.swift
Andrew Trick c665311626 Fix infinite recursion in ClosureSpecialize
Fixes getSpecializationLevelRecursive to handle recursive manglings caused by interleaving CapturePropagation and ClosureSpecialize passes.

For some reason, only the first closure parameter was checked for recursion. We need to handle patterns like this:

  kind=FunctionSignatureSpecialization
    kind=SpecializationPassID, index=3
    kind=FunctionSignatureSpecializationParam
    kind=FunctionSignatureSpecializationParam
      kind=FunctionSignatureSpecializationParamKind, index=0
      kind=FunctionSignatureSpecializationParamPayload, text="$s4test10ExpressionO8contains5whereS3bXE_tFSbACXEfU_S2bXEfU_36$s4test12IndirectEnumVACycfcS2bXEfU_Tf3npf_n"

I fixed the logic so we now check for recursion on all closure parameters and bail out on unrecognized mangling formats.

For reference, see summary.sil in
Infinitely recursive closure specialization #61955
https://github.com/apple/swift/issues/61955

Fixes rdar://101589190 (Swift Compiler hangs when building this code for release)
2022-11-07 14:44:04 -08:00

82 lines
3.7 KiB
Swift

// RUN: %{python} %S/../Inputs/timeout.py 10 %target-swift-frontend -O -parse-as-library %s -emit-sil | %FileCheck %s
public func callit() {
testit { false }
}
// Check if the compiler terminates and does not full into an infinite optimization
// loop between the ClosureSpecializer and CapturePropagation.
// CHECK-LABEL: sil @$s23closure_specialize_loop6testit1cySbyc_tF
public func testit(c: @escaping () -> Bool) {
if c() {
testit { !c() }
}
}
// PR: https://github.com/apple/swift/pull/61956
// Optimizing Expression.contains(where:) should not timeout.
//
// Repeated capture propagation leads to:
// func contains$termPred@arg0$[termPred$falsePred@arg1]@arg1(expr) {
// closure = termPred$[termPred$falsePred@arg1]@arg1
// falsePred(expr)
// contains$termPred@arg0$termPred$[termPred$falsePred@arg1]@arg1(expr)
// }
//
// func contains$termPred@arg0$termPred$[termPred$falsePred@arg1]@arg1(expr) {
// closure = [termPred(termPred$[termPred$falsePred@arg1]@arg1)]
// closure(expr)
// contains$termPred@arg0(expr, closure)
// }
// The Demangled type tree looks like:
// kind=FunctionSignatureSpecialization
// kind=SpecializationPassID, index=3
// kind=FunctionSignatureSpecializationParam
// kind=FunctionSignatureSpecializationParam
// kind=FunctionSignatureSpecializationParamKind, index=0
// kind=FunctionSignatureSpecializationParamPayload, text="$s4test10ExpressionO8contains5whereS3bXE_tFSbACXEfU_S2bXEfU_36$s4test12IndirectEnumVACycfcS2bXEfU_Tf3npf_n"
//
// CHECK-LABEL: $s23closure_specialize_loop10ExpressionO8contains5whereS3bXE_tFSbACXEfU_S2bXEfU_012$s23closure_b7_loop10d44O8contains5whereS3bXE_tFSbACXEfU_S2bXEfU_012g13_b7_loop10d44ijk2_tlm2U_no52U_012g30_B34_loop12IndirectEnumVACycfcnO10U_Tf3npf_nY2_nTf3npf_n
// ---> function signature specialization
// <Arg[1] = [Constant Propagated Function : function signature specialization
// <Arg[1] = [Constant Propagated Function : function signature specialization
// <Arg[1] = [Constant Propagated Function : closure #1 (Swift.Bool) -> Swift.Bool
// in closure_specialize_loop.IndirectEnum.init() -> closure_specialize_loop.IndirectEnum]>
// of closure #1 (Swift.Bool) -> Swift.Bool
// in closure #1 (closure_specialize_loop.Expression) -> Swift.Bool
// in closure_specialize_loop.Expression.contains(where: (Swift.Bool) -> Swift.Bool) -> Swift.Bool]>
// of closure #1 (Swift.Bool) -> Swift.Bool
// in closure #1 (closure_specialize_loop.Expression) -> Swift.Bool
// in closure_specialize_loop.Expression.contains(where: (Swift.Bool) -> Swift.Bool) -> Swift.Bool]>
// of closure #1 (Swift.Bool) -> Swift.Bool
// in closure #1 (closure_specialize_loop.Expression) -> Swift.Bool
// in closure_specialize_loop.Expression.contains(where: (Swift.Bool) -> Swift.Bool) -> Swift.Bool
//
public indirect enum Expression {
case term(Bool)
case list(_ expressions: [Expression])
public func contains(where predicate: (Bool) -> Bool) -> Bool {
switch self {
case let .term(term):
return predicate(term)
case let .list(expressions):
return expressions.contains { expression in
expression.contains { term in
predicate(term)
}
}
}
}
}
public struct IndirectEnum {
public init() {
let containsFalse = Expression.list([.list([.term(true), .term(false)]), .term(true)]).contains { term in
term == false
}
print(containsFalse)
}
}