i believe i may have found a cousin of this issue: in the swift 6.2 compiler, code of the following form can take an extremely long time to compile when optimizations are enabled:
final class A {}
final class B {
let prop1: A
let prop2: A
...
let propN: A
init() {
self.prop1 = switch () { default: A() }
self.prop2 = switch () { default: A() }
...
self.propN = switch () { default: A() }
}
}
when compiling with an invocation like:
swiftc -swift-version 5 -O -emit-sil <file>
this code exhibits the following scaling in the 6.0 and 6.2 compilers:
property count | 256 | 512 | 1024 | 2048 |
---|---|---|---|---|
6.0 compile time (s) | <1 | <1 | 1 | 4.6 |
6.2 compile time (s) | 1.4 | 18 | 226 | 2629 |
sampling the 6.2 compiler process while building yields something that looks like this (truncated):
2346 (anonymous namespace)::CopyPropagation::run() (in swift-frontend) + 2420 [0x105397338]
+ 2337 swift::CanonicalizeOSSALifetime::canonicalizeValueLifetime(swift::SILValue, llvm::ArrayRef<swift::SILInstruction*>) (in swift-frontend) + 560 [0x10545fbec]
+ ! 2323 swift::CanonicalizeOSSALifetime::computeLiveness() (in swift-frontend) + 388 [0x10545d784]
+ ! : 2323 swift::CanonicalizeOSSALifetime::extendLivenessToDeadEnds() (in swift-frontend) + 2332 [0x105459350]
+ ! : 2323 swift::OSSALifetimeCompletion::visitAvailabilityBoundary(swift::SILValue, swift::SSAPrunedLiveness const&, llvm::function_ref<void (swift::SILInstruction*, swift::OSSALifetimeCompletion::LifetimeEnd)>) (in swift-frontend) + 4108 [0x104dd9aa4]
+ ! : 2321 visitUsersOutsideLinearLivenessBoundary(swift::SILValue, swift::SSAPrunedLiveness const&, llvm::function_ref<void (swift::SILInstruction*)>) (in swift-frontend) + 520 [0x104dda3c0]
+ ! : | 2321 swift::PrunedLiveRange<swift::SSAPrunedLiveness>::isWithinLivenessBoundary(swift::SILInstruction*) const (in swift-frontend) + 272,260,... [0x104dfac40,0x104dfac34,...]
so far, the only workaround i've found is to compile the code with the setting -Xfrontend -enable-copy-propagation=false
. this returns the compilation time to a reasonable duration (under 1 second for the 1024 property case).
i'm curious to better understand the possible cause of this behavior, and what can be done about it. my current intuition is that this loop is for some reason running a lot, and it may have something to do with enabling OSSA modules by default.
i'd also like to know:
- are there downsides to explicitly disabling the copy propagation pass
- are there ways of structuring source code or other flags that can be used to avoid this performance issue
- what explains why the 6.2 compiler behaves differently than the 6.0 compiler on these examples
thanks in advance for your insights!