[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