-
Notifications
You must be signed in to change notification settings - Fork 10.4k
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-13263] Invalid Debug Information Generation #55703
Comments
Comment by Mustafa YALCIN (JIRA) 3 |
Building this with the toolchain from master (swift: Doing this in multiple phases ( conflicting debug info for argument
call void @llvm.dbg.value(metadata %T1M1SV1CCySf_G* %0, metadata !289, metadata !DIExpression(DW_OP_LLVM_fragment
, 0, 64)), !dbg !288
!286 = !DILocalVariable(name: "self", arg: 1, scope: !283, file: !1, type: !287, flags: DIFlagArtificial)
!289 = !DILocalVariable(name: "self", arg: 1, scope: !283, file: !1, type: !290, flags: DIFlagArtificial) Doing it in a single phase triggers an LLVM assertion about the overlapping debug info fragment generated from this: swift-frontend: /SourceCache/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp:572: void llvm::DwarfExpr
ession::addFragmentOffset(const llvm::DIExpression *): Assertion `FragmentOffset >= OffsetInBits && "overlapping or duplicate fragments"' failed. It seems that |
Comment by Mustafa YALCIN (JIRA) 3 |
7 similar comments
Comment by Mustafa YALCIN (JIRA) 3 |
Comment by Mustafa YALCIN (JIRA) 3 |
Comment by Mustafa YALCIN (JIRA) 3 |
Comment by Mustafa YALCIN (JIRA) 3 |
Comment by Mustafa YALCIN (JIRA) 3 |
Comment by Mustafa YALCIN (JIRA) 3 |
Comment by Mustafa YALCIN (JIRA) 3 |
@compnerd I could not reproduce the issue. Can you add a more self contained test case, e.g. with full expanded invocation lines? Also I had to fix some obvious syntax errors in the test file. Also, how did you build the swift compiler? Is this reproducible on Mac? |
@eeckstein: the issue should be directly reproducible from the test case (which is a lit test) on both macOS and Linux. I pushed the test case to dan-zheng@SR-13263 so it's easier to reproduce. The crash is an LLVM assertion about overlapping debug info fragments: swift-frontend: /SourceCache/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp:572: void llvm::DwarfExpr
ession::addFragmentOffset(const llvm::DIExpression *): Assertion `FragmentOffset >= OffsetInBits && "overlapping or duplicate fragments"' failed. test/DebugInfo/sr13263.swift has a bunch of details. The issue is only reproducible with a two file test case and
Could someone please help take a look? @compnerd and I are reaching the limits of our debugging ability, so any help would be greatly appreciated! |
One thing that looks suspicious is multiple calls to ;; LLVM IR for the problematic function in SR-13263.
define hidden swiftcc void @"$s4main1TV4move5alongyAC13TangentVectorV_tF"(%T4main1TV13TangentVectorV* noalias nocapture dereferenceable(57) %0, %T4main1TV* nocapture swiftself dereferenceable(57) %1) #​0 !dbg !583 {
entry:
%2 = alloca %T4main1VV13TangentVectorV, align 8
call void @llvm.dbg.declare(metadata %T4main1VV13TangentVectorV* %2, metadata !586, metadata !DIExpression()), !dbg !590
%3 = alloca %T4main1UV13TangentVectorV, align 8
call void @llvm.dbg.declare(metadata %T4main1UV13TangentVectorV* %3, metadata !598, metadata !DIExpression()), !dbg !599
%4 = alloca %T4main1VV13TangentVectorV, align 8
call void @llvm.dbg.declare(metadata %T4main1VV13TangentVectorV* %4, metadata !586, metadata !DIExpression()), !dbg !600
%5 = alloca %T4main1UV13TangentVectorV, align 8
call void @llvm.dbg.declare(metadata %T4main1UV13TangentVectorV* %5, metadata !598, metadata !DIExpression()), !dbg !599 This is lowered from the following SIL post-LoadableByAddress (file): *** SIL module after #​99, stage IRGen Preparation, pass 1: LoadableByAddress (loadable-address)
// T.move(along:)
sil hidden @$s4main1TV4move5alongyAC13TangentVectorV_tF : $@convention(method) (@in_guaranteed T.TangentVector, @inout T) -> () {
// %0 "direction" // users: %6, %8, %41
// %1 "self" // users: %10, %43, %7
bb0(%0 : $*T.TangentVector, %1 : $*T):
%2 = alloc_stack $V.TangentVector // users: %38, %28, %30, %26, %76
%3 = alloc_stack $U.TangentVector // users: %11, %13, %25, %9, %75
%4 = alloc_stack $V.TangentVector // users: %69, %59, %61, %57, %74
%5 = alloc_stack $U.TangentVector // users: %44, %46, %56, %42, %73
debug_value_addr %0 : $*T.TangentVector, let, name "direction", argno 1 // id: %6
debug_value_addr %1 : $*T, var, name "self", argno 2 // id: %7
%8 = struct_element_addr %0 : $*T.TangentVector, #T.TangentVector.u1 // user: %9
copy_addr [take] %8 to [initialization] %3 : $*U.TangentVector // id: %9
%10 = struct_element_addr %1 : $*T, #T.u1 // users: %27, %15, %12
debug_value_addr %3 : $*U.TangentVector, let, name "direction", argno 1 // id: %11
debug_value_addr %10 : $*U, var, name "self", argno 2 // id: %12
...
%25 = struct_element_addr %3 : $*U.TangentVector, #U.TangentVector.v // user: %26
copy_addr [take] %25 to [initialization] %2 : $*V.TangentVector // id: %26
%27 = struct_element_addr %10 : $*U, #U.v // users: %40, %32, %29
debug_value_addr %2 : $*V.TangentVector, let, name "direction", argno 1 // id: %28
debug_value_addr %27 : $*V, var, name "self", argno 2 // id: %29
...
%41 = struct_element_addr %0 : $*T.TangentVector, #T.TangentVector.u2 // user: %42
copy_addr [take] %41 to [initialization] %5 : $*U.TangentVector // id: %42
%43 = struct_element_addr %1 : $*T, #T.u2 // users: %58, %48, %45
debug_value_addr %5 : $*U.TangentVector, let, name "direction", argno 1 // id: %44
debug_value_addr %43 : $*U, var, name "self", argno 2 // id: %45
...
%56 = struct_element_addr %5 : $*U.TangentVector, #U.TangentVector.v // user: %57
copy_addr [take] %56 to [initialization] %4 : $*V.TangentVector // id: %57
%58 = struct_element_addr %43 : $*U, #U.v // users: %71, %63, %60
debug_value_addr %4 : $*V.TangentVector, let, name "direction", argno 1 // id: %59
debug_value_addr %58 : $*V, var, name "self", argno 2 // id: %60
...
} // end sil function '$s4main1TV4move5alongyAC13TangentVectorV_tF' Is it legal to have multiple |
@adrian-prantl any thoughts? |
@dan-zheng I think that the reason might be that @eeckstein it just needs |
Assertion failure: swift-frontend: /SourceCache/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp:572: void llvm::DwarfExpression::addFragmentOffset(const llvm::DIExpression *): Assertion `FragmentOffset >= OffsetInBits && "overlapping or duplicate fragments"' failed.
...
3. Running pass 'X86 Assembly Printer' on function '@"$s4main1TV4move5alongyAC13TangentVectorV_tF"' This is using the current trunk build of swiftc -parse-as-library -O -g -I /tmp -emit-ir /tmp/reduced.swift -o - -module-name main -Xfrontend -disable-llvm-optzns This results in the following extracted IR: define hidden swiftcc void @"$s4main1TV4move5alongyAC13TangentVectorV_tF"(%T4main1TV13TangentVectorV* noalias nocapture dereferenceable(57) %0, %T4main1TV* nocapture swiftself dereferenceable(57) %1) #​0 !dbg !541 {
entry:
...
%3 = alloca %T4main1UV13TangentVectorV, align 8
call void @llvm.dbg.declare(metadata %T4main1UV13TangentVectorV* %3, metadata !556, metadata !DIExpression()), !dbg !557
...
%5 = alloca %T4main1UV13TangentVectorV, align 8
call void @llvm.dbg.declare(metadata %T4main1UV13TangentVectorV* %5, metadata !556, metadata !DIExpression()), !dbg !557
...
}
...
!0 = distinct !DICompileUnit(language: DW_LANG_Swift, file: !1, producer: "Swift version 5.3-dev (LLVM cd34624440cb40a, Swift 44ac558e3243ea3)", isOptimized: true, runtimeVersion: 5, emissionKind: FullDebug, enums: !2, imports: !3)
!1 = !DIFile(filename: "/tmp/reduced.swift", directory: "/SourceCache")
!2 = !{}
!3 = !{!4, !6, !8, !10}
!4 = !DIImportedEntity(tag: DW_TAG_imported_module, scope: !1, entity: !5, file: !1)
!5 = !DIModule(scope: null, name: "main", includePath: "/tmp")
!6 = !DIImportedEntity(tag: DW_TAG_imported_module, scope: !1, entity: !7, file: !1)
!7 = !DIModule(scope: null, name: "Swift", includePath: "/BinaryCache/Ninja-ReleaseAssert/swift-linux-x86_64/lib/swift/linux/Swift.swiftmodule/x86_64-unknown-linux-gnu.swiftmodule")
!8 = !DIImportedEntity(tag: DW_TAG_imported_module, scope: !1, entity: !9, file: !1, line: 27)
!9 = !DIModule(scope: null, name: "_Differentiation", includePath: "/BinaryCache/Ninja-ReleaseAssert/swift-linux-x86_64/lib/swift/linux/_Differentiation.swiftmodule/x86_64-unknown-linux-gnu.swiftmodule")
!10 = !DIImportedEntity(tag: DW_TAG_imported_module, scope: !1, entity: !11, file: !1, line: 28)
!11 = !DIModule(scope: null, name: "M", includePath: "/tmp/M.swiftmodule")
...
!127 = !DIFile(filename: "<compiler-generated>", directory: "")
...
!131 = !DICompositeType(tag: DW_TAG_structure_type, name: "U", scope: !5, file: !1, size: 200, elements: !2, runtimeLang: DW_LANG_Swift, identifier: "$s4main1UVD")
...
!139 = !DICompositeType(tag: DW_TAG_structure_type, name: "$sytD", file: !1, elements: !2, runtimeLang: DW_LANG_Swift, identifier: "$sytD")
...
!181 = !DICompositeType(tag: DW_TAG_structure_type, name: "TangentVector", scope: !131, file: !1, size: 200, elements: !2, runtimeLang: DW_LANG_Swift, identifier: "$s4main1UV13TangentVectorVD")
...
!242 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !181)
...
!551 = distinct !DISubprogram(name: "move", linkageName: "$s4main1UV4move5alongyAC13TangentVectorV_tF", scope: !131, file: !127, type: !552, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2)
!552 = !DISubroutineType(types: !553)
!553 = !{!139, !181, !131}
...
!556 = !DILocalVariable(name: "direction", arg: 1, scope: !551, file: !1, type: !242, flags: DIFlagArtificial) The interesting thing here is that there are two local variable definitions |
If the same variable (identified by ![](DILocalVariable metadata) is indeed mapped to two different allocas, I believe that's a frontend bug. I'd expect fresh )DILocalVariables to be set up for the allocas %3 and %5. Otherwise, this is saying that the same variable lives in two different stack slots. |
@adrian-prantl - |
@vedantk Interesting point. I was thinking that this could be legal if an object is passed into an inlined function by reference and thus the inlined function's byref variable shares the memory with the original object in the caller. But you are right that the input could already be wrong, too. |
@compnerd Do you know which pass inserts the debug_value(_addr) that turns into the duplicate dbg.declare? Is it something differention-related? |
@adrian-prantl: LoadableByAddress inserts the duplicate Here is the SIL before and after LoadableByAddress: https://github.com/dan-zheng/swift/blob/SR-13263/test/DebugInfo/sr13263.sil-print#L72. The SIL after LoadableByAddress looks very similar to the LLVM IR with duplicate dbg.declare: *** SIL module after #​99, stage IRGen Preparation, pass 1: LoadableByAddress (loadable-address)
// T.move(along:)
sil hidden @$s4main1TV4move5alongyAC13TangentVectorV_tF : $@convention(method) (@in_guaranteed T.TangentVector, @inout T) -> () {
// %0 "direction" // users: %6, %8, %41
// %1 "self" // users: %10, %43, %7
bb0(%0 : $*T.TangentVector, %1 : $*T):
%2 = alloc_stack $V.TangentVector // users: %38, %28, %30, %26, %76
%3 = alloc_stack $U.TangentVector // users: %11, %13, %25, %9, %75
%4 = alloc_stack $V.TangentVector // users: %69, %59, %61, %57, %74
%5 = alloc_stack $U.TangentVector // users: %44, %46, %56, %42, %73
debug_value_addr %0 : $*T.TangentVector, let, name "direction", argno 1 // id: %6
debug_value_addr %1 : $*T, var, name "self", argno 2 // id: %7
%8 = struct_element_addr %0 : $*T.TangentVector, #T.TangentVector.u1 // user: %9
copy_addr [take] %8 to [initialization] %3 : $*U.TangentVector // id: %9
%10 = struct_element_addr %1 : $*T, #T.u1 // users: %27, %15, %12
debug_value_addr %3 : $*U.TangentVector, let, name "direction", argno 1 // id: %11
debug_value_addr %10 : $*U, var, name "self", argno 2 // id: %12
...
%25 = struct_element_addr %3 : $*U.TangentVector, #U.TangentVector.v // user: %26
copy_addr [take] %25 to [initialization] %2 : $*V.TangentVector // id: %26
%27 = struct_element_addr %10 : $*U, #U.v // users: %40, %32, %29
debug_value_addr %2 : $*V.TangentVector, let, name "direction", argno 1 // id: %28
debug_value_addr %27 : $*V, var, name "self", argno 2 // id: %29
...
%41 = struct_element_addr %0 : $*T.TangentVector, #T.TangentVector.u2 // user: %42
copy_addr [take] %41 to [initialization] %5 : $*U.TangentVector // id: %42
%43 = struct_element_addr %1 : $*T, #T.u2 // users: %58, %48, %45
debug_value_addr %5 : $*U.TangentVector, let, name "direction", argno 1 // id: %44
debug_value_addr %43 : $*U, var, name "self", argno 2 // id: %45
...
%56 = struct_element_addr %5 : $*U.TangentVector, #U.TangentVector.v // user: %57
copy_addr [take] %56 to [initialization] %4 : $*V.TangentVector // id: %57
%58 = struct_element_addr %43 : $*U, #U.v // users: %71, %63, %60
debug_value_addr %4 : $*V.TangentVector, let, name "direction", argno 1 // id: %59
debug_value_addr %58 : $*V, var, name "self", argno 2 // id: %60
...
} // end sil function '$s4main1TV4move5alongyAC13TangentVectorV_tF' We confirmed that disabling LoadableByAddress fixes the LLVM "overlapping debug info fragments" assertion failure. Specifically, commenting out these lines from LoadableByAddress fixes the assertion failure: https://github.com/apple/swift/blob/f2545dc7d1a84aba0fc82b1eaaf1f5d49c139cb0/lib/IRGen/LoadableByAddress.cpp#L2127-L2129. Is this info useful to you? Could there be a bug in the LBA debug info propagation (or a bad interaction with inlining)? |
I could reproduce it now, thanks! @adrian-prantl Can you please take a look? |
@eeckstein I thought there is a small semantic difference between @adrian-prantl the odd debug information appears with the LBA pass. |
Well, ``debug_value_addr`` is just the address-version of ``debug_value``. The only difference should be that with the first, the value is in memory, with the second, the value is an SSA-value. |
@eeckstein Whichever SIL debug intrinsic is used (debug_value/debug_value_addr), if the storage for the variable is an alloca, the expectation is that there is a single/unique alloca for the variable that's live throughout the function. If that's not compatible with swift optimizations, we can find a way to fix that: llvm has a way to describe a variable whose address changes. Stepping back a bit, I'm not sure that the pre-pass SIL is correct. It looks like there are two assignments to the variable "direction", but they have different types (`$T.TangentVector` vs. `$U.TangentVector`). ``` What's the intended meaning? Is there supposed to be one variable ("direction") that changes value to `struct_extract %0`? Would it be preferable to simply omit the first `debug_value`? |
@vedantk: thanks for the catch about the pre-LoadableByAddress SIL. The multiple debug_value instructions appear after inlining, when *** SIL function after #​6270, stage HighLevel,Function+EarlyLoopOpt, pass 18: EarlyInliner (early-inline)
// T.move(along:)
sil hidden @$s4main1TV4move5alongyAC13TangentVectorV_tF : $@convention(method) (@guaranteed T.TangentVector, @inout T) -> () {
// %0 "direction" // users: %36, %4, %2
// %1 "self" // users: %5, %37, %3
bb0(%0 : $T.TangentVector, %1 : $*T):
debug_value %0 : $T.TangentVector, let, name "direction", argno 1 // id: %2
debug_value_addr %1 : $*T, var, name "self", argno 2 // id: %3
%4 = struct_extract %0 : $T.TangentVector, #T.TangentVector.u1 // users: %20, %8, %6
%5 = struct_element_addr %1 : $*T, #T.u1 // users: %21, %9, %7
debug_value %4 : $U.TangentVector, let, name "direction", argno 1 // id: %6
debug_value_addr %5 : $*U, var, name "self", argno 2 // id: %7
Is it right for inlining to preserve these SIL debug_value/debug_value_addr instructions, or do the instructions conflict (because they have the same name and argno but different types)? |
@VedantKI'm not really familiar with the debug info model. This would be a question for @adrian-prantl |
Comment by Fan Jiang (JIRA) Encountered the same bug today when I try to build swift-apis from TensorFlow. debuginfo is indeed generated twice. |
* 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
LLVM seems to determine a variable instance as a combination of DILocalVariable and DILocation. Therefore if multiple llvm.dbg.declare have the same variable/location parameters, they are considered to be referencing the same instance of variable. Swift IRGen emits a set of llvm.dbg.declare calls for every variable instance (with unique SILDebugScope), so it is important that these calls have distinct variable/location parameters. Otherwise their DIExpression may be incorrect when treated as referencing the same variable. For example, if they have a DIExpression with fragments, we will see this as multiple declarations of the same fragment. LLVM detects this and crashes with assertion failure: DwarfExpression.cpp:679: void llvm::DwarfExpression::addFragmentOffset(const llvm::DIExpression *): Assertion `FragmentOffset >= OffsetInBits && "overlapping or duplicate fragments"' failed. The patch resolves swiftlang#55703. The LIT test (debug_scope_distinct.swift) is the reproducer from that issue.
LLVM seems to determine a variable instance as a combination of DILocalVariable and DILocation. Therefore if multiple llvm.dbg.declare have the same variable/location parameters, they are considered to be referencing the same instance of variable. Swift IRGen emits a set of llvm.dbg.declare calls for every variable instance (with unique SILDebugScope), so it is important that these calls have distinct variable/location parameters. Otherwise their DIExpression may be incorrect when treated as referencing the same variable. For example, if they have a DIExpression with fragments, we will see this as multiple declarations of the same fragment. LLVM detects this and crashes with assertion failure: DwarfExpression.cpp:679: void llvm::DwarfExpression::addFragmentOffset(const llvm::DIExpression *): Assertion `FragmentOffset >= OffsetInBits && "overlapping or duplicate fragments"' failed. The patch resolves swiftlang#55703. The LIT test (debug_scope_distinct.swift) is the reproducer from that issue.
LLVM seems to determine a variable instance as a combination of DILocalVariable and DILocation. Therefore if multiple llvm.dbg.declare have the same variable/location parameters, they are considered to be referencing the same instance of variable. Swift IRGen emits a set of llvm.dbg.declare calls for every variable instance (with unique SILDebugScope), so it is important that these calls have distinct variable/location parameters. Otherwise their DIExpression may be incorrect when treated as referencing the same variable. For example, if they have a DIExpression with fragments, we will see this as multiple declarations of the same fragment. LLVM detects this and crashes with assertion failure: DwarfExpression.cpp:679: void llvm::DwarfExpression::addFragmentOffset(const llvm::DIExpression *): Assertion `FragmentOffset >= OffsetInBits && "overlapping or duplicate fragments"' failed. The patch resolves swiftlang#55703. The LIT test (debug_scope_distinct.swift) is the reproducer from that issue.
LLVM seems to determine a variable instance as a combination of DILocalVariable and DILocation. Therefore if multiple llvm.dbg.declare have the same variable/location parameters, they are considered to be referencing the same instance of variable. Swift IRGen emits a set of llvm.dbg.declare calls for every variable instance (with unique SILDebugScope), so it is important that these calls have distinct variable/location parameters. Otherwise their DIExpression may be incorrect when treated as referencing the same variable. For example, if they have a DIExpression with fragments, we will see this as multiple declarations of the same fragment. LLVM detects this and crashes with assertion failure: DwarfExpression.cpp:679: void llvm::DwarfExpression::addFragmentOffset(const llvm::DIExpression *): Assertion `FragmentOffset >= OffsetInBits && "overlapping or duplicate fragments"' failed. The patch resolves swiftlang#55703. The LIT test (debug_scope_distinct.swift) is the reproducer from that issue.
The patch resolves swiftlang#55703. When the original function has a tuple result type, we should append thunkedLinearMap as the last element of the tuple to match the function declaration. Before this patch, the compiler used to wrap the original result tuple and thunkedLinearMap into another tuple, and caused the verifier error. Before the patch: return %{{.*}} : $((Float, Double), @callee_guaranteed (X.TangentVector) -> Float) After the patch: return %{{.*}} : $(Float, Double, @callee_guaranteed (Float) -> X.TangentVector)
Attachment: Download
Additional Detail from JIRA
md5: 1cf1abd3137f286141ea88df6a315030
Issue Description:
lit test reproducer:
Crash:
The text was updated successfully, but these errors were encountered: