diff --git a/llvm/lib/Target/BPF/BTFDebug.h b/llvm/lib/Target/BPF/BTFDebug.h --- a/llvm/lib/Target/BPF/BTFDebug.h +++ b/llvm/lib/Target/BPF/BTFDebug.h @@ -255,6 +255,7 @@ std::map>> FixupDerivedTypes; std::setProtoFunctions; + uint32_t ByteTypeId; /// Add types to TypeEntries. /// @{ @@ -262,6 +263,8 @@ uint32_t addType(std::unique_ptr TypeEntry, const DIType *Ty); /// Add types to TypeEntries only and return type id. uint32_t addType(std::unique_ptr TypeEntry); + /// Add unknown types to TypeEntries and DIToIdMap. + uint32_t addUnknownType(const DIType *Ty); /// @} /// IR type visiting functions. @@ -269,19 +272,19 @@ void visitTypeEntry(const DIType *Ty); void visitTypeEntry(const DIType *Ty, uint32_t &TypeId, bool CheckPointer, bool SeenPointer); - void visitBasicType(const DIBasicType *BTy, uint32_t &TypeId); - void visitSubroutineType( + bool visitBasicType(const DIBasicType *BTy, uint32_t &TypeId); + bool visitSubroutineType( const DISubroutineType *STy, bool ForSubprog, const std::unordered_map &FuncArgNames, uint32_t &TypeId); - void visitFwdDeclType(const DICompositeType *CTy, bool IsUnion, + bool visitFwdDeclType(const DICompositeType *CTy, bool IsUnion, uint32_t &TypeId); - void visitCompositeType(const DICompositeType *CTy, uint32_t &TypeId); - void visitStructType(const DICompositeType *STy, bool IsStruct, + bool visitCompositeType(const DICompositeType *CTy, uint32_t &TypeId); + bool visitStructType(const DICompositeType *STy, bool IsStruct, uint32_t &TypeId); - void visitArrayType(const DICompositeType *ATy, uint32_t &TypeId); - void visitEnumType(const DICompositeType *ETy, uint32_t &TypeId); - void visitDerivedType(const DIDerivedType *DTy, uint32_t &TypeId, + bool visitArrayType(const DICompositeType *ATy, uint32_t &TypeId); + bool visitEnumType(const DICompositeType *ETy, uint32_t &TypeId); + bool visitDerivedType(const DIDerivedType *DTy, uint32_t &TypeId, bool CheckPointer, bool SeenPointer); void visitMapDefType(const DIType *Ty, uint32_t &TypeId); /// @} @@ -319,6 +322,9 @@ /// Emit the .BTF.ext section. void emitBTFExtSection(); + /// Generate ArrayIndexTypeId unless it's already generated. + void generateArrayIndexTypeId(); + protected: /// Gather pre-function debug information. void beginFunctionImpl(const MachineFunction *MF) override; diff --git a/llvm/lib/Target/BPF/BTFDebug.cpp b/llvm/lib/Target/BPF/BTFDebug.cpp --- a/llvm/lib/Target/BPF/BTFDebug.cpp +++ b/llvm/lib/Target/BPF/BTFDebug.cpp @@ -387,7 +387,7 @@ BTFDebug::BTFDebug(AsmPrinter *AP) : DebugHandlerBase(AP), OS(*Asm->OutStreamer), SkipInstruction(false), LineInfoGenerated(false), SecNameOff(0), ArrayIndexTypeId(0), - MapDefNotCollected(true) { + MapDefNotCollected(true), ByteTypeId(0) { addString("\0"); } @@ -407,31 +407,45 @@ return Id; } -void BTFDebug::visitBasicType(const DIBasicType *BTy, uint32_t &TypeId) { +uint32_t BTFDebug::addUnknownType(const DIType *Ty) { + uint64_t SizeInBits = Ty->getSizeInBits(); + assert(SizeInBits % 8 == 0); + if (ByteTypeId == 0) { + auto ByteTypeEntry = std::make_unique( + dwarf::DW_ATE_unsigned_char, 8, 0, "__BYTE_TYPE__"); + ByteTypeId = addType(std::move(ByteTypeEntry)); + } + auto TypeEntry = std::make_unique(ByteTypeId, SizeInBits / 8); + generateArrayIndexTypeId(); + return addType(std::move(TypeEntry), Ty); +} + +bool BTFDebug::visitBasicType(const DIBasicType *BTy, uint32_t &TypeId) { // Only int types are supported in BTF. uint32_t Encoding = BTy->getEncoding(); if (Encoding != dwarf::DW_ATE_boolean && Encoding != dwarf::DW_ATE_signed && Encoding != dwarf::DW_ATE_signed_char && Encoding != dwarf::DW_ATE_unsigned && Encoding != dwarf::DW_ATE_unsigned_char) - return; + return false; // Create a BTF type instance for this DIBasicType and put it into // DIToIdMap for cross-type reference check. auto TypeEntry = std::make_unique( Encoding, BTy->getSizeInBits(), BTy->getOffsetInBits(), BTy->getName()); TypeId = addType(std::move(TypeEntry), BTy); + return true; } /// Handle subprogram or subroutine types. -void BTFDebug::visitSubroutineType( +bool BTFDebug::visitSubroutineType( const DISubroutineType *STy, bool ForSubprog, const std::unordered_map &FuncArgNames, uint32_t &TypeId) { DITypeRefArray Elements = STy->getTypeArray(); uint32_t VLen = Elements.size() - 1; if (VLen > BTF::MAX_VLEN) - return; + return false; // Subprogram has a valid non-zero-length name, and the pointee of // a function pointer has an empty name. The subprogram type will @@ -447,15 +461,16 @@ for (const auto Element : Elements) { visitTypeEntry(Element); } + return true; } /// Handle structure/union types. -void BTFDebug::visitStructType(const DICompositeType *CTy, bool IsStruct, +bool BTFDebug::visitStructType(const DICompositeType *CTy, bool IsStruct, uint32_t &TypeId) { const DINodeArray Elements = CTy->getElements(); uint32_t VLen = Elements.size(); if (VLen > BTF::MAX_VLEN) - return; + return false; // Check whether we have any bitfield members or not bool HasBitField = false; @@ -475,9 +490,10 @@ // Visit all struct members. for (const auto *Element : Elements) visitTypeEntry(cast(Element)); + return true; } -void BTFDebug::visitArrayType(const DICompositeType *CTy, uint32_t &TypeId) { +bool BTFDebug::visitArrayType(const DICompositeType *CTy, uint32_t &TypeId) { // Visit array element type. uint32_t ElemTypeId; const DIType *ElemType = CTy->getBaseType(); @@ -509,49 +525,58 @@ // The IR does not have a type for array index while BTF wants one. // So create an array index type if there is none. - if (!ArrayIndexTypeId) { - auto TypeEntry = std::make_unique(dwarf::DW_ATE_unsigned, 32, - 0, "__ARRAY_SIZE_TYPE__"); - ArrayIndexTypeId = addType(std::move(TypeEntry)); - } + generateArrayIndexTypeId(); + + return true; } -void BTFDebug::visitEnumType(const DICompositeType *CTy, uint32_t &TypeId) { +void BTFDebug::generateArrayIndexTypeId() { + if (ArrayIndexTypeId) + return; + auto TypeEntry = std::make_unique(dwarf::DW_ATE_unsigned, 32, 0, + "__ARRAY_SIZE_TYPE__"); + ArrayIndexTypeId = addType(std::move(TypeEntry)); +} + +bool BTFDebug::visitEnumType(const DICompositeType *CTy, uint32_t &TypeId) { DINodeArray Elements = CTy->getElements(); uint32_t VLen = Elements.size(); if (VLen > BTF::MAX_VLEN) - return; + return false; auto TypeEntry = std::make_unique(CTy, VLen); TypeId = addType(std::move(TypeEntry), CTy); // No need to visit base type as BTF does not encode it. + return true; } /// Handle structure/union forward declarations. -void BTFDebug::visitFwdDeclType(const DICompositeType *CTy, bool IsUnion, +bool BTFDebug::visitFwdDeclType(const DICompositeType *CTy, bool IsUnion, uint32_t &TypeId) { auto TypeEntry = std::make_unique(CTy->getName(), IsUnion); TypeId = addType(std::move(TypeEntry), CTy); + return true; } /// Handle structure, union, array and enumeration types. -void BTFDebug::visitCompositeType(const DICompositeType *CTy, +bool BTFDebug::visitCompositeType(const DICompositeType *CTy, uint32_t &TypeId) { auto Tag = CTy->getTag(); if (Tag == dwarf::DW_TAG_structure_type || Tag == dwarf::DW_TAG_union_type) { // Handle forward declaration differently as it does not have members. if (CTy->isForwardDecl()) - visitFwdDeclType(CTy, Tag == dwarf::DW_TAG_union_type, TypeId); + return visitFwdDeclType(CTy, Tag == dwarf::DW_TAG_union_type, TypeId); else - visitStructType(CTy, Tag == dwarf::DW_TAG_structure_type, TypeId); + return visitStructType(CTy, Tag == dwarf::DW_TAG_structure_type, TypeId); } else if (Tag == dwarf::DW_TAG_array_type) - visitArrayType(CTy, TypeId); + return visitArrayType(CTy, TypeId); else if (Tag == dwarf::DW_TAG_enumeration_type) - visitEnumType(CTy, TypeId); + return visitEnumType(CTy, TypeId); + return false; } /// Handle pointer, typedef, const, volatile, restrict and member types. -void BTFDebug::visitDerivedType(const DIDerivedType *DTy, uint32_t &TypeId, +bool BTFDebug::visitDerivedType(const DIDerivedType *DTy, uint32_t &TypeId, bool CheckPointer, bool SeenPointer) { unsigned Tag = DTy->getTag(); @@ -577,7 +602,7 @@ Fixup.first = CTag == dwarf::DW_TAG_union_type; Fixup.second.push_back(TypeEntry.get()); TypeId = addType(std::move(TypeEntry), DTy); - return; + return true; } } } @@ -589,7 +614,7 @@ auto TypeEntry = std::make_unique(DTy, Tag, false); TypeId = addType(std::move(TypeEntry), DTy); } else if (Tag != dwarf::DW_TAG_member) { - return; + return false; } // Visit base type of pointer, typedef, const, volatile, restrict or @@ -599,6 +624,7 @@ visitTypeEntry(DTy->getBaseType(), TempTypeId, true, false); else visitTypeEntry(DTy->getBaseType(), TempTypeId, CheckPointer, SeenPointer); + return true; } void BTFDebug::visitTypeEntry(const DIType *Ty, uint32_t &TypeId, @@ -640,17 +666,18 @@ return; } + bool IsKnown = false; if (const auto *BTy = dyn_cast(Ty)) - visitBasicType(BTy, TypeId); + IsKnown = visitBasicType(BTy, TypeId); else if (const auto *STy = dyn_cast(Ty)) - visitSubroutineType(STy, false, std::unordered_map(), - TypeId); + IsKnown = visitSubroutineType( + STy, false, std::unordered_map(), TypeId); else if (const auto *CTy = dyn_cast(Ty)) - visitCompositeType(CTy, TypeId); + IsKnown = visitCompositeType(CTy, TypeId); else if (const auto *DTy = dyn_cast(Ty)) - visitDerivedType(DTy, TypeId, CheckPointer, SeenPointer); - else - llvm_unreachable("Unknown DIType"); + IsKnown = visitDerivedType(DTy, TypeId, CheckPointer, SeenPointer); + if (!IsKnown) + TypeId = addUnknownType(Ty); } void BTFDebug::visitTypeEntry(const DIType *Ty) { diff --git a/llvm/test/CodeGen/BPF/BTF/double.ll b/llvm/test/CodeGen/BPF/BTF/double.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/BPF/BTF/double.ll @@ -0,0 +1,73 @@ +; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s +; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; double a; +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +@a = dso_local local_unnamed_addr global double 0.000000e+00, align 8, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!7, !8, !9} +!llvm.ident = !{!10} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 96 +; CHECK-NEXT: .long 96 +; CHECK-NEXT: .long 42 +; [1] __BYTE_TYPE__, int, size=1 byte, unsigned, 8 bits +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 1) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 8 # 0x8 +; [2] __ARRAY_SIZE_TYPE__, int, size=4 bytes, unsigned, 32 bits +; CHECK-NEXT: .long 15 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 32 # 0x20 +; [3] array, type=__BYTE_TYPE__, index_type=__ARRAY_SIZE_TYPE__, nelems=8 +; CHECK-NEXT: .long 0 # BTF_KIND_ARRAY(id = 3) +; CHECK-NEXT: .long 50331648 # 0x3000000 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 8 +; [4] a, var, type=__BYTE_TYPE__[8], global +; CHECK-NEXT: .long 35 # BTF_KIND_VAR(id = 4) +; CHECK-NEXT: .long 234881024 # 0xe000000 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 1 +; [5] .bss, datasec, 1 var, {a, offset=&a, size=8 bytes} +; CHECK-NEXT: .long 37 # BTF_KIND_DATASEC(id = 5) +; CHECK-NEXT: .long 251658241 # 0xf000001 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long a +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "__BYTE_TYPE__" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "__ARRAY_SIZE_TYPE__" # string offset=15 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 97 # string offset=35 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".bss" # string offset=37 +; CHECK-NEXT: .byte 0 + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 11.0.0 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, splitDebugInlining: false, nameTableKind: None) +!3 = !DIFile(filename: "t.c", directory: "/home/yhs/tmp") +!4 = !{} +!5 = !{!0} +!6 = !DIBasicType(name: "double", size: 64, encoding: DW_ATE_float) +!7 = !{i32 7, !"Dwarf Version", i32 4} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{i32 1, !"wchar_size", i32 4} +!10 = !{!"clang version 11.0.0 "} diff --git a/llvm/test/CodeGen/BPF/BTF/float.ll b/llvm/test/CodeGen/BPF/BTF/float.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/BPF/BTF/float.ll @@ -0,0 +1,73 @@ +; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s +; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; float a; +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +@a = dso_local local_unnamed_addr global float 0.000000e+00, align 4, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!7, !8, !9} +!llvm.ident = !{!10} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 96 +; CHECK-NEXT: .long 96 +; CHECK-NEXT: .long 42 +; [1] __BYTE_TYPE__, int, size=1 byte, unsigned, 8 bits +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 1) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 8 # 0x8 +; [2] __ARRAY_SIZE_TYPE__, int, size=4 bytes, unsigned, 32 bits +; CHECK-NEXT: .long 15 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 32 # 0x20 +; [3] array, type=__BYTE_TYPE__, index_type=__ARRAY_SIZE_TYPE__, nelems=4 +; CHECK-NEXT: .long 0 # BTF_KIND_ARRAY(id = 3) +; CHECK-NEXT: .long 50331648 # 0x3000000 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 4 +; [4] a, var, type=__BYTE_TYPE__[4], global +; CHECK-NEXT: .long 35 # BTF_KIND_VAR(id = 4) +; CHECK-NEXT: .long 234881024 # 0xe000000 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 1 +; [5] .bss, datasec, 1 var, {a, offset=&a, size=4 bytes} +; CHECK-NEXT: .long 37 # BTF_KIND_DATASEC(id = 5) +; CHECK-NEXT: .long 251658241 # 0xf000001 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long a +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "__BYTE_TYPE__" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "__ARRAY_SIZE_TYPE__" # string offset=15 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 97 # string offset=35 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".bss" # string offset=37 +; CHECK-NEXT: .byte 0 + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 11.0.0 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, splitDebugInlining: false, nameTableKind: None) +!3 = !DIFile(filename: "t.c", directory: "/home/yhs/tmp") +!4 = !{} +!5 = !{!0} +!6 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float) +!7 = !{i32 7, !"Dwarf Version", i32 4} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{i32 1, !"wchar_size", i32 4} +!10 = !{!"clang version 11.0.0 "}