Index: llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -5457,14 +5457,38 @@ = [&](ArrayRef> SplitRegs) { unsigned Offset = 0; for (auto RegAndSize : SplitRegs) { + // If the expression is already a fragment, the current register + // offset+size might extend beyond the fragment. In this case, only + // the register bits that are inside the fragment are relevant. + int RegFragmentSizeInBits = RegAndSize.second; + if (auto ExprFragmentInfo = Expr->getFragmentInfo()) { + uint64_t ExprFragmentSizeInBits = ExprFragmentInfo->SizeInBits; + // The register is entirely outside the expression fragment, + // so is irrelevant for debug info. + if (Offset >= ExprFragmentSizeInBits) + break; + // The register is partially outside the expression fragment, only + // the low bits within the fragment are relevant for debug info. + if (Offset + RegFragmentSizeInBits > ExprFragmentSizeInBits) { + RegFragmentSizeInBits = ExprFragmentSizeInBits - Offset; + } + } + auto FragmentExpr = DIExpression::createFragmentExpression( - Expr, Offset, RegAndSize.second); - if (!FragmentExpr) + Expr, Offset, RegFragmentSizeInBits); + Offset += RegAndSize.second; + // If a valid fragment expression cannot be created, the variable's + // correct value cannot be determined and so it is set as Undef. + if (!FragmentExpr) { + SDDbgValue *SDV = DAG.getConstantDbgValue( + Variable, Expr, UndefValue::get(V->getType()), DL, SDNodeOrder); + DAG.AddDbgValue(SDV, nullptr, false); continue; + } + Op = MachineOperand::CreateReg(RegAndSize.first, false); FuncInfo.ArgDbgValues.push_back( BuildMI(MF, DL, TII->get(TargetOpcode::DBG_VALUE), IsDbgDeclare, RegAndSize.first, Variable, *FragmentExpr)); - Offset += RegAndSize.second; } }; @@ -5493,6 +5517,7 @@ if (!Op) return false; + assert(Variable->isValidLocationForIntrinsic(DL) && "Expected inlined-at fields to agree"); IsIndirect = (Op->isReg()) ? IsIndirect : true; Index: llvm/lib/IR/DebugInfoMetadata.cpp =================================================================== --- llvm/lib/IR/DebugInfoMetadata.cpp +++ llvm/lib/IR/DebugInfoMetadata.cpp @@ -1139,6 +1139,7 @@ for (auto Op : Expr->expr_ops()) { switch (Op.getOp()) { default: break; + case dwarf::DW_OP_shr: case dwarf::DW_OP_plus: case dwarf::DW_OP_minus: // We can't safely split arithmetic into multiple fragments because we Index: llvm/lib/Transforms/Utils/Local.cpp =================================================================== --- llvm/lib/Transforms/Utils/Local.cpp +++ llvm/lib/Transforms/Utils/Local.cpp @@ -1666,8 +1666,27 @@ // No-op casts and zexts are irrelevant for debug info. if (CI->isNoopCast(DL) || isa(&I)) return SrcDIExpr; - return nullptr; - } else if (auto *GEP = dyn_cast(&I)) { + + Type *Type = CI->getType(); + // Casts other than Trunc or SExt to scalar types cannot be salvaged. + if (Type->isVectorTy() || (!isa(&I) && !isa(&I))) + return nullptr; + + Value *FromValue = CI->getOperand(0); + unsigned FromTypeBitSize = FromValue->getType()->getScalarSizeInBits(); + + unsigned ToTypeBitSize = Type->getScalarSizeInBits(); + + // The result of the cast will be sign extended iff the instruction is a + // SExt; signedness is otherwise irrelevant on the expression stack. + unsigned Encoding = + isa(&I) ? dwarf::DW_ATE_signed : dwarf::DW_ATE_unsigned; + + return applyOps({dwarf::DW_OP_LLVM_convert, FromTypeBitSize, Encoding, + dwarf::DW_OP_LLVM_convert, ToTypeBitSize, Encoding}); + } + + if (auto *GEP = dyn_cast(&I)) { unsigned BitWidth = M.getDataLayout().getIndexSizeInBits(GEP->getPointerAddressSpace()); // Rewrite a constant GEP into a DIExpression. Index: llvm/test/CodeGen/ARM/fragmented-args-multiple-regs.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/ARM/fragmented-args-multiple-regs.ll @@ -0,0 +1,77 @@ +; RUN: llc < %s -mtriple=armv7-linux-gnueabihf -O1 -stop-after=finalize-isel | FileCheck %s + +; Function Attrs: norecurse nounwind readnone +define dso_local i32 @h(i64 %j) local_unnamed_addr #0 !dbg !8 { +entry: + call void @llvm.dbg.value(metadata i64 %j, metadata !14, metadata !DIExpression()), !dbg !29 + call void @llvm.dbg.value(metadata i64 %j, metadata !15, metadata !DIExpression(DW_OP_LLVM_convert, 64, DW_ATE_unsigned, DW_OP_LLVM_convert, 32, DW_ATE_unsigned, DW_OP_stack_value, DW_OP_LLVM_fragment, 0, 32)), !dbg !29 + call void @llvm.dbg.value(metadata i64 %j, metadata !15, metadata !DIExpression(DW_OP_constu, 32, DW_OP_shr, DW_OP_LLVM_convert, 64, DW_ATE_unsigned, DW_OP_LLVM_convert, 32, DW_ATE_unsigned, DW_OP_stack_value, DW_OP_LLVM_fragment, 32, 32)), !dbg !29 + %tobool = icmp ult i64 %j, 4294967296, !dbg !30 + br i1 %tobool, label %cleanup, label %if.then, !dbg !31 + +if.then: ; preds = %entry + call void @llvm.dbg.value(metadata i64 %j, metadata !15, metadata !DIExpression(DW_OP_LLVM_convert, 64, DW_ATE_unsigned, DW_OP_LLVM_convert, 32, DW_ATE_unsigned, DW_OP_stack_value, DW_OP_LLVM_fragment, 0, 32)), !dbg !29 + %conv = sitofp i64 %j to double, !dbg !32 + %add = fadd double %conv, 0x43F0000000000000, !dbg !33 + call void @llvm.dbg.value(metadata double %add, metadata !25, metadata !DIExpression()), !dbg !34 + %conv2 = fptosi double %add to i32, !dbg !35 + br label %cleanup + +cleanup: ; preds = %entry, %if.then + %retval.0 = phi i32 [ %conv2, %if.then ], [ undef, %entry ] + ret i32 %retval.0, !dbg !36 +} + +; CHECK-LABEL: bb.0.entry: +; CHECK: DBG_VALUE $noreg, $noreg, !15, !DIExpression({{.+}}DW_OP_LLVM_fragment, 32, 32 +; CHECK: DBG_VALUE [[REG1:%[0-9]+]], $noreg, !14, !DIExpression(DW_OP_LLVM_fragment, 32, 32 +; CHECK: DBG_VALUE [[REG2:%[0-9]+]], $noreg, !14, !DIExpression(DW_OP_LLVM_fragment, 0, 32 +; CHECK: DBG_VALUE [[REG2]], $noreg, !15, !DIExpression({{.+}}DW_OP_LLVM_fragment, 0, 32 + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #1 + +attributes #0 = { norecurse nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+armv7-a,+dsp,+neon,+vfp3,-thumb-mode" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone speculatable } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5, !6} +!llvm.ident = !{!7} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "tif_aux.c", directory: "/tmp") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{i32 1, !"min_enum_size", i32 4} +!7 = !{!"clang version 9.0.0 "} +!8 = distinct !DISubprogram(name: "h", scope: !1, file: !1, line: 10, type: !9, scopeLine: 10, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !13) +!9 = !DISubroutineType(types: !10) +!10 = !{!11, !12} +!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!12 = !DIBasicType(name: "long long int", size: 64, encoding: DW_ATE_signed) +!13 = !{!14, !15, !25} +!14 = !DILocalVariable(name: "j", arg: 1, scope: !8, file: !1, line: 10, type: !12) +!15 = !DILocalVariable(name: "i", scope: !8, file: !1, line: 11, type: !16) +!16 = !DIDerivedType(tag: DW_TAG_typedef, name: "g", file: !1, line: 8, baseType: !17) +!17 = distinct !DICompositeType(tag: DW_TAG_union_type, file: !1, line: 5, size: 64, elements: !18) +!18 = !{!19, !24} +!19 = !DIDerivedType(tag: DW_TAG_member, name: "e", scope: !17, file: !1, line: 6, baseType: !20, size: 64) +!20 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "b", file: !1, line: 1, size: 64, elements: !21) +!21 = !{!22, !23} +!22 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !20, file: !1, line: 2, baseType: !11, size: 32) +!23 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !20, file: !1, line: 2, baseType: !11, size: 32, offset: 32) +!24 = !DIDerivedType(tag: DW_TAG_member, name: "f", scope: !17, file: !1, line: 7, baseType: !12, size: 64) +!25 = !DILocalVariable(name: "a", scope: !26, file: !1, line: 14, type: !28) +!26 = distinct !DILexicalBlock(scope: !27, file: !1, line: 13, column: 14) +!27 = distinct !DILexicalBlock(scope: !8, file: !1, line: 13, column: 7) +!28 = !DIBasicType(name: "double", size: 64, encoding: DW_ATE_float) +!29 = !DILocation(line: 0, scope: !8) +!30 = !DILocation(line: 13, column: 7, scope: !27) +!31 = !DILocation(line: 13, column: 7, scope: !8) +!32 = !DILocation(line: 14, column: 16, scope: !26) +!33 = !DILocation(line: 14, column: 20, scope: !26) +!34 = !DILocation(line: 0, scope: !26) +!35 = !DILocation(line: 15, column: 12, scope: !26) +!36 = !DILocation(line: 17, column: 1, scope: !8) Index: llvm/test/DebugInfo/salvage-cast-debug-info.ll =================================================================== --- /dev/null +++ llvm/test/DebugInfo/salvage-cast-debug-info.ll @@ -0,0 +1,25 @@ +; RUN: opt %s -debugify -early-cse -S | FileCheck %s +define i32 @foo(i64 %nose, i32 %more) { +; CHECK-LABEL: @foo( +; CHECK: call void @llvm.dbg.value(metadata i64 %nose, metadata [[V1:![0-9]+]], metadata !DIExpression(DW_OP_LLVM_convert, 64, DW_ATE_unsigned, DW_OP_LLVM_convert, 32, DW_ATE_unsigned +; CHECK: call void @llvm.dbg.value(metadata i64 %nose.shift, metadata [[V2:![0-9]+]] +; CHECK: call void @llvm.dbg.value(metadata i64 %nose.shift, metadata [[V3:![0-9]+]], metadata !DIExpression(DW_OP_LLVM_convert, 64, DW_ATE_unsigned, DW_OP_LLVM_convert, 32, DW_ATE_unsigned + +entry: + %nose.trunc = trunc i64 %nose to i32 + %nose.shift = lshr i64 %nose, 32 + %nose.trunc.2 = trunc i64 %nose.shift to i32 + %add = add nsw i32 %more, 1 + ret i32 %add +} + +!llvm.module.flags = !{!0, !1} +!llvm.ident = !{!2} + +!0 = !{i32 1, !"wchar_size", i32 2} +!1 = !{i32 7, !"PIC Level", i32 2} +!2 = !{!"clang version 9.0.0 "} + +; CHECK: [[V1]] = !DILocalVariable( +; CHECK: [[V2]] = !DILocalVariable( +; CHECK: [[V3]] = !DILocalVariable( Index: llvm/test/Transforms/EarlyCSE/debug-info-undef.ll =================================================================== --- llvm/test/Transforms/EarlyCSE/debug-info-undef.ll +++ llvm/test/Transforms/EarlyCSE/debug-info-undef.ll @@ -10,7 +10,7 @@ %0 = load i8, i8* @a, align 1, !dbg !19, !tbaa !20 %conv = sext i8 %0 to i16, !dbg !19 -; CHECK: call void @llvm.dbg.value(metadata i16 undef, metadata !17, metadata !DIExpression()), !dbg !18 +; CHECK: call void @llvm.dbg.value(metadata i8 %0, metadata !17, metadata !DIExpression(DW_OP_LLVM_convert, 8, DW_ATE_signed, DW_OP_LLVM_convert, 16, DW_ATE_signed, DW_OP_stack_value)), !dbg !18 ; CHECK-NEXT: call i32 (...) @optimize_me_not() call void @llvm.dbg.value(metadata i16 %conv, metadata !17, metadata !DIExpression()), !dbg !18 Index: llvm/test/Transforms/InstCombine/cast-mul-select.ll =================================================================== --- llvm/test/Transforms/InstCombine/cast-mul-select.ll +++ llvm/test/Transforms/InstCombine/cast-mul-select.ll @@ -13,6 +13,8 @@ ; we preserve the debug information in the resulting ; instruction. ; DBGINFO-LABEL: @mul( +; DBGINFO-NEXT: call void @llvm.dbg.value(metadata i32 %x +; DBGINFO-NEXT: call void @llvm.dbg.value(metadata i32 %y ; DBGINFO-NEXT: [[C:%.*]] = mul i32 {{.*}} ; DBGINFO-NEXT: [[D:%.*]] = and i32 {{.*}} ; DBGINFO-NEXT: call void @llvm.dbg.value(metadata i32 [[C]] Index: llvm/test/Transforms/InstCombine/unavailable-debug.ll =================================================================== --- llvm/test/Transforms/InstCombine/unavailable-debug.ll +++ llvm/test/Transforms/InstCombine/unavailable-debug.ll @@ -2,7 +2,7 @@ ; Make sure to update the debug value after dead code elimination. ; CHECK: %call = call signext i8 @b(i32 6), !dbg !39 -; CHECK-NEXT: call void @llvm.dbg.value(metadata i32 undef, metadata !30, metadata !DIExpression()), !dbg !38 +; CHECK-NEXT: call void @llvm.dbg.value(metadata i8 %call, metadata !30, metadata !DIExpression(DW_OP_LLVM_convert, 8, DW_ATE_signed, DW_OP_LLVM_convert, 32, DW_ATE_signed, DW_OP_stack_value)), !dbg !38 @e = common local_unnamed_addr global i8 0, align 1, !dbg !0 @c = common local_unnamed_addr global i32 0, align 4, !dbg !6