swiftlang / swift

The Swift Programming Language
https://swift.org
Apache License 2.0
67.58k stars 10.36k forks source link

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

Open asl opened 7 months ago

asl commented 7 months ago

Description

Factored out second testcase from https://github.com/apple/swift/issues/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 a62e62d046ba949) Target: arm64-apple-macosx13.0

Additional information

No response

jkshtj commented 7 months ago

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

asl commented 7 months ago

@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 :)

asl commented 4 months ago

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:

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 commented 4 months ago

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