Skip to content

[AutoDiff][SILGen] Did not create differentiability witness for function #59135

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
philipturner opened this issue May 27, 2022 · 9 comments · May be fixed by #80983
Open

[AutoDiff][SILGen] Did not create differentiability witness for function #59135

philipturner opened this issue May 27, 2022 · 9 comments · May be fixed by #80983
Labels
AutoDiff bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. crash Bug: A crash, i.e., an abnormal termination of software SIL swift 5.9

Comments

@philipturner
Copy link
Contributor

philipturner commented May 27, 2022

Describe the bug
When running the following script, the compiler crashes. Use swiftc file.swift -emit-module to reproduce this behavior.

Reproducer

import _Differentiation

public struct Tensor: Differentiable & AdditiveArithmetic {
  @inlinable
  func subscriptIndexPath() -> Tensor {
    fatalError()
  }

  @inlinable
  @differentiable(reverse, wrt: self)
  func subscriptRanges() -> Tensor {
    subscriptIndexPath()
  }
  
  @usableFromInline
  @derivative(of: subscriptIndexPath)
  func _vjpSubscriptIndexPath() -> (
    value: Tensor, pullback: (Tensor) -> Tensor
  ) {
    fatalError()
  }
}

Expected behavior

(base) philipturner@M1-Max-MacBook-Pro Desktop % swiftc file.swift -emit-module
error: emit-module command failed due to signal 6 (use -v to see invocation)
Assertion failed: (original->isExternalDeclaration() && "SILGen should create differentiability witnesses for all function " "definitions with explicit differentiable attributes"), function getOrCreateMinimalASTDifferentiabilityWitness, file Common.cpp, line 521.
Please submit a bug report (https://swift.org/contributing/#reporting-bugs) and include the project and the crash backtrace.
Stack dump:
0.	Program arguments: /Library/Developer/Toolchains/swift-5.7-DEVELOPMENT-SNAPSHOT-2022-05-18-a.xctoolchain/usr/bin/swift-frontend -frontend -emit-module -experimental-skip-non-inlinable-function-bodies-without-types file.swift -target arm64-apple-macosx12.0 -Xllvm -aarch64-use-tbi -warn-on-potentially-unavailable-enum-case -enable-objc-interop -sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.3.sdk -color-diagnostics -new-driver-path /Library/Developer/Toolchains/swift-5.7-DEVELOPMENT-SNAPSHOT-2022-05-18-a.xctoolchain/usr/bin/swift-driver -empty-abi-descriptor -resource-dir /Library/Developer/Toolchains/swift-5.7-DEVELOPMENT-SNAPSHOT-2022-05-18-a.xctoolchain/usr/lib/swift -module-name file -target-sdk-version 12.3 -emit-module-doc-path file.swiftdoc -emit-module-source-info-path file.swiftsourceinfo -o file.swiftmodule -emit-abi-descriptor-path file.abi.json
1.	Apple Swift version 5.7-dev (LLVM 9fde71b269b42b8, Swift ddc46e1f5bd885d)
2.	Compiling with the current language version
3.	While evaluating request ExecuteSILPipelineRequest(Run pipelines { Mandatory Diagnostic Passes + Enabling Optimization Passes } on SIL for file)
4.	While running pass #110 SILModuleTransform "Differentiation".
5.	While canonicalizing `differentiable_function` SIL node   %3 = differentiable_function [parameters 0] [results 0] %2 : $@convention(method) (Tensor) -> Tensor // user: %4
6.	While ...in SIL function "@$s4file6TensorV15subscriptRangesACyFTJrSpSr".
 for 'subscriptRanges()' (at file.swift:11:3)
Stack dump without symbol names (ensure you have llvm-symbolizer in your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point to it):
0  swift-frontend           0x000000010920e01c llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) + 56
1  swift-frontend           0x000000010920d27c llvm::sys::RunSignalHandlers() + 128
2  swift-frontend           0x000000010920e680 SignalHandler(int) + 304
3  libsystem_platform.dylib 0x000000019923f4a4 _sigtramp + 56
4  libsystem_pthread.dylib  0x0000000199227ee0 pthread_kill + 288
5  libsystem_c.dylib        0x0000000199162340 abort + 168
6  libsystem_c.dylib        0x0000000199161754 err + 0
7  swift-frontend           0x00000001093bc808 swift::autodiff::getOrCreateMinimalASTDifferentiabilityWitness(swift::SILModule&, swift::SILFunction*, swift::DifferentiabilityKind, swift::IndexSubset*, swift::IndexSubset*) (.cold.2) + 0
8  swift-frontend           0x000000010538c77c swift::autodiff::getOrCreateMinimalASTDifferentiabilityWitness(swift::SILModule&, swift::SILFunction*, swift::DifferentiabilityKind, swift::IndexSubset*, swift::IndexSubset*) + 724
9  swift-frontend           0x00000001054cff40 (anonymous namespace)::DifferentiationTransformer::promoteToDifferentiableFunction(swift::DifferentiableFunctionInst*, swift::SILBuilder&, swift::SILLocation, swift::autodiff::DifferentiationInvoker) + 1320
10 swift-frontend           0x00000001054cdefc (anonymous namespace)::DifferentiationTransformer::processDifferentiableFunctionInst(swift::DifferentiableFunctionInst*) + 484
11 swift-frontend           0x00000001054cbf88 (anonymous namespace)::Differentiation::run() + 1292
12 swift-frontend           0x000000010553f2fc swift::SILPassManager::runModulePass(unsigned int) + 956
13 swift-frontend           0x000000010554482c swift::SILPassManager::execute() + 624
14 swift-frontend           0x000000010553c3dc swift::SILPassManager::executePassPipelinePlan(swift::SILPassPipelinePlan const&) + 68
15 swift-frontend           0x000000010553c364 swift::ExecuteSILPipelineRequest::evaluate(swift::Evaluator&, swift::SILPipelineExecutionDescriptor) const + 68
16 swift-frontend           0x000000010555c800 swift::SimpleRequest<swift::ExecuteSILPipelineRequest, std::__1::tuple<> (swift::SILPipelineExecutionDescriptor), (swift::RequestFlags)1>::evaluateRequest(swift::ExecuteSILPipelineRequest const&, swift::Evaluator&) + 28
17 swift-frontend           0x00000001055473e8 llvm::Expected<swift::ExecuteSILPipelineRequest::OutputType> swift::Evaluator::getResultUncached<swift::ExecuteSILPipelineRequest>(swift::ExecuteSILPipelineRequest const&) + 252
18 swift-frontend           0x000000010553c5d8 swift::executePassPipelinePlan(swift::SILModule*, swift::SILPassPipelinePlan const&, bool, swift::irgen::IRGenModule*) + 84
19 swift-frontend           0x000000010554aeec swift::runSILDiagnosticPasses(swift::SILModule&) + 92
20 swift-frontend           0x0000000104d8b0d0 swift::CompilerInstance::performSILProcessing(swift::SILModule*) + 72
21 swift-frontend           0x0000000104d2fae8 performCompileStepsPostSILGen(swift::CompilerInstance&, std::__1::unique_ptr<swift::SILModule, std::__1::default_delete<swift::SILModule> >, llvm::PointerUnion<swift::ModuleDecl*, swift::SourceFile*>, swift::PrimarySpecificPaths const&, int&, swift::FrontendObserver*) + 716
22 swift-frontend           0x0000000104d2f4ac swift::performCompileStepsPostSema(swift::CompilerInstance&, int&, swift::FrontendObserver*) + 1028
23 swift-frontend           0x0000000104d3c808 withSemanticAnalysis(swift::CompilerInstance&, swift::FrontendObserver*, llvm::function_ref<bool (swift::CompilerInstance&)>, bool) + 160
24 swift-frontend           0x0000000104d31108 swift::performFrontend(llvm::ArrayRef<char const*>, char const*, void*, swift::FrontendObserver*) + 3388
25 swift-frontend           0x0000000104c45bc0 swift::mainEntry(int, char const**) + 3764
26 dyld                     0x0000000111b6908c start + 520

Environment (please complete the following information):

  • OS: macOS 12.4
  • Toolchain: Swift 5.7 Development Snapshot: May 18, 2022 (compiled from the release/5.7 branch)
@philipturner philipturner added the bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. label May 27, 2022
@philipturner
Copy link
Contributor Author

philipturner commented Jul 5, 2022

This originated between the 2021-09-09 and 2021-09-14 development snapshots (September 2021).

@philipturner
Copy link
Contributor Author

philipturner commented Jul 6, 2022

The crash has some peculiar characteristics for when it appears and how it manifests:

  • (Case 1) = subscriptIndexPath is @inlinable, derivative is @inlinable
  • (Case 2) = subscriptIndexPath is @inlinable, derivative is @usableFromInline
  • (Case 3) = subscriptIndexPath is @usableFromInline, derivative is @inlinable:
  • (Case 4) = subscriptIndexPath is @usableFromInline, derivative is @usableFromInline

Release toolchains

  • (Case 1) no crash or error
  • (Case 2) no crash or error
  • (Case 3) no crash or error
  • (Case 4) no crash or error

Development toolchains

  • (Case 1) no crash or error
  • (Case 2) compiler crash <---
  • (Case 3) no crash or error
  • (Case 4) no crash or error

When you add the @differentiable attribute to subscriptIndexPath, the same behavior happens on both types of toolchains. There is sometimes an error diagnostic saying _Raw.stridedSlice is not differentiable.

  • (Case 1) no crash or error
  • (Case 2) error diagnostic <---
  • (Case 3) no crash or error
  • (Case 4) no crash or error

For now my solution in S4TF is: make both subscriptIndexPath and its derivative @usableFromInline. Then, expose the @differentiable attribute that is currently commented out. This falls under Case 1, which compiles under all circumstances.

philipturner added a commit to philipturner/s4tf that referenced this issue Jul 6, 2022
philipturner added a commit to s4tf/s4tf that referenced this issue Jul 6, 2022
* Initial support for release toolchains

* Fix typo

* Remove fatal error

* Comment out x10_training_loop for Colab

* Make `Mergeable.stack` differentiable, working around swiftlang/swift#59876

* Remove #available(macOS 9999, *) restriction

* Enable RNN tests

* Re-enable tensorflow#1162

* Allow Array replaceSubrange

* Fit within 100 spaces

* Type fix "partecipating" -> "participating"

* Remove redundant same-type constraint

* Remove deprecated Dataset API and reposition Zip2TensorGroup

* Refactor tests

* Refactor X10 tests

* Fix failing tests on macOS + arm64

* Remove workarounds for swiftlang/swift#55703 (SR-13263)

* Enable ops_test.swift

* Optimize ops_test.swift

* Optimize more tests

* Rename gradient(at:in) to gradient(at:of:)

* Rename argument label in withoutDerivative

* Enable tests blocked by reflection crash

* Workaround for swiftlang/swift#59135 on dev toolchains

* Fix tests for Colab

* Attempt to speed up tests on Colab

* Revert changes to tests

* Fix tests on Colab NVIDIA GPU

* Revert specializations for NVIDIA GPUs
@philipturner philipturner closed this as not planned Won't fix, can't repro, duplicate, stale Apr 25, 2023
@asl
Copy link
Contributor

asl commented Apr 25, 2023

@philipturner Why are you closing it?

@asl asl added AutoDiff triage needed This issue needs more specific labels labels Apr 25, 2023
@philipturner philipturner reopened this Apr 25, 2023
@BradLarson
Copy link
Contributor

This does still reproduce with the 2023-04-27 nightly snapshot, in the same form.

@AnthonyLatsis AnthonyLatsis added crash Bug: A crash, i.e., an abnormal termination of software SIL swift 5.9 and removed triage needed This issue needs more specific labels labels May 3, 2023
@fibrechannelscsi
Copy link
Contributor

This is showing up in some of the work we've been doing recently. I have the following single-file reproducer:

import Foundation
import _Differentiation
struct B: Differentiable{}
struct X { var j = [Float]()}
struct W: Differentiable {
    @noDerivative var z: X
    var h: B
}
func o<T, R>(_ x: T, _ f: @differentiable(reverse) (T) -> R) -> R {f(x)}
func m<T, R>(_ f: @escaping @differentiable(reverse) (T) -> R) -> @differentiable(reverse) (T) -> R {{ x in o(x, f) }}
@differentiable(reverse)
 func s(h: B) -> B {
    var (_, e) = (0,0)
    @differentiable(reverse)
    func y(_ i: W) -> W {
        for m in 0 ... e {let d = i.z.j[m]}
        return i
    }
    let w = m(y)
    return B()
}

Here's the stack trace when building with the 6.1 2025-03-25a toolchain:

1.	Apple Swift version 6.1-dev (LLVM 83bb915697f5992, Swift 1e211b4d3227ecc)
2.	Compiling with effective version 5.10
3.	While evaluating request ExecuteSILPipelineRequest(Run pipelines { Mandatory Diagnostic Passes + Enabling Optimization Passes } on SIL for rrr)
4.	While running pass #856 SILModuleTransform "Differentiation".
5.	While canonicalizing `differentiable_function` SIL node   %15 = differentiable_function [parameters 0] [results 0] %14 : $@callee_guaranteed (@guaranteed W) -> @owned W // users: %34, %16
6.	While ...in SIL function "@$s3rrr1s1hAA1BVAE_tFTJrSpSr".
 for 's(h:)' (at /Users/user/a/main.swift:12:2)
Stack dump without symbol names (ensure you have llvm-symbolizer in your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point to it):
0  swift-frontend           0x0000000107867844 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) + 56
1  swift-frontend           0x0000000107865f70 llvm::sys::RunSignalHandlers() + 112
2  swift-frontend           0x0000000107867e88 SignalHandler(int) + 292
3  libsystem_platform.dylib 0x000000019f436de4 _sigtramp + 56
4  libsystem_pthread.dylib  0x000000019f3fff70 pthread_kill + 288
5  libsystem_c.dylib        0x000000019f30c908 abort + 128
6  libsystem_c.dylib        0x000000019f30bc1c err + 0
7  swift-frontend           0x0000000107926020 swift::autodiff::DifferentiationInvoker::print(llvm::raw_ostream&) const (.cold.1) + 0
8  swift-frontend           0x0000000102caa410 swift::autodiff::getOrCreateMinimalASTDifferentiabilityWitness(swift::SILModule&, swift::SILFunction*, swift::DifferentiabilityKind, swift::IndexSubset*, swift::IndexSubset*) + 740
9  swift-frontend           0x0000000102e3bb10 (anonymous namespace)::DifferentiationTransformer::processDifferentiableFunctionInst(swift::DifferentiableFunctionInst*) + 2056
10 swift-frontend           0x0000000102e392b8 (anonymous namespace)::Differentiation::run() + 1312
11 swift-frontend           0x0000000102edbdf0 swift::SILPassManager::runModulePass(unsigned int) + 856
12 swift-frontend           0x0000000102ede15c swift::SILPassManager::execute() + 624
13 swift-frontend           0x0000000102ed8c04 swift::SILPassManager::executePassPipelinePlan(swift::SILPassPipelinePlan const&) + 72
14 swift-frontend           0x0000000102ed8b84 swift::ExecuteSILPipelineRequest::evaluate(swift::Evaluator&, swift::SILPipelineExecutionDescriptor) const + 68
15 swift-frontend           0x0000000102f249c4 swift::SimpleRequest<swift::ExecuteSILPipelineRequest, std::__1::tuple<> (swift::SILPipelineExecutionDescriptor), (swift::RequestFlags)1>::evaluateRequest(swift::ExecuteSILPipelineRequest const&, swift::Evaluator&) + 28
16 swift-frontend           0x0000000102ef4d88 swift::ExecuteSILPipelineRequest::OutputType swift::Evaluator::getResultUncached<swift::ExecuteSILPipelineRequest, swift::ExecuteSILPipelineRequest::OutputType swift::evaluateOrFatal<swift::ExecuteSILPipelineRequest>(swift::Evaluator&, swift::ExecuteSILPipelineRequest)::'lambda'()>(swift::ExecuteSILPipelineRequest const&, swift::ExecuteSILPipelineRequest::OutputType swift::evaluateOrFatal<swift::ExecuteSILPipelineRequest>(swift::Evaluator&, swift::ExecuteSILPipelineRequest)::'lambda'()) + 204
17 swift-frontend           0x0000000102ed8df4 swift::executePassPipelinePlan(swift::SILModule*, swift::SILPassPipelinePlan const&, bool, swift::irgen::IRGenModule*) + 64
18 swift-frontend           0x0000000102f07b2c swift::runSILDiagnosticPasses(swift::SILModule&) + 192
19 swift-frontend           0x00000001027ac38c swift::CompilerInstance::performSILProcessing(swift::SILModule*) + 80
20 swift-frontend           0x0000000102578fe0 performCompileStepsPostSILGen(swift::CompilerInstance&, std::__1::unique_ptr<swift::SILModule, std::__1::default_delete<swift::SILModule>>, llvm::PointerUnion<swift::ModuleDecl*, swift::SourceFile*>, swift::PrimarySpecificPaths const&, int&, swift::FrontendObserver*) + 820
21 swift-frontend           0x0000000102578670 swift::performCompileStepsPostSema(swift::CompilerInstance&, int&, swift::FrontendObserver*) + 468
22 swift-frontend           0x0000000102584784 withSemanticAnalysis(swift::CompilerInstance&, swift::FrontendObserver*, llvm::function_ref<bool (swift::CompilerInstance&)>, bool) + 164
23 swift-frontend           0x000000010257a380 performCompile(swift::CompilerInstance&, int&, swift::FrontendObserver*) + 716
24 swift-frontend           0x0000000102579b9c swift::performFrontend(llvm::ArrayRef<char const*>, char const*, void*, swift::FrontendObserver*) + 2228
25 swift-frontend           0x000000010235d524 swift::mainEntry(int, char const**) + 3064
26 dyld                     0x000000019f080274 start + 2840

The stack trace is similar, but not quite. I'm not sure if it's a result of the codebase changing after a couple of years.

@asl
Copy link
Contributor

asl commented Apr 10, 2025

Here is the assertion:

Assertion failed: (original->isExternalDeclaration() && "SILGen should create differentiability witnesses for all function " "definitions with explicit differentiable attributes"), function getOrCreateMinimalASTDifferentiabilityWitness, file Common.cpp, line 538.

Looks like we failed to create witness for:

  // function_ref specialized y #1 (_:) in s(h:)
  %12 = function_ref @$s4main1s1hAA1BVAE_tF1yL_yAA1WVAHFTf2ni_n : $@convention(thin) (@guaranteed W, Int) -> @owned W // user: %14
  %13 = load [trivial] %2                         // user: %14
  %14 = partial_apply [callee_guaranteed] %12(%13) : $@convention(thin) (@guaranteed W, Int) -> @owned W // user: %15
  %15 = differentiable_function [parameters 0] [results 0] %14 // users: %34, %16

So, it is likely related to nested functions. And unlikely to the original issue testcase as above...

@asl
Copy link
Contributor

asl commented Apr 21, 2025

So, here the problem is the mandatory CapturePromotion pass that specialized closure taking arguments by reference into closures taking arguments by value. In this particular case it does not create differentiability witness for the newly cloned function.

@asl
Copy link
Contributor

asl commented Apr 22, 2025

The original issue is different. Without -emit-module two differential witnesses are emitted:

// differentiability witness for Tensor.subscriptRanges()
sil_differentiability_witness [serialized] [reverse] [parameters 0] [results 0] @$s4main6TensorV15subscriptRangesACyF : $@convention(method) (Tensor) -> Tensor {
}

// differentiability witness for Tensor.subscriptIndexPath()
sil_differentiability_witness [serialized] [reverse] [parameters 0] [results 0] @$s4main6TensorV18subscriptIndexPathACyF : $@convention(method) (Tensor) -> Tensor {
  vjp: @$s4main6TensorV18subscriptIndexPathACyFTJrSpSr : $@convention(method) (Tensor) -> (Tensor, @owned @callee_guaranteed (Tensor) -> Tensor)
}

And with -emit-module we're having only one:

// differentiability witness for Tensor.subscriptRanges()
sil_differentiability_witness [serialized] [reverse] [parameters 0] [results 0] @$s4main6TensorV15subscriptRangesACyF : $@convention(method) (Tensor) -> Tensor {
}

hence the assertion.

@asl
Copy link
Contributor

asl commented Apr 22, 2025

So, the original function Tensor.subscriptIndexPath() is not marked as @differentiable as a result, no explicit differentiable witness is generated for it. However, the witness is generated as a side effect of providing a derivative via @derivative(of: subscriptIndexPath) on _vjpSubscriptIndexPath. Since _vjpSubscriptIndexPath is not emitted when -emit-module is used we do not create a witness for Tensor.subscriptIndexPath() as a side effect.

I guess this raises interesting questions, similar to @_alwaysEmitIntoClient from #78908 / #54445 it seems that we need to check for registered derivative configurations and emit witnesses judging on this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
AutoDiff bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. crash Bug: A crash, i.e., an abnormal termination of software SIL swift 5.9
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants