Index: llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp =================================================================== --- llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp +++ llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp @@ -6194,15 +6194,17 @@ // Some DVIs that were single location-op when cached are now multi-op, // due to LSR optimisations. However, multi-op salvaging is not yet // supported by SCEV salvaging. But, we can attempt a salvage by restoring - // the pre-LSR single-op expression. + // the pre-LSR single-op location and expression. if (DVIRec.DVI->hasArgList()) { if (!DVIRec.DVI->getVariableLocationOp(0)) continue; llvm::Type *Ty = DVIRec.DVI->getVariableLocationOp(0)->getType(); DVIRec.DVI->setRawLocation( llvm::ValueAsMetadata::get(UndefValue::get(Ty))); - DVIRec.DVI->setExpression(DVIRec.Expr); } + // LSR may have modified the expression during a salvage attempt, so + // restore to the expression that corresponds to the cached SCEV. + DVIRec.DVI->setExpression(DVIRec.Expr); Changed |= RewriteDVIUsingIterCount(DVIRec, IterCountExpr, SE); } Index: llvm/test/Transforms/LoopStrengthReduce/dbg-preserve-2.ll =================================================================== --- llvm/test/Transforms/LoopStrengthReduce/dbg-preserve-2.ll +++ llvm/test/Transforms/LoopStrengthReduce/dbg-preserve-2.ll @@ -1,8 +1,10 @@ ; RUN: opt < %s -loop-reduce -S | FileCheck %s -; Test that LSR does not produce invalid debug info when a debug value is -; salvaged during LSR by adding additional location operands, then becomes -; undef, and finally recovered by SCEV salvaging. +; When attempting to salvage a dbg.value, LSR modifies the dbg.value arguments +; whether or not the salvage is successful. For SCEV-based salvaging to work +; correctly, after LSR the arguments must be restored from the cache. Even if +; locations are now undef, the dbg.value should have the same numbr of location +; operands. target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" Index: llvm/test/Transforms/LoopStrengthReduce/dbg-preserve-3.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/LoopStrengthReduce/dbg-preserve-3.ll @@ -0,0 +1,175 @@ +; RUN: opt -loop-reduce -S %s | FileCheck %s +; When attempting to salvage a dbg.value, LSR modifies the dbg.value arguments +; whether or not the salvage is successful. For SCEV-based salvaging to work +; correctly, after LSR the arguments must be restorded from the cache. If the +; DIExpression has been modified, it must be restored to ensure a oorrect +; expression is generated; + +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +%class.p = type { i8 } +%class.m = type { %class.l.base, [4 x i8] } +%class.l.base = type { %class.i.base } +%class.i.base = type { %class.h.base } +%class.h.base = type <{ %class.d, i32 }> +%class.d = type { i8* } + +@o = dso_local local_unnamed_addr global %class.p* null, align 8, !dbg !0 + +define dso_local void @flump() local_unnamed_addr !dbg !57 { +for.body.preheader: + %a = alloca %class.m, align 8 + %0 = bitcast %class.m* %a to i8*, !dbg !64 + %1 = getelementptr inbounds %class.m, %class.m* %a, i64 0, i32 0, i32 0, i32 0, i32 1, !dbg !65 + %2 = bitcast %class.m* %a to i32**, !dbg !88 + store i32* %1, i32** %2, align 8, !dbg !88 + %e.i = getelementptr inbounds %class.m, %class.m* %a, i64 0, i32 0, i32 0, i32 0, i32 0, i32 0 + %3 = bitcast i32* %1 to i8*, !dbg !95 + br label %for.body, !dbg !95 + +for.cond.cleanup: + call void @llvm.lifetime.end.p0i8(i64 16, i8* nonnull %0), !dbg !64 + ret void, !dbg !64 + +for.body: + %4 = phi i8* [ %.pre, %_ZN1i1jEv.exit.for.body_crit_edge ], [ %3, %for.body.preheader ], !dbg !96 + %c.03 = phi %class.p* [ %incdec.ptr, %_ZN1i1jEv.exit.for.body_crit_edge ], [ undef, %for.body.preheader ] + %tobool.not.i = icmp eq i8* %4, null, !dbg !96 + br i1 %tobool.not.i, label %_ZN1i1jEv.exit, label %if.then.i, !dbg !103 + +if.then.i: ; preds = %for.body + call void @_Z1bv(), !dbg !96 + br label %_ZN1i1jEv.exit, !dbg !96 + +_ZN1i1jEv.exit: + %incdec.ptr = getelementptr inbounds %class.p, %class.p* %c.03, i64 1, !dbg !104 + ; CHECK-NOT: call void @llvm.dbg.value(metadata %class.p* %lsr.iv, metadata ![[var_c]], metadata !DIExpression(DW_OP_plus_uconst, 1, DW_OP_plus_uconst, 1, DW_OP_stack_value)), + ; CHECK: call void @llvm.dbg.value(metadata %class.p* %lsr.iv, metadata ![[var_c:[0-9]+]], metadata !DIExpression(DW_OP_plus_uconst, 1, DW_OP_stack_value)), + call void @llvm.dbg.value(metadata %class.p* %incdec.ptr, metadata !62, metadata !DIExpression()), !dbg !106 + call void @llvm.dbg.value(metadata %class.p* %incdec.ptr, metadata !62, metadata !DIExpression()), !dbg !95 + %5 = load %class.p*, %class.p** @o, align 8, !dbg !104 + %cmp.not = icmp eq %class.p* %incdec.ptr, %5, !dbg !104 + br i1 %cmp.not, label %for.cond.cleanup, label %_ZN1i1jEv.exit.for.body_crit_edge, !dbg !95, !llvm.loop !105 +_ZN1i1jEv.exit.for.body_crit_edge: + %.pre = load i8*, i8** %e.i, align 8, !dbg !96 + br label %for.body, !dbg !95 +} + +declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) +declare !dbg !108 dso_local void @_Z1bv() local_unnamed_addr +declare void @llvm.dbg.value(metadata, metadata, metadata) + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!52, !53, !54, !55} +!llvm.ident = !{!56} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "o", scope: !2, file: !6, line: 32, type: !48, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang version 14.0.0 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, retainedTypes: !4, globals: !47, splitDebugInlining: false, nameTableKind: None) +!3 = !DIFile(filename: "min.cpp", directory: "/test") +!4 = !{!5, !9, !12, !15, !18} +!5 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "m<6>", file: !6, line: 24, size: 128, flags: DIFlagTypePassByValue | DIFlagNonTrivial, elements: !7, templateParams: !45, identifier: "_ZTS1mILi6EE") +!6 = !DIFile(filename: "./min.cpp", directory: "/test") +!7 = !{!8, !41} +!8 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !5, baseType: !9, flags: DIFlagPublic, extraData: i32 0) +!9 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "l", file: !6, line: 20, size: 128, flags: DIFlagTypePassByValue | DIFlagNonTrivial, elements: !10, identifier: "_ZTS1l") +!10 = !{!11, !36} +!11 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !9, baseType: !12, flags: DIFlagPublic, extraData: i32 0) +!12 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "i", file: !6, line: 13, size: 128, flags: DIFlagTypePassByValue | DIFlagNonTrivial, elements: !13, identifier: "_ZTS1i") +!13 = !{!14, !32} +!14 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !12, baseType: !15, extraData: i32 0) +!15 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "h", file: !6, line: 7, size: 128, flags: DIFlagTypePassByValue | DIFlagNonTrivial, elements: !16, identifier: "_ZTS1h") +!16 = !{!17, !26, !28} +!17 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !15, baseType: !18, flags: DIFlagPublic, extraData: i32 0) +!18 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "d", file: !6, line: 2, size: 64, flags: DIFlagTypePassByValue | DIFlagNonTrivial, elements: !19, identifier: "_ZTS1d") +!19 = !{!20, !22} +!20 = !DIDerivedType(tag: DW_TAG_member, name: "e", scope: !18, file: !6, line: 4, baseType: !21, size: 64, flags: DIFlagProtected) +!21 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) +!22 = !DISubprogram(name: "d", scope: !18, file: !6, line: 5, type: !23, scopeLine: 5, flags: DIFlagProtected | DIFlagPrototyped, spFlags: DISPFlagOptimized) +!23 = !DISubroutineType(types: !24) +!24 = !{null, !25, !21} +!25 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !18, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) +!26 = !DIDerivedType(tag: DW_TAG_member, name: "f", scope: !15, file: !6, line: 8, baseType: !27, size: 32, offset: 64) +!27 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!28 = !DISubprogram(name: "h", scope: !15, file: !6, line: 11, type: !29, scopeLine: 11, flags: DIFlagProtected | DIFlagPrototyped, spFlags: DISPFlagOptimized) +!29 = !DISubroutineType(types: !30) +!30 = !{null, !31} +!31 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !15, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) +!32 = !DISubprogram(name: "j", linkageName: "_ZN1i1jEv", scope: !12, file: !6, line: 15, type: !33, scopeLine: 15, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagOptimized) +!33 = !DISubroutineType(types: !34) +!34 = !{null, !35} +!35 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) +!36 = !DISubprogram(name: "l", scope: !9, file: !6, line: 22, type: !37, scopeLine: 22, flags: DIFlagProtected | DIFlagPrototyped, spFlags: DISPFlagOptimized) +!37 = !DISubroutineType(types: !38) +!38 = !{null, !39, !40} +!39 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !9, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) +!40 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!41 = !DISubprogram(name: "m", scope: !5, file: !6, line: 26, type: !42, scopeLine: 26, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagOptimized) +!42 = !DISubroutineType(types: !43) +!43 = !{null, !44} +!44 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) +!45 = !{!46} +!46 = !DITemplateValueParameter(name: "k", type: !27, value: i32 6) +!47 = !{!0} +!48 = !DIDerivedType(tag: DW_TAG_typedef, name: "n", scope: !49, file: !6, line: 30, baseType: !51) +!49 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "p", file: !6, line: 28, size: 8, flags: DIFlagTypePassByValue, elements: !50, identifier: "_ZTS1p") +!50 = !{} +!51 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !49, size: 64) +!52 = !{i32 7, !"Dwarf Version", i32 4} +!53 = !{i32 2, !"Debug Info Version", i32 3} +!54 = !{i32 1, !"wchar_size", i32 4} +!55 = !{i32 7, !"uwtable", i32 1} +!56 = !{!"clang version 14.0.0"} +!57 = distinct !DISubprogram(name: "fn2", linkageName: "flump", scope: !6, file: !6, line: 33, type: !58, scopeLine: 33, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !60) +!58 = !DISubroutineType(types: !59) +!59 = !{null} +!60 = !{!61, !62} +!61 = !DILocalVariable(name: "a", scope: !57, file: !6, line: 34, type: !5) +!62 = !DILocalVariable(name: "c", scope: !63, file: !6, line: 35, type: !48) +!63 = distinct !DILexicalBlock(scope: !57, file: !6, line: 35, column: 3) +!64 = !DILocation(line: 34, column: 3, scope: !57) +!65 = !DILocation(line: 11, column: 12, scope: !66, inlinedAt: !70) +!66 = distinct !DISubprogram(name: "h", linkageName: "_ZN1hC2Ev", scope: !15, file: !6, line: 11, type: !29, scopeLine: 11, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, declaration: !28, retainedNodes: !67) +!67 = !{!68} +!68 = !DILocalVariable(name: "this", arg: 1, scope: !66, type: !69, flags: DIFlagArtificial | DIFlagObjectPointer) +!69 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !15, size: 64) +!70 = distinct !DILocation(line: 13, column: 7, scope: !71, inlinedAt: !76) +!71 = distinct !DISubprogram(name: "i", linkageName: "_ZN1iC2Ev", scope: !12, file: !6, line: 13, type: !33, scopeLine: 13, flags: DIFlagArtificial | DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, declaration: !72, retainedNodes: !73) +!72 = !DISubprogram(name: "i", scope: !12, type: !33, flags: DIFlagPublic | DIFlagArtificial | DIFlagPrototyped, spFlags: DISPFlagOptimized) +!73 = !{!74} +!74 = !DILocalVariable(name: "this", arg: 1, scope: !71, type: !75, flags: DIFlagArtificial | DIFlagObjectPointer) +!75 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64) +!76 = distinct !DILocation(line: 22, column: 3, scope: !77, inlinedAt: !82) +!77 = distinct !DISubprogram(name: "l", linkageName: "_ZN1lC2Ej", scope: !9, file: !6, line: 22, type: !37, scopeLine: 22, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, declaration: !36, retainedNodes: !78) +!78 = !{!79, !81} +!79 = !DILocalVariable(name: "this", arg: 1, scope: !77, type: !80, flags: DIFlagArtificial | DIFlagObjectPointer) +!80 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !9, size: 64) +!81 = !DILocalVariable(arg: 2, scope: !77, file: !6, line: 22, type: !40) +!82 = distinct !DILocation(line: 26, column: 9, scope: !83, inlinedAt: !87) +!83 = distinct !DISubprogram(name: "m", linkageName: "_ZN1mILi6EEC2Ev", scope: !5, file: !6, line: 26, type: !42, scopeLine: 26, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, declaration: !41, retainedNodes: !84) +!84 = !{!85} +!85 = !DILocalVariable(name: "this", arg: 1, scope: !83, type: !86, flags: DIFlagArtificial | DIFlagObjectPointer) +!86 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64) +!87 = distinct !DILocation(line: 34, column: 8, scope: !57) +!88 = !DILocation(line: 5, column: 16, scope: !89, inlinedAt: !94) +!89 = distinct !DISubprogram(name: "d", linkageName: "_ZN1dC2EPv", scope: !18, file: !6, line: 5, type: !23, scopeLine: 5, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, declaration: !22, retainedNodes: !90) +!90 = !{!91, !93} +!91 = !DILocalVariable(name: "this", arg: 1, scope: !89, type: !92, flags: DIFlagArtificial | DIFlagObjectPointer) +!92 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !18, size: 64) +!93 = !DILocalVariable(name: "g", arg: 2, scope: !89, file: !6, line: 5, type: !21) +!94 = distinct !DILocation(line: 11, column: 9, scope: !66, inlinedAt: !70) +!95 = !DILocation(line: 35, column: 3, scope: !63) +!96 = !DILocation(line: 16, column: 9, scope: !97, inlinedAt: !101) +!97 = distinct !DILexicalBlock(scope: !98, file: !6, line: 16, column: 9) +!98 = distinct !DISubprogram(name: "j", linkageName: "_ZN1i1jEv", scope: !12, file: !6, line: 15, type: !33, scopeLine: 15, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, declaration: !32, retainedNodes: !99) +!99 = !{!100} +!100 = !DILocalVariable(name: "this", arg: 1, scope: !98, type: !75, flags: DIFlagArtificial | DIFlagObjectPointer) +!101 = distinct !DILocation(line: 36, column: 7, scope: !102) +!102 = distinct !DILexicalBlock(scope: !63, file: !6, line: 35, column: 3) +!103 = !DILocation(line: 16, column: 9, scope: !98, inlinedAt: !101) +!104 = !DILocation(line: 35, column: 24, scope: !102) +!105 = distinct !{!105, !95, !106, !107} +!106 = !DILocation(line: 36, column: 9, scope: !63) +!107 = !{!"llvm.loop.mustprogress"} +!108 = !DISubprogram(name: "b", linkageName: "_Z1bv", scope: !6, file: !6, line: 1, type: !58, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !50)