Index: lib/Transforms/InstCombine/InstCombineCasts.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineCasts.cpp +++ lib/Transforms/InstCombine/InstCombineCasts.cpp @@ -1088,17 +1088,31 @@ uint32_t SrcBitsKept = SrcTy->getScalarSizeInBits()-BitsToClear; uint32_t DestBitSize = DestTy->getScalarSizeInBits(); + // Since the old instruction is merged, we preserve it's DI as + // a fragment in the resulting instruction + SmallVector SrcDbgInsts; + findDbgUsers(SrcDbgInsts, Src); + if (SrcDbgInsts.size()) { + DIBuilder DIB(*CI.getModule()); + for (auto *DII : SrcDbgInsts) { + auto Fragment = DIExpression::createFragmentExpression( + DII->getExpression(), SrcBitsKept, DestBitSize); + DIB.insertDbgValueIntrinsic( + Res, DII->getVariable(), Fragment.getValue(), + DII->getDebugLoc().get(), &*std::next(CI.getIterator())); + } + } + // If the high bits are already filled with zeros, just replace this // cast with the result. - if (MaskedValueIsZero(Res, - APInt::getHighBitsSet(DestBitSize, - DestBitSize-SrcBitsKept), - 0, &CI)) + if (MaskedValueIsZero( + Res, APInt::getHighBitsSet(DestBitSize, DestBitSize - SrcBitsKept), + 0, &CI)) return replaceInstUsesWith(CI, Res); // We need to emit an AND to clear the high bits. - Constant *C = ConstantInt::get(Res->getType(), - APInt::getLowBitsSet(DestBitSize, SrcBitsKept)); + Constant *C = ConstantInt::get( + Res->getType(), APInt::getLowBitsSet(DestBitSize, SrcBitsKept)); return BinaryOperator::CreateAnd(Res, C); } Index: test/Transforms/InstCombine/debuginfo-trunc-and-zext.ll =================================================================== --- /dev/null +++ test/Transforms/InstCombine/debuginfo-trunc-and-zext.ll @@ -0,0 +1,43 @@ +; RUN: opt -instcombine -S < %s | FileCheck %s + +define <2 x i64> @test3(<2 x i64> %A) !dbg !6 { + %trunc = trunc <2 x i64> %A to <2 x i32>, !dbg !14 + call void @llvm.dbg.value(metadata <2 x i32> %trunc, metadata !9, metadata !DIExpression()), !dbg !14 + %and = and <2 x i32> %trunc, , !dbg !15 + call void @llvm.dbg.value(metadata <2 x i32> %and, metadata !11, metadata !DIExpression()), !dbg !15 + %zext = zext <2 x i32> %and to <2 x i64>, !dbg !16 + call void @llvm.dbg.value(metadata <2 x i64> %zext, metadata !12, metadata !DIExpression()), !dbg !16 + ret <2 x i64> %zext, !dbg !17 +} + +; CHECK: call void @llvm.dbg.value{{.*}} +; CHECK: call void @llvm.dbg.value{{.*}} +; CHECK: call void @llvm.dbg.value{{.*}} + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #0 + +attributes #0 = { nounwind readnone speculatable } + +!llvm.dbg.cu = !{!0} +!llvm.debugify = !{!3, !4} +!llvm.module.flags = !{!5} + +!0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) +!1 = !DIFile(filename: "debuginfo-trunc-and-zext.ll", directory: "/") +!2 = !{} +!3 = !{i32 4} +!4 = !{i32 3} +!5 = !{i32 2, !"Debug Info Version", i32 3} +!6 = distinct !DISubprogram(name: "test3", linkageName: "test3", scope: null, file: !1, line: 1, type: !7, isLocal: false, isDefinition: true, scopeLine: 1, isOptimized: true, unit: !0, retainedNodes: !8) +!7 = !DISubroutineType(types: !2) +!8 = !{!9, !11, !12} +!9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10) +!10 = !DIBasicType(name: "ty64", size: 64, encoding: DW_ATE_unsigned) +!11 = !DILocalVariable(name: "2", scope: !6, file: !1, line: 2, type: !10) +!12 = !DILocalVariable(name: "3", scope: !6, file: !1, line: 3, type: !13) +!13 = !DIBasicType(name: "ty128", size: 128, encoding: DW_ATE_unsigned) +!14 = !DILocation(line: 1, column: 1, scope: !6) +!15 = !DILocation(line: 2, column: 1, scope: !6) +!16 = !DILocation(line: 3, column: 1, scope: !6) +!17 = !DILocation(line: 4, column: 1, scope: !6)