Skip to content

[AutoDiff] Assertion failed: (srcAddr->getType() == destAddr->getType()) #72618

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
asl opened this issue Mar 27, 2024 · 4 comments
Open

[AutoDiff] Assertion failed: (srcAddr->getType() == destAddr->getType()) #72618

asl opened this issue Mar 27, 2024 · 4 comments
Assignees
Labels
assertion failure Bug → crash: An assertion failure AutoDiff bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler itself crash Bug: A crash, i.e., an abnormal termination of software SILOptimizer Area → compiler: SIL optimization passes swift 6.0

Comments

@asl
Copy link
Contributor

asl commented Mar 27, 2024

Description

Factored out second testcase from #72363

Reproduction

import _Differentiation; protocol P {}
struct D: P, Differentiable {}; func a(_ x: P) {}
@differentiable(reverse where T == D) func f<T: P>(_ x: T) -> T {a(x); return x}

Stack dump

1.	Apple Swift version 6.0-dev (LLVM ce41a43bba95b2b, Swift 1a840948a0905df)
2.	Compiling with effective version 5.10
3.	While evaluating request ExecuteSILPipelineRequest(Run pipelines { Mandatory Diagnostic Passes + Enabling Optimization Passes } on SIL for main)
4.	While running pass #242 SILModuleTransform "Differentiation".
5.	While processing // differentiability witness for f<A>(_:)
sil_differentiability_witness hidden [reverse] [parameters 0] [results 0] <T where T == D> @$s4main1fyxxAA1PRzlF : $@convention(thin) <T where T : P> (@in_guaranteed T) -> @out T {
}

 on SIL function "@$s4main1fyxxAA1PRzlF".
 for 'f(_:)' (at main.swift:3:39)
6.	While generating VJP for SIL function "@$s4main1fyxxAA1PRzlF".
 for 'f(_:)' (at main.swift:3:39)
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           0x00000001061bbfc4 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) + 56
1  swift-frontend           0x00000001061ba790 llvm::sys::RunSignalHandlers() + 112
2  swift-frontend           0x00000001061bc60c SignalHandler(int) + 304
3  libsystem_platform.dylib 0x000000018b12aa24 _sigtramp + 56
4  libsystem_pthread.dylib  0x000000018b0fbc28 pthread_kill + 288
5  libsystem_c.dylib        0x000000018b009ae8 abort + 180
6  libsystem_c.dylib        0x000000018b008e44 err + 0
7  swift-frontend           0x000000010633dde0 swift::SILCloner<swift::autodiff::VJPCloner::Implementation>::visitExplicitCopyAddrInst(swift::ExplicitCopyAddrInst*) (.cold.1) + 0
8  swift-frontend           0x000000010157fab0 swift::SILCloner<swift::autodiff::VJPCloner::Implementation>::visitCopyAddrInst(swift::CopyAddrInst*) + 352
9  swift-frontend           0x000000010156d7d8 swift::SILCloner<swift::autodiff::VJPCloner::Implementation>::visitBlocksDepthFirst(swift::SILBasicBlock*) + 380
10 swift-frontend           0x000000010156ccec swift::SILCloner<swift::autodiff::VJPCloner::Implementation>::cloneFunctionBody(swift::SILFunction*, swift::SILBasicBlock*, llvm::ArrayRef<swift::SILValue>, bool) + 236
11 swift-frontend           0x000000010156c4ac swift::autodiff::VJPCloner::Implementation::run() + 920
12 swift-frontend           0x000000010156cd4c swift::autodiff::VJPCloner::run() + 24
13 swift-frontend           0x00000001016c8928 (anonymous namespace)::DifferentiationTransformer::canonicalizeDifferentiabilityWitness(swift::SILDifferentiabilityWitness*, swift::autodiff::DifferentiationInvoker, swift::IsSerialized_t) + 6032
14 swift-frontend           0x00000001016c67a0 (anonymous namespace)::Differentiation::run() + 1060
15 swift-frontend           0x0000000101768dac swift::SILPassManager::runModulePass(unsigned int) + 856
16 swift-frontend           0x000000010176b118 swift::SILPassManager::execute() + 624
17 swift-frontend           0x0000000101765984 swift::SILPassManager::executePassPipelinePlan(swift::SILPassPipelinePlan const&) + 72
18 swift-frontend           0x0000000101765904 swift::ExecuteSILPipelineRequest::evaluate(swift::Evaluator&, swift::SILPipelineExecutionDescriptor) const + 68
19 swift-frontend           0x00000001017a0d48 swift::SimpleRequest<swift::ExecuteSILPipelineRequest, std::__1::tuple<> (swift::SILPipelineExecutionDescriptor), (swift::RequestFlags)1>::evaluateRequest(swift::ExecuteSILPipelineRequest const&, swift::Evaluator&) + 28
20 swift-frontend           0x000000010178161c 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
21 swift-frontend           0x0000000101765b60 swift::executePassPipelinePlan(swift::SILModule*, swift::SILPassPipelinePlan const&, bool, swift::irgen::IRGenModule*) + 64
22 swift-frontend           0x0000000101783a68 swift::runSILDiagnosticPasses(swift::SILModule&) + 192
23 swift-frontend           0x0000000100fcd1b8 swift::CompilerInstance::performSILProcessing(swift::SILModule*) + 68
24 swift-frontend           0x0000000100d9380c 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*) + 796
25 swift-frontend           0x0000000100d93144 swift::performCompileStepsPostSema(swift::CompilerInstance&, int&, swift::FrontendObserver*) + 1160
26 swift-frontend           0x0000000100da40c4 withSemanticAnalysis(swift::CompilerInstance&, swift::FrontendObserver*, llvm::function_ref<bool (swift::CompilerInstance&)>, bool) + 160
27 swift-frontend           0x0000000100d95530 performCompile(swift::CompilerInstance&, int&, swift::FrontendObserver*) + 708
28 swift-frontend           0x0000000100d9449c swift::performFrontend(llvm::ArrayRef<char const*>, char const*, void*, swift::FrontendObserver*) + 2368
29 swift-frontend           0x0000000100bb37b0 swift::mainEntry(int, char const**) + 3096
30 dyld                     0x000000018ada3f28 start + 2236

Expected behavior

The compilation should succeed, or the compiler should produce an error message indicating why the compilation cannot succeed.

Environment

Swift version 6.0-dev (LLVM db7d0a8bc4512db, Swift a62e62d)
Target: arm64-apple-macosx13.0

Additional information

No response

@asl asl added bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. crash Bug: A crash, i.e., an abnormal termination of software triage needed This issue needs more specific labels labels Mar 27, 2024
@asl asl changed the title Assertion failed: (srcAddr->getType() == destAddr->getType()) [AutoDiff] Assertion failed: (srcAddr->getType() == destAddr->getType()) Mar 27, 2024
@asl asl added AutoDiff and removed triage needed This issue needs more specific labels labels Mar 27, 2024
@asl asl self-assigned this Mar 27, 2024
@jkshtj
Copy link
Contributor

jkshtj commented Mar 27, 2024

@asl are you actively working on this? Otherwise I can take a look at it.

@asl
Copy link
Contributor Author

asl commented Mar 28, 2024

@asl are you actively working on this? Otherwise I can take a look at it.

Yes, as I mentioned today, I am working on this. Closure optimizations are much more important :)

@AnthonyLatsis AnthonyLatsis added compiler The Swift compiler itself assertion failure Bug → crash: An assertion failure swift 5.10 SILOptimizer Area → compiler: SIL optimization passes swift 6.0 and removed swift 5.10 labels Apr 16, 2024
@asl
Copy link
Contributor Author

asl commented Jun 18, 2024

So, this case is different and I'm afraid (see below) we are having lots of issues with same-type requirements in derivatives.

What happens is:

  • As all requirements are equalities, VJP is generated with fully substituted non-generic signature:
// reverse-mode derivative of f<A>(_:)
sil hidden [ossa] @$s4main1fyxxAA1PRzlFAA1DVRszlTJrSpSr : $@convention(thin) (@in_guaranteed D) -> (@out D, @owned @callee_guaranteed (@in_guaranteed D.TangentVector) -> @out D.TangentVector) {
  • However, VJP body is cloned from the original unsubstituted f<T:P>:
// f<A>(_:)
sil hidden [ossa] @$s4main1fyxxAA1PRzlF : $@convention(thin) <T where T : P> (@in_guaranteed T) -> @out T {
// %0 "$return_value"                             // user: %10
// %1 "x"                                         // users: %10, %5, %2
bb0(%0 : $*T, %1 : $*T):
  debug_value %1 : $*T, let, name "x", argno 1, expr op_deref // id: %2
  %3 = alloc_stack $any P                         // users: %9, %8, %7, %4
  %4 = init_existential_addr %3 : $*any P, $T     // user: %5
  copy_addr %1 to [init] %4 : $*T                 // id: %5
  // function_ref a(_:)
  %6 = function_ref @$s4main1ayyAA1P_pF : $@convention(thin) (@in_guaranteed any P) -> () // user: %7
  %7 = apply %6(%3) : $@convention(thin) (@in_guaranteed any P) -> ()
  destroy_addr %3 : $*any P                       // id: %8
  dealloc_stack %3 : $*any P                      // id: %9
  copy_addr %1 to [init] %0 : $*T                 // id: %10
  %11 = tuple ()                                  // user: %12
  return %11 : $()                                // id: %12
} // end sil function '$s4main1fyxxAA1PRzlF'

The issue happens here:

  %4 = init_existential_addr %3 : $*any P, $T     // user: %5
  copy_addr %1 to [init] %4 : $*T                 // id: %5

in VJP cloner there is no information that T == D and therefore %4 is cloned as-is. So, copy_addr tries to produce a copy from %1 which has type $*D to $*T causing SIL verifier mismatch.

Here is similar, but a bit easier case adopted from the existing testcase (SILGen/differentiability_witness_generic_signature.swift):

struct AllConcrete<T>: Differentiable {}

extension AllConcrete {
  //   Original generic signature: `<T>`
  // Derivative generic signature: `<T where T == Float>`
  //    Witness generic signature: `<T where T == Float>`
  @_silgen_name("allconcrete_where_gensig_constrained")
  @differentiable(reverse where T == Float)
  func whereClauseGenericSignatureConstrained() -> AllConcrete {
    var a = self
    return a
  }
}

Note that the comment in the testcase is wrong, the derivative generic signature is null these days.

VJP here is:

// allconcrete_where_gensig_constrainedSfRszlTJrSpSr
sil hidden [ossa] @allconcrete_where_gensig_constrainedSfRszlTJrSpSr : $@convention(method) (AllConcrete<Float>) -> (AllConcrete<Float>, @owned @callee_guaranteed (AllConcrete<Float>.TangentVector) -> AllConcrete<Float>.TangentVector) {
// %0                                             // users: %3, %1
bb0(%0 : $AllConcrete<Float>):
  debug_value %0 : $AllConcrete<Float>, let, name "self", argno 1 // id: %1
  %2 = alloc_stack [var_decl] $AllConcrete<T>, var, name "a" // users: %7, %4, %3
  store %0 to [trivial] %2 : $*AllConcrete<T>     // id: %3
  %4 = begin_access [read] [static] %2 : $*AllConcrete<T> // users: %6, %5
  %5 = load [trivial] %4 : $*AllConcrete<T>       // user: %10
  end_access %4 : $*AllConcrete<T>                // id: %6
  dealloc_stack %2 : $*AllConcrete<T>             // id: %7
  // function_ref allconcrete_where_gensig_constrainedSfRszlTJpSpSr
  %8 = function_ref @allconcrete_where_gensig_constrainedSfRszlTJpSpSr : $@convention(thin) (AllConcrete<Float>.TangentVector) -> AllConcrete<Float>.TangentVector // user: %9
  %9 = partial_apply [callee_guaranteed] %8() : $@convention(thin) (AllConcrete<Float>.TangentVector) -> AllConcrete<Float>.TangentVector // user: %10
  %10 = tuple (%5 : $AllConcrete<T>, %9 : $@callee_guaranteed (AllConcrete<Float>.TangentVector) -> AllConcrete<Float>.TangentVector) // user: %11
  return %10 : $(AllConcrete<T>, @callee_guaranteed (AllConcrete<Float>.TangentVector) -> AllConcrete<Float>.TangentVector) // id: %11
} // end sil function 'allconcrete_where_gensig_constrainedSfRszlTJrSpSr'

and SIL verifier complains (and indeed, there is no way to resolve T above):

SIL verification failed: Operand is of an ArchetypeType that does not exist in the Caller's generic param list.: isArchetypeValidInFunction(A, F)
Verifying instruction:
->   %2 = alloc_stack [var_decl] $AllConcrete<T>, var, name "a" // users: %7, %4, %3
     store %0 to [trivial] %2 : $*AllConcrete<T>  // id: %3
     %4 = begin_access [read] [static] %2 : $*AllConcrete<T> // users: %6, %5
     dealloc_stack %2 : $*AllConcrete<T>          // id: %7

So, the question is: why same-type requirements are dropped from VJP's generic signature? Tagging @rxwei for maybe some past knowledge.

@rxwei
Copy link
Contributor

rxwei commented Jun 18, 2024

My memory is rusty on this one, but I do recall autodiff having issues with same-type constraints all along. @dan-zheng knows best.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
assertion failure Bug → crash: An assertion failure AutoDiff bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler itself crash Bug: A crash, i.e., an abnormal termination of software SILOptimizer Area → compiler: SIL optimization passes swift 6.0
Projects
None yet
Development

No branches or pull requests

4 participants