Skip to content
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

[SR-6700] [DebugInfo] SIL alloc_stack hoisting doesn't preserve DI correctly #49249

Closed
dcci mannequin opened this issue Jan 5, 2018 · 8 comments
Closed

[SR-6700] [DebugInfo] SIL alloc_stack hoisting doesn't preserve DI correctly #49249

dcci mannequin opened this issue Jan 5, 2018 · 8 comments
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself crash Bug: A crash, i.e., an abnormal termination of software debug info Area → compiler → IRGen: Debug information emission SILOptimizedDebugInfo

Comments

@dcci
Copy link
Mannequin

dcci mannequin commented Jan 5, 2018

Previous ID SR-6700
Radar rdar://problem/36622140
Original Reporter @dcci
Type Bug
Status Resolved
Resolution Done
Additional Detail from JIRA
Votes 0
Component/s Compiler
Labels Bug, CompilerCrash, DebugInfo, SILOptimizedDebugInfo
Assignee None
Priority Medium

md5: ccbfa5ab6b32015ec6eba6263814ccf6

Issue Description:

Testcase:

protocol MyArrayBufferProtocol : MutableCollection, RandomAccessCollection {
  mutating func myReplace<C>(
    _ subRange: Range<Int>,
    with newValues: C
  ) where C : Collection, C.Iterator.Element == Element
}
extension Array : MyArrayBufferProtocol {
  mutating func myReplace<C>(
    _ subRange: Range<Int>,
    with newValues: C
  ) where C : Collection, C.Iterator.Element == Element {
    replaceSubrange(subRange, with: newValues)
  }
}
public func run_PopFrontArrayGeneric(_ N: Int) {
  for _ in 1...20*N {
  }
}

cmdline:

 /Users/davide/swift/build/Ninja-RelWithDebInfoAssert/swift-macosx-x86_64/bin/swift -frontend -c red.swift -target x86_64-apple-macosx10.9 -sdk ${SDK} -Onone

Found by: #13491

Verifier crash log:

SIL verification failed: Found an hole in debug lexical scopes: DS == LastSeenScope
Verifying instruction:
     %13 = tuple ()                               // user: %15
->   return %13 : $()                             // id: %15
In function:
// Array.myReplace<A>(_:with:)
sil hidden @_T0Sa15PopFrontGenericE9myReplace_4withys5RangeVySiG_qd__t7ElementQyd__Rszs10CollectionRd__lF : $@convention(method) <Element><C where Element == C.Element, C : Collection> (Range<Int>, @in C, @inout Array<Element>) -> () {
// %0                                             // users: %10, %4
// %1                                             // users: %12, %7, %5
// %2                                             // users: %8, %6
bb0(%0 : $Range<Int>, %1 : $*C, %2 : $*Array<Element>):
  %3 = alloc_stack $C                             // users: %14, %10, %7
  debug_value %0 : $Range<Int>, let, name "subRange", argno 1 // id: %4
  debug_value_addr %1 : $*C, let, name "newValues", argno 2 // id: %5
  debug_value_addr %2 : $*Array<Element>, var, name "self", argno 3 // id: %6
  copy_addr %1 to [initialization] %3 : $*C       // id: %7
  %8 = begin_access [modify] [static] %2 : $*Array<Element> // users: %11, %10
  // function_ref Array.replaceSubrange<A>(_:with:)
  %9 = function_ref @_T0Sa15replaceSubrange_4withys5RangeVySiG_qd__t7ElementQyd__Rszs10CollectionRd__lF : $@convention(method) <τ_0_0><τ_1_0 where τ_0_0 == τ_1_0.Element, τ_1_0 : Collection> (Range<Int>, @in τ_1_0, @inout Array<τ_0_0>) -> () // user: %10
  %10 = apply %9<Element, C>(%0, %3, %8) : $@convention(method) <τ_0_0><τ_1_0 where τ_0_0 == τ_1_0.Element, τ_1_0 : Collection> (Range<Int>, @in τ_1_0, @inout Array<τ_0_0>) -> ()
  end_access %8 : $*Array<Element>                // id: %11
  destroy_addr %1 : $*C                           // id: %12
  %13 = tuple ()                                  // user: %15
  dealloc_stack %3 : $*C                          // id: %14
  return %13 : $()                                // id: %15
} // end sil function '_T0Sa15PopFrontGenericE9myReplace_4withys5RangeVySiG_qd__t7ElementQyd__Rszs10CollectionRd__lF'

0  swift                    0x0000000106514aa8 llvm::sys::PrintStackTrace(llvm::raw_ostream&) + 40
1  swift                    0x00000001065139f6 llvm::sys::RunSignalHandlers() + 86
2  swift                    0x000000010651506e SignalHandler(int) + 366
3  libsystem_platform.dylib 0x00007fff684e4f5a _sigtramp + 26
4  libsystem_platform.dylib 000000000000000000 _sigtramp + 2545004736
5  libsystem_c.dylib        0x00007fff6830f312 abort + 127
6  swift                    0x0000000103cb04aa (anonymous namespace)::SILVerifier::_require(bool, llvm::Twine const&, std::__1::function<void ()> const&) + 490
7  swift                    0x0000000103cb22c1 (anonymous namespace)::SILVerifier::visitSILBasicBlock(swift::SILBasicBlock*) + 1681
8  swift                    0x0000000103cae427 swift::SILFunction::verify(bool) const + 8295
9  swift                    0x000000010390e124 swift::SILPassManager::runPassOnFunction(swift::SILFunctionTransform*, swift::SILFunction*) + 5188
10 swift                    0x000000010390ee44 swift::SILPassManager::runFunctionPasses(llvm::ArrayRef<swift::SILFunctionTransform*>) + 1092
11 swift                    0x00000001039102f4 swift::SILPassManager::runOneIteration() + 964
12 swift                    0x00000001031c521b swift::SILPassManager::executePassPipelinePlan(swift::SILPassPipelinePlan const&) + 187
13 swift                    0x00000001031c4b22 runIRGenPreparePasses(swift::SILModule&, swift::irgen::IRGenModule&) + 162
14 swift                    0x00000001031c2e33 performIRGeneration(swift::IRGenOptions&, swift::ModuleDecl*, std::__1::unique_ptr<swift::SILModule, std::__1::default_delete<swift::SILModule> >, llvm::StringRef, llvm::LLVMContext&, swift::SourceFile*, llvm::GlobalVariable**, unsigned int) + 979
15 swift                    0x00000001031c19c8 swift::performIRGeneration(swift::IRGenOptions&, swift::ModuleDecl*, std::__1::unique_ptr<swift::SILModule, std::__1::default_delete<swift::SILModule> >, llvm::StringRef, llvm::LLVMContext&, llvm::GlobalVariable**) + 808
16 swift                    0x0000000103071b24 performCompile(swift::CompilerInstance&, swift::CompilerInvocation&, llvm::ArrayRef<char const*>, int&, swift::FrontendObserver*, swift::UnifiedStatsReporter*) + 14068
17 swift                    0x000000010306d42a swift::performFrontend(llvm::ArrayRef<char const*>, char const*, void*, swift::FrontendObserver*) + 3210
18 swift                    0x000000010302e300 main + 3360
19 libdyld.dylib            0x00007fff68263115 start + 1

cc: @adrian-prantl/@vedantk@eeckstein

@dcci
Copy link
Mannequin Author

dcci mannequin commented Jan 5, 2018

@belkadan Jordan, as I'm going to submit several of these in the next while, can we add another label `OptimizedDebugInfo` or something like that? Thanks!

@adrian-prantl
Copy link
Member

Can you paste the crash log including debug information (-sil-print-debuginfo) otherwise it's difficult to grasp what/where the bug is? Thanks!

@dcci
Copy link
Mannequin Author

dcci mannequin commented Jan 5, 2018

Oops, I thought I did:

In function:
sil_scope 1 { loc "red.swift":8:17 parent @_T0Sa3redE9myReplace_4withys5RangeVySiG_qd__t7ElementQyd__Rszs10CollectionRd__lF : $@convention(method) <τ_0_0><τ_1_0 where τ_0_0 == τ_1_0.Element, τ_1_0 : Collection> (Range<Int>, @in τ_1_0, @inout Array<τ_0_0>) -> () }
sil_scope 2 { loc "red.swift":13:3 parent 1 }

// Array.myReplace<A>(_:with:)
sil hidden @_T0Sa3redE9myReplace_4withys5RangeVySiG_qd__t7ElementQyd__Rszs10CollectionRd__lF : $@convention(method) <Element><C where Element == C.Element, C : Collection> (Range<Int>, @in C, @inout Array<Element>) -> () {
// %0                                             // users: %10, %4
// %1                                             // users: %12, %7, %5
// %2                                             // users: %8, %6
bb0(%0 : $Range<Int>, %1 : $*C, %2 : $*Array<Element>):
  %3 = alloc_stack $C, loc "red.swift":12:37, scope 2 // users: %14, %10, %7
  debug_value %0 : $Range<Int>, let, name "subRange", argno 1, loc "red.swift":9:7, scope 1 // id: %4
  debug_value_addr %1 : $*C, let, name "newValues", argno 2, loc "red.swift":10:10, scope 1 // id: %5
  debug_value_addr %2 : $*Array<Element>, var, name "self", argno 3, loc "red.swift":8:17, scope 1 // id: %6
  copy_addr %1 to [initialization] %3 : $*C, loc "red.swift":12:37, scope 2 // id: %7
  %8 = begin_access [modify] [static] %2 : $*Array<Element>, loc "red.swift":12:5, scope 2 // users: %11, %10
  // function_ref Array.replaceSubrange<A>(_:with:)
  %9 = function_ref @_T0Sa15replaceSubrange_4withys5RangeVySiG_qd__t7ElementQyd__Rszs10CollectionRd__lF : $@convention(method) <τ_0_0><τ_1_0 where τ_0_0 == τ_1_0.Element, τ_1_0 : Collection> (Range<Int>, @in τ_1_0, @inout Array<τ_0_0>) -> (), loc "red.swift":12:5, scope 2 // user: $10
  %10 = apply %9<Element, C>(%0, %3, %8) : $@convention(method) <τ_0_0><τ_1_0 where τ_0_0 == τ_1_0.Element, τ_1_0 : Collection> (Range<Int>, @in τ_1_0, @inout Array<τ_0_0>) -> (), loc "red.swift":12:5, scope 2
  end_access %8 : $*Array<Element>, loc "red.swift":12:5, scope 2 // id: %11
  destroy_addr %1 : $*C, loc "red.swift":13:3, scope 2 // id: %12
  %13 = tuple (), loc "red.swift":13:3, scope 2   // user: %15
  dealloc_stack %3 : $*C, loc "red.swift":12:37, scope 2 // id: %14
  return %13 : $(), loc "red.swift":13:3, scope 2 // id: %15
} // end sil function '_T0Sa3redE9myReplace_4withys5RangeVySiG_qd__t7ElementQyd__Rszs10CollectionRd__lF'

As you can see the `alloc_stack` instruction defined by `%3` gets the wrong scope.

The reason why alloc_stack hoisting breaks DI is that it calls `moveFront()`

void SILInstruction::moveFront(SILBasicBlock *Block) {
  getParent()->remove(this);
  Block->push_front(this);
}

which completely ignores the scope, just moves stuff around.

@dcci
Copy link
Mannequin Author

dcci mannequin commented Jan 5, 2018

Also, for completeness, here's the intermediate before and after the transformations (which shows that alloc stack has the "right" scope before the transform)

*** SIL module before IRGen Preparation transformation (0) ***
sil_scope 1 { loc "red.swift":8:17 parent @_T0Sa3redE9myReplace_4withys5RangeVySiG_qd__t7ElementQyd__Rszs10CollectionRd__lF : $@convention(method) <τ_0_0><τ_1_0 where τ_0_0 == τ_1_0.Element, τ_1_0 : Collection> (Range<Int>, @in τ_1_0, @inout Array<τ_0_0>) -> () }
sil_scope 2 { loc "red.swift":13:3 parent 1 }

// Array.myReplace<A>(_:with:)
sil hidden @_T0Sa3redE9myReplace_4withys5RangeVySiG_qd__t7ElementQyd__Rszs10CollectionRd__lF : $@convention(method) <Element><C where Element == C.Element, C : Collection> (Range<Int>, @in C, @inout Array<Element>) -> () {
// %0                                             // users: %10, %3
// %1                                             // users: %13, %7, %4
// %2                                             // users: %8, %5
bb0(%0 : $Range<Int>, %1 : $*C, %2 : $*Array<Element>):
  debug_value %0 : $Range<Int>, let, name "subRange", argno 1, loc "red.swift":9:7, scope 1 // id: %3
  debug_value_addr %1 : $*C, let, name "newValues", argno 2, loc "red.swift":10:10, scope 1 // id: %4
  debug_value_addr %2 : $*Array<Element>, var, name "self", argno 3, loc "red.swift":8:17, scope 1 // id: %5                                                                                                                                                                                 %6 = alloc_stack $C, loc "red.swift":12:37, scope 2 // users: %12, %10, %7
  copy_addr %1 to [initialization] %6 : $*C, loc "red.swift":12:37, scope 2 // id: %7
  %8 = begin_access [modify] [static] %2 : $*Array<Element>, loc "red.swift":12:5, scope 2 // users: %11, %10
  // function_ref Array.replaceSubrange<A>(_:with:)
  %9 = function_ref @_T0Sa15replaceSubrange_4withys5RangeVySiG_qd__t7ElementQyd__Rszs10CollectionRd__lF : $@convention(method) <τ_0_0><τ_1_0 where τ_0_0 == τ_1_0.Element, τ_1_0 : Collection> (Range<Int>, @in τ_1_0, @inout Array<τ_0_0>) -> (), loc "red.swift":12:5, scope 2 // user: %10
  %10 = apply %9<Element, C>(%0, %6, %8) : $@convention(method) <τ_0_0><τ_1_0 where τ_0_0 == τ_1_0.Element, τ_1_0 : Collection> (Range<Int>, @in τ_1_0, @inout Array<τ_0_0>) -> (), loc "red.swift":12:5, scope 2
  end_access %8 : $*Array<Element>, loc "red.swift":12:5, scope 2 // id: %11
  dealloc_stack %6 : $*C, loc "red.swift":12:46, scope 2 // id: %12
  destroy_addr %1 : $*C, loc "red.swift":13:3, scope 2 // id: %13
  %14 = tuple (), loc "red.swift":13:3, scope 2   // user: %15
  return %14 : $(), loc "red.swift":13:3, scope 2 // id: %15
} // end sil function '_T0Sa3redE9myReplace_4withys5RangeVySiG_qd__t7ElementQyd__Rszs10CollectionRd__lF'

*** SIL function after IRGen Preparation SIL alloc_stack Hoisting (alloc-stack-hoisting) (#1) ***
sil_scope 1 { loc "red.swift":8:17 parent @_T0Sa3redE9myReplace_4withys5RangeVySiG_qd__t7ElementQyd__Rszs10CollectionRd__lF : $@convention(method) <τ_0_0><τ_1_0 where τ_0_0 == τ_1_0.Element, τ_1_0 : Collection> (Range<Int>, @in τ_1_0, @inout Array<τ_0_0>) -> () }
sil_scope 2 { loc "red.swift":13:3 parent 1 }

// Array.myReplace<A>(_:with:)
sil hidden @_T0Sa3redE9myReplace_4withys5RangeVySiG_qd__t7ElementQyd__Rszs10CollectionRd__lF : $@convention(method) <Element><C where Element == C.Element, C : Collection> (Range<Int>, @in C, @inout Array<Element>) -> () {
// %0                                             // users: %10, %4
// %1                                             // users: %12, %7, %5
// %2                                             // users: %8, %6
bb0(%0 : $Range<Int>, %1 : $*C, %2 : $*Array<Element>):                                                                                                                                                                                                                                      %3 = alloc_stack $C, loc "red.swift":12:37, scope 2 // users: %14, %10, %7
  debug_value %0 : $Range<Int>, let, name "subRange", argno 1, loc "red.swift":9:7, scope 1 // id: %4
  debug_value_addr %1 : $*C, let, name "newValues", argno 2, loc "red.swift":10:10, scope 1 // id: %5
  debug_value_addr %2 : $*Array<Element>, var, name "self", argno 3, loc "red.swift":8:17, scope 1 // id: %6
  copy_addr %1 to [initialization] %3 : $*C, loc "red.swift":12:37, scope 2 // id: %7
  %8 = begin_access [modify] [static] %2 : $*Array<Element>, loc "red.swift":12:5, scope 2 // users: %11, %10
  // function_ref Array.replaceSubrange<A>(_:with:)
  %9 = function_ref @_T0Sa15replaceSubrange_4withys5RangeVySiG_qd__t7ElementQyd__Rszs10CollectionRd__lF : $@convention(method) <τ_0_0><τ_1_0 where τ_0_0 == τ_1_0.Element, τ_1_0 : Collection> (Range<Int>, @in τ_1_0, @inout Array<τ_0_0>) -> (), loc "red.swift":12:5, scope 2 // user: $10
  %10 = apply %9<Element, C>(%0, %3, %8) : $@convention(method) <τ_0_0><τ_1_0 where τ_0_0 == τ_1_0.Element, τ_1_0 : Collection> (Range<Int>, @in τ_1_0, @inout Array<τ_0_0>) -> (), loc "red.swift":12:5, scope 2
  end_access %8 : $*Array<Element>, loc "red.swift":12:5, scope 2 // id: %11
  destroy_addr %1 : $*C, loc "red.swift":13:3, scope 2 // id: %12
  %13 = tuple (), loc "red.swift":13:3, scope 2   // user: %15
  dealloc_stack %3 : $*C, loc "red.swift":12:37, scope 2 // id: %14
  return %13 : $(), loc "red.swift":13:3, scope 2 // id: %15
} // end sil function '_T0Sa3redE9myReplace_4withys5RangeVySiG_qd__t7ElementQyd__Rszs10CollectionRd__lF'

@adrian-prantl
Copy link
Member

I think this may be a case where we need to relax the verification.

If the alloc_stack gets lowered into an LLVM IR alloca, then the scope doesn't matter much because alloca's are always generated in the function prologue and without a location/scope. We do, however, use the scope and location to generate the debug information for any variable associated with the alloc_stack instruction. This means we should absolutely not modify that scope of an alloc_stack, or else the variable will appear in the wrong scope in the debug info.

@belkadan
Copy link
Contributor

belkadan commented Jan 5, 2018

Re: labels: I don't have any strong opinions about new labels. I've invented most of the current set, largely based on (a) high-level classification of bugs (crash / assertion failure / verifier error vs. miscompile vs. diagnostic issue vs. …) or (b) something you might want to search on later. The three it has right now—CompilerCrash, DebugInfo, and your new SILOptimizedDebugInfo—makes sense to me.

@dcci
Copy link
Mannequin Author

dcci mannequin commented Jan 18, 2018

@swift-ci create

@dcci
Copy link
Mannequin Author

dcci mannequin commented Jan 18, 2018

Modified the verifier to take in account allocas.

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
@AnthonyLatsis AnthonyLatsis added the crash Bug: A crash, i.e., an abnormal termination of software label Dec 12, 2022
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself crash Bug: A crash, i.e., an abnormal termination of software debug info Area → compiler → IRGen: Debug information emission SILOptimizedDebugInfo
Projects
None yet
Development

No branches or pull requests

3 participants