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
Comments
@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! |
Can you paste the crash log including debug information (-sil-print-debuginfo) otherwise it's difficult to grasp what/where the bug is? Thanks! |
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. |
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' |
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. |
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. |
@swift-ci create |
Modified the verifier to take in account allocas. |
Additional Detail from JIRA
md5: ccbfa5ab6b32015ec6eba6263814ccf6
Issue Description:
Testcase:
cmdline:
Found by: #13491
Verifier crash log:
cc: @adrian-prantl/@vedantk@eeckstein
The text was updated successfully, but these errors were encountered: