[llvm] r312318 - Debug info for variables whose type is shrinked to bool

Mikael Holmén via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 7 00:36:48 PDT 2017


Hi Nikola and reviewers,

I think the debug info produced with this patch triggers a problem in llc.

Specifically, in DwarfDebug::beginModule() we do

         CU.getOrCreateGlobalVariableDIE(GV, sortGlobalExprs(GVMap[GV]));

It's the sorting done by sortGlobalExprs that doesn't seem to handle the 
case when we have mixed DW_OP_LLVM_fragment and DW_OP_deref very well.

Input to sort:
!DIExpression(DW_OP_LLVM_fragment, 0, 16)
!DIExpression(DW_OP_LLVM_fragment, 16, 16)
!DIExpression(DW_OP_LLVM_fragment, 32, 16)
!DIExpression(DW_OP_LLVM_fragment, 48, 16)
!DIExpression(DW_OP_deref, DW_OP_constu, 1, DW_OP_mul, DW_OP_constu, 0, 
DW_OP_plus, DW_OP_stack_value)
!DIExpression(DW_OP_LLVM_fragment, 80, 16)
!DIExpression(DW_OP_LLVM_fragment, 96, 16)
!DIExpression(DW_OP_LLVM_fragment, 112, 16)
!DIExpression(DW_OP_LLVM_fragment, 128, 16)
!DIExpression(DW_OP_LLVM_fragment, 144, 16)
!DIExpression(DW_OP_LLVM_fragment, 160, 16)
!DIExpression(DW_OP_LLVM_fragment, 176, 16)
!DIExpression(DW_OP_LLVM_fragment, 192, 16)
!DIExpression(DW_OP_LLVM_fragment, 208, 16)
!DIExpression(DW_OP_LLVM_fragment, 224, 16)
!DIExpression(DW_OP_deref, DW_OP_constu, 1, DW_OP_mul, DW_OP_constu, 0, 
DW_OP_plus, DW_OP_stack_value)
!DIExpression(DW_OP_LLVM_fragment, 256, 16)

Output from sort:
!DIExpression(DW_OP_LLVM_fragment, 0, 16)
!DIExpression(DW_OP_LLVM_fragment, 16, 16)
!DIExpression(DW_OP_LLVM_fragment, 32, 16)
!DIExpression(DW_OP_LLVM_fragment, 48, 16)
!DIExpression(DW_OP_LLVM_fragment, 128, 16)
!DIExpression(DW_OP_deref, DW_OP_constu, 1, DW_OP_mul, DW_OP_constu, 0, 
DW_OP_plus, DW_OP_stack_value)
!DIExpression(DW_OP_LLVM_fragment, 80, 16)
!DIExpression(DW_OP_LLVM_fragment, 96, 16)
!DIExpression(DW_OP_LLVM_fragment, 112, 16)
!DIExpression(DW_OP_LLVM_fragment, 144, 16)
!DIExpression(DW_OP_LLVM_fragment, 160, 16)
!DIExpression(DW_OP_LLVM_fragment, 176, 16)
!DIExpression(DW_OP_LLVM_fragment, 192, 16)
!DIExpression(DW_OP_LLVM_fragment, 208, 16)
!DIExpression(DW_OP_LLVM_fragment, 224, 16)
!DIExpression(DW_OP_deref, DW_OP_constu, 1, DW_OP_mul, DW_OP_constu, 0, 
DW_OP_plus, DW_OP_stack_value)
!DIExpression(DW_OP_LLVM_fragment, 256, 16)

The above "sorting" then causes an assert to blow in 
DwarfExpression::addFragmentOffset since that function seems to assume 
that we handle fragments in strictly growing offset order.

The sortGlobalExprs looks like

/// Sort and unique GVEs by comparing their fragment offset.
static SmallVectorImpl<DwarfCompileUnit::GlobalExpr> &
sortGlobalExprs(SmallVectorImpl<DwarfCompileUnit::GlobalExpr> &GVEs) {
   std::sort(GVEs.begin(), GVEs.end(),
             [](DwarfCompileUnit::GlobalExpr A, 
DwarfCompileUnit::GlobalExpr B) {
               if (A.Expr != B.Expr && A.Expr && B.Expr) {
                 auto FragmentA = A.Expr->getFragmentInfo();
                 auto FragmentB = B.Expr->getFragmentInfo();
                 if (FragmentA && FragmentB)
                   return FragmentA->OffsetInBits < FragmentB->OffsetInBits;
               }
               return false;
             });
   GVEs.erase(std::unique(GVEs.begin(), GVEs.end(),
                          [](DwarfCompileUnit::GlobalExpr A,
                             DwarfCompileUnit::GlobalExpr B) {
                            return A.Expr == B.Expr;
                          }),
              GVEs.end());
   return GVEs;
}

if I add

                 if (FragmentA)
                   return true;

after the check

                 if (FragmentA && FragmentB)
                   return FragmentA->OffsetInBits <

then it gets nicely sorted.

But maybe we need to be even more careful if we want to make sure the 
fragments are all properly sorted when there are all kinds of things in 
the input, and we should change the sorting to:
   // Sort all expressions containing fragment offsets (relative to each 
other),
   // and put all other expressions in random order (relative to each 
other) but
   // after the fragment expressions.
   std::sort(GVEs.begin(), GVEs.end(),
             [](DwarfCompileUnit::GlobalExpr A, 
DwarfCompileUnit::GlobalExpr B) {
               auto FragmentA = A.Expr ? A.Expr->getFragmentInfo() : None;
               auto FragmentB = B.Expr ? B.Expr->getFragmentInfo() : None;
               if (FragmentA && FragmentB)
                 return FragmentA->OffsetInBits < FragmentB->OffsetInBits;
               if (FragmentA)
                 return true;
               return false;
             });

so we ensure a proper sorting also when there are GlobalExprs with no Expr?

Also note that the attempt to remove duplicates in sortGlobalExprs will 
not remove all duplicates! Since std::unique only removes _consecutive_ 
equal elements, and the aobve sorting really only sorts the fragments, 
it might leave duplicate non-fragment expressions. I've no idea if this 
is a problem though.

I see the above problems with

llc -o - sort.ll

where sort.ll is a heavily reduced ll file originally produced using 
r312318. llc end stops with

llc: ../lib/CodeGen/AsmPrinter/DwarfExpression.cpp:405: void 
llvm::DwarfExpression::addFragmentOffset(const llvm::DIExpression *): 
Assertion `FragmentOffset >= OffsetInBits && "overlapping or duplicate 
fragments"' failed.

Also note that if I use another compiler to compile llc (e.g. gcc 
compared to clang) the problem assert doesn't show up. I suppose this is 
due to luck, and has to do with the order in which std::sort compares 
the objects in the input.

Regards,
Mikael

On 09/01/2017 12:05 PM, Strahinja Petrovic via llvm-commits wrote:
> Author: spetrovic
> Date: Fri Sep  1 03:05:27 2017
> New Revision: 312318
> 
> URL: http://llvm.org/viewvc/llvm-project?rev=312318&view=rev
> Log:
> Debug info for variables whose type is shrinked to bool
> 
> This patch provides such debug information for integer
> variables whose type is shrinked to bool by providing
> dwarf expression which returns either constant initial
> value or other value.
> 
> Patch by Nikola Prica.
> 
> Differential Revision: https://reviews.llvm.org/D35994
> 
> Modified:
>      llvm/trunk/lib/CodeGen/AsmPrinter/DwarfExpression.cpp
>      llvm/trunk/lib/IR/DebugInfoMetadata.cpp
>      llvm/trunk/lib/Transforms/IPO/GlobalOpt.cpp
> 
> Modified: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfExpression.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/DwarfExpression.cpp?rev=312318&r1=312317&r2=312318&view=diff
> ==============================================================================
> --- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfExpression.cpp (original)
> +++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfExpression.cpp Fri Sep  1 03:05:27 2017
> @@ -338,6 +338,7 @@ void DwarfExpression::addExpression(DIEx
>         break;
>       case dwarf::DW_OP_plus:
>       case dwarf::DW_OP_minus:
> +    case dwarf::DW_OP_mul:
>         emitOp(Op->getOp());
>         break;
>       case dwarf::DW_OP_deref:
> 
> Modified: llvm/trunk/lib/IR/DebugInfoMetadata.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/DebugInfoMetadata.cpp?rev=312318&r1=312317&r2=312318&view=diff
> ==============================================================================
> --- llvm/trunk/lib/IR/DebugInfoMetadata.cpp (original)
> +++ llvm/trunk/lib/IR/DebugInfoMetadata.cpp Fri Sep  1 03:05:27 2017
> @@ -643,6 +643,7 @@ bool DIExpression::isValid() const {
>       case dwarf::DW_OP_plus_uconst:
>       case dwarf::DW_OP_plus:
>       case dwarf::DW_OP_minus:
> +    case dwarf::DW_OP_mul:
>       case dwarf::DW_OP_deref:
>       case dwarf::DW_OP_xderef:
>         break;
> 
> Modified: llvm/trunk/lib/Transforms/IPO/GlobalOpt.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/GlobalOpt.cpp?rev=312318&r1=312317&r2=312318&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Transforms/IPO/GlobalOpt.cpp (original)
> +++ llvm/trunk/lib/Transforms/IPO/GlobalOpt.cpp Fri Sep  1 03:05:27 2017
> @@ -36,6 +36,7 @@
>   #include "llvm/IR/Module.h"
>   #include "llvm/IR/Operator.h"
>   #include "llvm/IR/ValueHandle.h"
> +#include "llvm/IR/DebugInfoMetadata.h"
>   #include "llvm/Pass.h"
>   #include "llvm/Support/Debug.h"
>   #include "llvm/Support/ErrorHandling.h"
> @@ -1603,12 +1604,47 @@ static bool TryToShrinkGlobalToBoolean(G
>     assert(InitVal->getType() != Type::getInt1Ty(GV->getContext()) &&
>            "No reason to shrink to bool!");
>   
> +  SmallVector<DIGlobalVariableExpression *, 1> GVs;
> +  GV->getDebugInfo(GVs);
> +
>     // If initialized to zero and storing one into the global, we can use a cast
>     // instead of a select to synthesize the desired value.
>     bool IsOneZero = false;
> -  if (ConstantInt *CI = dyn_cast<ConstantInt>(OtherVal))
> +  if (ConstantInt *CI = dyn_cast<ConstantInt>(OtherVal)){
>       IsOneZero = InitVal->isNullValue() && CI->isOne();
>   
> +    ConstantInt *CIInit = dyn_cast<ConstantInt>(GV->getInitializer());
> +    uint64_t ValInit = CIInit->getZExtValue();
> +    uint64_t ValOther = CI->getZExtValue();
> +    uint64_t ValMinus = ValOther - ValInit;
> +
> +    for(auto *GVe : GVs){
> +      DIGlobalVariable *DGV = GVe->getVariable();
> +      DIExpression *E = GVe->getExpression();
> +
> +      // val * (ValOther - ValInit) + ValInit:
> +      // DW_OP_deref DW_OP_constu <ValMinus>
> +      // DW_OP_mul DW_OP_constu <ValInit> DW_OP_plus DW_OP_stack_value
> +      E = DIExpression::get(NewGV->getContext(),
> +                           {dwarf::DW_OP_deref,
> +                            dwarf::DW_OP_constu,
> +                            ValMinus,
> +                            dwarf::DW_OP_mul,
> +                            dwarf::DW_OP_constu,
> +                            ValInit,
> +                            dwarf::DW_OP_plus,
> +                            dwarf::DW_OP_stack_value});
> +      DIGlobalVariableExpression *DGVE =
> +        DIGlobalVariableExpression::get(NewGV->getContext(), DGV, E);
> +      NewGV->addDebugInfo(DGVE);
> +    }
> +  } else {
> +    // FIXME: This will only emit address for debugger on which will
> +    // be written only 0 or 1.
> +    for(auto *GV : GVs)
> +      NewGV->addDebugInfo(GV);
> +  }
> +
>     while (!GV->use_empty()) {
>       Instruction *UI = cast<Instruction>(GV->user_back());
>       if (StoreInst *SI = dyn_cast<StoreInst>(UI)) {
> 
> 
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
> 
-------------- next part --------------

@f1.a.0 = external unnamed_addr global i16, align 1, !dbg !0
@f1.a.1 = external unnamed_addr global i16, align 1, !dbg !30
@f1.a.2 = external unnamed_addr global i16, align 1, !dbg !31
@f1.a.3 = external unnamed_addr global i16, align 1, !dbg !32
@f1.a.4 = external unnamed_addr global i1, align 1, !dbg !33
@f1.a.5 = external unnamed_addr global i16, align 1, !dbg !34
@f1.a.6 = external unnamed_addr global i16, align 1, !dbg !35
@f1.a.7 = external unnamed_addr global i16, align 1, !dbg !36
@f1.a.8 = external unnamed_addr global i16, align 1, !dbg !37
@f1.a.9 = external unnamed_addr global i16, align 1, !dbg !38
@f1.a.10 = external unnamed_addr global i16, align 1, !dbg !39
@f1.a.11 = external unnamed_addr global i16, align 1, !dbg !40
@f1.a.12 = external unnamed_addr global i16, align 1, !dbg !41
@f1.a.13 = external unnamed_addr global i16, align 1, !dbg !42
@f1.a.14 = external unnamed_addr global i16, align 1, !dbg !43
@f1.a.15 = external unnamed_addr global i1, align 1, !dbg !49
@f1.a.16 = external unnamed_addr global i16, align 1, !dbg !44

!llvm.dbg.cu = !{!6}
!llvm.module.flags = !{!45, !46, !47}
!llvm.ident = !{!48}

!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression(DW_OP_LLVM_fragment, 0, 16))
!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 26, type: !10, isLocal: true, isDefinition: true)
!2 = distinct !DISubprogram(name: "f1", scope: !3, file: !3, line: 24, type: !4, isLocal: false, isDefinition: true, scopeLine: 25, flags: DIFlagPrototyped, isOptimized: true, unit: !6, variables: !7)
!3 = !DIFile(filename: "foo.c", directory: "/bar")
!4 = !DISubroutineType(types: !5)
!5 = !{null}
!6 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "my compiler", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !7, globals: !8)
!7 = !{}
!8 = !{!9}
!9 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
!10 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !3, line: 1, size: 272, elements: !11)
!11 = !{!12, !14, !15, !16, !17, !18, !19, !20, !21, !22, !23, !24, !25, !26, !27, !28, !29}
!12 = !DIDerivedType(tag: DW_TAG_member, name: "i01", scope: !10, file: !3, line: 4, baseType: !13, size: 8, offset: 6, flags: DIFlagBitField, extraData: i64 0)
!13 = !DIBasicType(name: "int", size: 16, encoding: DW_ATE_signed)
!14 = !DIDerivedType(tag: DW_TAG_member, name: "i02", scope: !10, file: !3, line: 5, baseType: !13, size: 8, offset: 16, flags: DIFlagBitField, extraData: i64 16)
!15 = !DIDerivedType(tag: DW_TAG_member, name: "i03", scope: !10, file: !3, line: 6, baseType: !13, size: 15, offset: 32, flags: DIFlagBitField, extraData: i64 32)
!16 = !DIDerivedType(tag: DW_TAG_member, name: "i04", scope: !10, file: !3, line: 7, baseType: !13, size: 4, offset: 48, flags: DIFlagBitField, extraData: i64 48)
!17 = !DIDerivedType(tag: DW_TAG_member, name: "i05", scope: !10, file: !3, line: 8, baseType: !13, size: 16, offset: 64)
!18 = !DIDerivedType(tag: DW_TAG_member, name: "i06", scope: !10, file: !3, line: 9, baseType: !13, size: 13, offset: 80, flags: DIFlagBitField, extraData: i64 80)
!19 = !DIDerivedType(tag: DW_TAG_member, name: "i07", scope: !10, file: !3, line: 10, baseType: !13, size: 4, offset: 96, flags: DIFlagBitField, extraData: i64 96)
!20 = !DIDerivedType(tag: DW_TAG_member, name: "i08", scope: !10, file: !3, line: 11, baseType: !13, size: 13, offset: 112, flags: DIFlagBitField, extraData: i64 112)
!21 = !DIDerivedType(tag: DW_TAG_member, name: "i09", scope: !10, file: !3, line: 12, baseType: !13, size: 10, offset: 128, flags: DIFlagBitField, extraData: i64 128)
!22 = !DIDerivedType(tag: DW_TAG_member, name: "i10", scope: !10, file: !3, line: 13, baseType: !13, size: 15, offset: 144, flags: DIFlagBitField, extraData: i64 144)
!23 = !DIDerivedType(tag: DW_TAG_member, name: "i11", scope: !10, file: !3, line: 15, baseType: !13, size: 5, offset: 168, flags: DIFlagBitField, extraData: i64 160)
!24 = !DIDerivedType(tag: DW_TAG_member, name: "i12", scope: !10, file: !3, line: 16, baseType: !13, size: 6, offset: 176, flags: DIFlagBitField, extraData: i64 176)
!25 = !DIDerivedType(tag: DW_TAG_member, name: "i13", scope: !10, file: !3, line: 17, baseType: !13, size: 16, offset: 192)
!26 = !DIDerivedType(tag: DW_TAG_member, name: "i14", scope: !10, file: !3, line: 18, baseType: !13, size: 5, offset: 208, flags: DIFlagBitField, extraData: i64 208)
!27 = !DIDerivedType(tag: DW_TAG_member, name: "i15", scope: !10, file: !3, line: 19, baseType: !13, size: 14, offset: 224, flags: DIFlagBitField, extraData: i64 224)
!28 = !DIDerivedType(tag: DW_TAG_member, name: "i16", scope: !10, file: !3, line: 20, baseType: !13, size: 16, offset: 240)
!29 = !DIDerivedType(tag: DW_TAG_member, name: "i17", scope: !10, file: !3, line: 21, baseType: !13, size: 4, offset: 256, flags: DIFlagBitField, extraData: i64 256)
!30 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression(DW_OP_LLVM_fragment, 16, 16))
!31 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression(DW_OP_LLVM_fragment, 32, 16))
!32 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression(DW_OP_LLVM_fragment, 48, 16))
!33 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression(DW_OP_deref, DW_OP_constu, 1, DW_OP_mul, DW_OP_constu, 0, DW_OP_plus, DW_OP_stack_value))
!34 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression(DW_OP_LLVM_fragment, 80, 16))
!35 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression(DW_OP_LLVM_fragment, 96, 16))
!36 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression(DW_OP_LLVM_fragment, 112, 16))
!37 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression(DW_OP_LLVM_fragment, 128, 16))
!38 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression(DW_OP_LLVM_fragment, 144, 16))
!39 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression(DW_OP_LLVM_fragment, 160, 16))
!40 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression(DW_OP_LLVM_fragment, 176, 16))
!41 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression(DW_OP_LLVM_fragment, 192, 16))
!42 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression(DW_OP_LLVM_fragment, 208, 16))
!43 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression(DW_OP_LLVM_fragment, 224, 16))
!44 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression(DW_OP_LLVM_fragment, 256, 16))
!49 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression(DW_OP_deref, DW_OP_constu, 1, DW_OP_mul, DW_OP_constu, 0, DW_OP_plus, DW_OP_stack_value))

!45 = !{i32 2, !"Dwarf Version", i32 4}
!46 = !{i32 2, !"Debug Info Version", i32 3}
!47 = !{i32 1, !"wchar_size", i32 1}
!48 = !{!"clang version 6.0.0"}


More information about the llvm-commits mailing list