yonghong-song created this revision. yonghong-song added reviewers: aprantl, dblaikie, RKSimon, ast. yonghong-song added a project: debug-info. Herald added subscribers: llvm-commits, cfe-commits, ormris, hiraditya. Herald added projects: clang, LLVM.
extern variable usage in BPF is different from traditional pure user space application. Recent discussion in linux bpf mailing list has two use cases where debug info types are required to use extern variables: - extern types are required to have a suitable interface in libbpf (bpf loader) to provide kernel config parameters to bpf programs. https://lore.kernel.org/bpf/CAEf4BzYCNo5GeVGMhp3fhysQ=_axAf=23ptwazs-yayafmx...@mail.gmail.com/T/#t - extern types are required so kernel bpf verifier can verify program which uses external functions more precisely. This will make later link with actual external function no need to reverify. https://lore.kernel.org/bpf/87eez4odqp....@toke.dk/T/#m8d5c3e87ffe7f2764e02d722cb0d8cbc136880ed This patch added clang support to emit debuginfo for extern variables, and bpf support to consume such info into BTF, which can then be used by bpf loader. A few more things need to do: - currently, I added clang EmitGlobalDeclVariable() to emit debuginfo for extern variables. It might be possible to reuse existing EmitGlobalVariable(). Need double check. - BPF is C only, so I only tested C. I am not sure whether adding other language support is necessary at this point. - add clang test cases and a few more bpf backend tests. But some early feedback will be great! Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D70625 Files: clang/include/clang/AST/ASTConsumer.h clang/include/clang/Basic/TargetInfo.h clang/include/clang/Sema/Sema.h clang/lib/Basic/Targets/BPF.h clang/lib/CodeGen/CGDebugInfo.cpp clang/lib/CodeGen/CGDebugInfo.h clang/lib/CodeGen/CodeGenAction.cpp clang/lib/CodeGen/CodeGenModule.cpp clang/lib/CodeGen/CodeGenModule.h clang/lib/CodeGen/ModuleBuilder.cpp clang/lib/Sema/Sema.cpp clang/lib/Sema/SemaDecl.cpp llvm/include/llvm/IR/DIBuilder.h llvm/lib/IR/DIBuilder.cpp llvm/lib/IR/DebugInfo.cpp llvm/lib/Target/BPF/BTF.h llvm/lib/Target/BPF/BTFDebug.cpp llvm/lib/Target/BPF/BTFDebug.h llvm/test/CodeGen/BPF/BTF/extern-var-func.ll llvm/test/CodeGen/BPF/BTF/extern-var-section.ll llvm/test/CodeGen/BPF/BTF/extern-var-struct.ll llvm/unittests/Transforms/Utils/CloningTest.cpp
Index: llvm/unittests/Transforms/Utils/CloningTest.cpp =================================================================== --- llvm/unittests/Transforms/Utils/CloningTest.cpp +++ llvm/unittests/Transforms/Utils/CloningTest.cpp @@ -764,7 +764,7 @@ DBuilder.createGlobalVariableExpression( Subprogram, "unattached", "unattached", File, 1, - DBuilder.createNullPtrType(), false, Expr); + DBuilder.createNullPtrType(), false, true, Expr); auto *Entry = BasicBlock::Create(C, "", F); IBuilder.SetInsertPoint(Entry); Index: llvm/test/CodeGen/BPF/BTF/extern-var-struct.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/BPF/BTF/extern-var-struct.ll @@ -0,0 +1,101 @@ +; 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: +; typedef struct t1 { int f1; } __t1; +; int test() { return global.f1; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm test.c + +%struct.t1 = type { i32 } + +@global = external dso_local local_unnamed_addr global %struct.t1, align 4, !dbg !0 + +; Function Attrs: norecurse nounwind readonly +define dso_local i32 @test() local_unnamed_addr #0 !dbg !15 { +entry: + %0 = load i32, i32* getelementptr inbounds (%struct.t1, %struct.t1* @global, i64 0, i32 0), align 4, !dbg !18, !tbaa !19 + ret i32 %0, !dbg !24 +} + +; 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 92 +; CHECK-NEXT: .long 92 +; CHECK-NEXT: .long 73 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1) +; CHECK-NEXT: .long 218103808 # 0xd000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 5 # BTF_KIND_FUNC(id = 3) +; CHECK-NEXT: .long 201326592 # 0xc000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 55 # BTF_KIND_TYPEDEF(id = 4) +; CHECK-NEXT: .long 134217728 # 0x8000000 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 60 # BTF_KIND_STRUCT(id = 5) +; CHECK-NEXT: .long 67108865 # 0x4000001 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 63 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 66 # BTF_KIND_VAR(id = 6) +; CHECK-NEXT: .long 234881024 # 0xe000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "int" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "test" # string offset=5 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".text" # string offset=10 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "/tmp/home/yhs/work/tests/extern/test.c" # string offset=16 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "__t1" # string offset=55 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "t1" # string offset=60 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "f1" # string offset=63 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "global" # string offset=66 +; CHECK-NEXT: .byte 0 + +attributes #0 = { norecurse nounwind readonly "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "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" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!11, !12, !13} +!llvm.ident = !{!14} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "global", scope: !2, file: !3, line: 2, type: !6, isLocal: false, isDefinition: false) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 2798d63180f4cc873bdaf689705fd4f9521ae89f)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/extern") +!4 = !{} +!5 = !{!0} +!6 = !DIDerivedType(tag: DW_TAG_typedef, name: "__t1", file: !3, line: 1, baseType: !7) +!7 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t1", file: !3, line: 1, size: 32, elements: !8) +!8 = !{!9} +!9 = !DIDerivedType(tag: DW_TAG_member, name: "f1", scope: !7, file: !3, line: 1, baseType: !10, size: 32) +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !{i32 2, !"Dwarf Version", i32 4} +!12 = !{i32 2, !"Debug Info Version", i32 3} +!13 = !{i32 1, !"wchar_size", i32 4} +!14 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 2798d63180f4cc873bdaf689705fd4f9521ae89f)"} +!15 = distinct !DISubprogram(name: "test", scope: !3, file: !3, line: 4, type: !16, scopeLine: 4, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !4) +!16 = !DISubroutineType(types: !17) +!17 = !{!10} +!18 = !DILocation(line: 4, column: 28, scope: !15) +!19 = !{!20, !21, i64 0} +!20 = !{!"t1", !21, i64 0} +!21 = !{!"int", !22, i64 0} +!22 = !{!"omnipotent char", !23, i64 0} +!23 = !{!"Simple C/C++ TBAA"} +!24 = !DILocation(line: 4, column: 14, scope: !15) Index: llvm/test/CodeGen/BPF/BTF/extern-var-section.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/BPF/BTF/extern-var-section.ll @@ -0,0 +1,123 @@ +; 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: +; extern int global_func(char c) __attribute__((section("abc"))); +; extern char ch __attribute__((section("abc"))); +; int test() { +; return global_func(0) + ch; +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm test.c + +@ch = external dso_local local_unnamed_addr global i8, section "abc", align 1, !dbg !0 + +; Function Attrs: nounwind +define dso_local i32 @test() local_unnamed_addr #0 !dbg !16 { +entry: + %call = tail call i32 @global_func(i8 signext 0) #2, !dbg !19 + %0 = load i8, i8* @ch, align 1, !dbg !20, !tbaa !21 + %conv = sext i8 %0 to i32, !dbg !20 + %add = add nsw i32 %call, %conv, !dbg !24 + ret i32 %add, !dbg !25 +} + +; 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 144 +; CHECK-NEXT: .long 144 +; CHECK-NEXT: .long 79 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1) +; CHECK-NEXT: .long 218103808 # 0xd000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 5 # BTF_KIND_FUNC(id = 3) +; CHECK-NEXT: .long 201326592 # 0xc000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 55 # BTF_KIND_INT(id = 4) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 16777224 # 0x1000008 +; CHECK-NEXT: .long 60 # BTF_KIND_VAR(id = 5) +; CHECK-NEXT: .long 234881024 # 0xe000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 6) +; CHECK-NEXT: .long 218103809 # 0xd000001 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 63 # BTF_KIND_VAR(id = 7) +; CHECK-NEXT: .long 234881024 # 0xe000000 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 75 # BTF_KIND_DATASEC(id = 8) +; CHECK-NEXT: .long 251658242 # 0xf000002 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long ch +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long global_func +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "int" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "test" # string offset=5 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".text" # string offset=10 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "/tmp/home/yhs/work/tests/extern/test.c" # string offset=16 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "char" # string offset=55 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "ch" # string offset=60 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "global_func" # string offset=63 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "abc" # string offset=75 +; CHECK-NEXT: .byte 0 + +declare !dbg !6 dso_local i32 @global_func(i8 signext) local_unnamed_addr #1 section "abc" + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "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" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind } + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!12, !13, !14} +!llvm.ident = !{!15} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "ch", scope: !2, file: !3, line: 2, type: !10, isLocal: false, isDefinition: false) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 0ad024346185b3f0b5167438e126568982b1168d)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, retainedTypes: !5, globals: !11, nameTableKind: None) +!3 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/extern") +!4 = !{} +!5 = !{!6} +!6 = !DISubprogram(name: "global_func", scope: !3, file: !3, line: 1, type: !7, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !4) +!7 = !DISubroutineType(types: !8) +!8 = !{!9, !10} +!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!10 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!11 = !{!0} +!12 = !{i32 2, !"Dwarf Version", i32 4} +!13 = !{i32 2, !"Debug Info Version", i32 3} +!14 = !{i32 1, !"wchar_size", i32 4} +!15 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 0ad024346185b3f0b5167438e126568982b1168d)"} +!16 = distinct !DISubprogram(name: "test", scope: !3, file: !3, line: 3, type: !17, scopeLine: 3, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !4) +!17 = !DISubroutineType(types: !18) +!18 = !{!9} +!19 = !DILocation(line: 4, column: 10, scope: !16) +!20 = !DILocation(line: 4, column: 27, scope: !16) +!21 = !{!22, !22, i64 0} +!22 = !{!"omnipotent char", !23, i64 0} +!23 = !{!"Simple C/C++ TBAA"} +!24 = !DILocation(line: 4, column: 25, scope: !16) +!25 = !DILocation(line: 4, column: 3, scope: !16) Index: llvm/test/CodeGen/BPF/BTF/extern-var-func.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/BPF/BTF/extern-var-func.ll @@ -0,0 +1,92 @@ +; 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: +; extern int global_func(char c); +; int test() { +; return global_func(0); +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm test.c + +; Function Attrs: nounwind +define dso_local i32 @test() local_unnamed_addr #0 !dbg !13 { +entry: + %call = tail call i32 @global_func(i8 signext 0) #2, !dbg !16 + ret i32 %call, !dbg !17 +} + +; 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 92 +; CHECK-NEXT: .long 92 +; CHECK-NEXT: .long 72 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1) +; CHECK-NEXT: .long 218103808 # 0xd000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 5 # BTF_KIND_FUNC(id = 3) +; CHECK-NEXT: .long 201326592 # 0xc000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 4) +; CHECK-NEXT: .long 218103809 # 0xd000001 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 55 # BTF_KIND_INT(id = 5) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 16777224 # 0x1000008 +; CHECK-NEXT: .long 60 # BTF_KIND_VAR(id = 6) +; CHECK-NEXT: .long 234881024 # 0xe000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "int" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "test" # string offset=5 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".text" # string offset=10 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "/tmp/home/yhs/work/tests/extern/test.c" # string offset=16 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "char" # string offset=55 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "global_func" # string offset=60 +; CHECK-NEXT: .byte 0 + +declare !dbg !4 dso_local i32 @global_func(i8 signext) local_unnamed_addr #1 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "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" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!9, !10, !11} +!llvm.ident = !{!12} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 77e5c60f04c4597ba5704d3cee61c6d359404ccd)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/extern") +!2 = !{} +!3 = !{!4} +!4 = !DISubprogram(name: "global_func", scope: !1, file: !1, line: 1, type: !5, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2) +!5 = !DISubroutineType(types: !6) +!6 = !{!7, !8} +!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!8 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!9 = !{i32 2, !"Dwarf Version", i32 4} +!10 = !{i32 2, !"Debug Info Version", i32 3} +!11 = !{i32 1, !"wchar_size", i32 4} +!12 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 77e5c60f04c4597ba5704d3cee61c6d359404ccd)"} +!13 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 2, type: !14, scopeLine: 2, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2) +!14 = !DISubroutineType(types: !15) +!15 = !{!7} +!16 = !DILocation(line: 3, column: 10, scope: !13) +!17 = !DILocation(line: 3, column: 3, scope: !13) Index: llvm/lib/Target/BPF/BTFDebug.h =================================================================== --- llvm/lib/Target/BPF/BTFDebug.h +++ llvm/lib/Target/BPF/BTFDebug.h @@ -293,6 +293,9 @@ /// Generate types and variables for globals. void processGlobals(bool ProcessingMapDef); + /// Generate types for function prototypes. + void processFuncPrototypes(); + /// Generate one offset relocation record. void generateFieldReloc(const MachineInstr *MI, const MCSymbol *ORSym, DIType *RootTy, StringRef AccessPattern); Index: llvm/lib/Target/BPF/BTFDebug.cpp =================================================================== --- llvm/lib/Target/BPF/BTFDebug.cpp +++ llvm/lib/Target/BPF/BTFDebug.cpp @@ -1055,15 +1055,11 @@ // Collect all types referenced by globals. const Module *M = MMI->getModule(); for (const GlobalVariable &Global : M->globals()) { - // Ignore external globals for now. - if (!Global.hasInitializer() && Global.hasExternalLinkage()) - continue; - // Decide the section name. StringRef SecName; if (Global.hasSection()) { SecName = Global.getSection(); - } else { + } else if (Global.hasInitializer() || !Global.hasExternalLinkage()) { // data, bss, or readonly sections if (Global.isConstant()) SecName = ".rodata"; @@ -1104,13 +1100,22 @@ Linkage != GlobalValue::ExternalLinkage) continue; - uint32_t GVarInfo = Linkage == GlobalValue::ExternalLinkage - ? BTF::VAR_GLOBAL_ALLOCATED - : BTF::VAR_STATIC; + uint32_t GVarInfo; + if (Linkage == GlobalValue::InternalLinkage) { + GVarInfo = BTF::VAR_STATIC; + } else if (Global.hasInitializer()) { + GVarInfo = BTF::VAR_GLOBAL_ALLOCATED; + } else { + GVarInfo = BTF::VAR_GLOBAL_EXTERNAL; + } + auto VarEntry = std::make_unique<BTFKindVar>(Global.getName(), GVTypeId, GVarInfo); uint32_t VarId = addType(std::move(VarEntry)); + if (SecName.empty()) + continue; + // Find or create a DataSec if (DataSecEntries.find(SecName) == DataSecEntries.end()) { DataSecEntries[SecName] = std::make_unique<BTFKindDataSec>(Asm, SecName); @@ -1144,6 +1149,34 @@ return false; } +void BTFDebug::processFuncPrototypes() { + const Module *M = MMI->getModule(); + for (const Function &F : M->functions()) { + const DISubprogram *SP = F.getSubprogram(); + if (!SP || SP->isDefinition()) + continue; + + uint32_t ProtoTypeId; + const std::unordered_map<uint32_t, StringRef> FuncArgNames; + visitSubroutineType(SP->getType(), false, FuncArgNames, ProtoTypeId); + + auto VarEntry = + std::make_unique<BTFKindVar>(SP->getName(), ProtoTypeId, + BTF::VAR_GLOBAL_EXTERNAL); + uint32_t VarId = addType(std::move(VarEntry)); + + StringRef SecName = F.getSection(); + if (SecName.empty()) + continue; + + if (DataSecEntries.find(SecName) == DataSecEntries.end()) { + DataSecEntries[SecName] = std::make_unique<BTFKindDataSec>(Asm, SecName); + } + + DataSecEntries[SecName]->addVar(VarId, Asm->getSymbol(&F), 8); + } +} + void BTFDebug::endModule() { // Collect MapDef globals if not collected yet. if (MapDefNotCollected) { @@ -1153,6 +1186,9 @@ // Collect global types/variables except MapDef globals. processGlobals(false); + + processFuncPrototypes(); + for (auto &DataSec : DataSecEntries) addType(std::move(DataSec.second)); Index: llvm/lib/Target/BPF/BTF.h =================================================================== --- llvm/lib/Target/BPF/BTF.h +++ llvm/lib/Target/BPF/BTF.h @@ -180,6 +180,7 @@ enum : uint8_t { VAR_STATIC = 0, ///< Linkage: InternalLinkage VAR_GLOBAL_ALLOCATED = 1, ///< Linkage: ExternalLinkage + VAR_GLOBAL_EXTERNAL = 2, ///< Linkage: ExternalLinkage }; /// BTF_KIND_DATASEC are followed by multiple "struct BTFDataSecVar". Index: llvm/lib/IR/DebugInfo.cpp =================================================================== --- llvm/lib/IR/DebugInfo.cpp +++ llvm/lib/IR/DebugInfo.cpp @@ -1290,7 +1290,7 @@ return wrap(unwrap(Builder)->createGlobalVariableExpression( unwrapDI<DIScope>(Scope), {Name, NameLen}, {Linkage, LinkLen}, unwrapDI<DIFile>(File), LineNo, unwrapDI<DIType>(Ty), LocalToUnit, - unwrap<DIExpression>(Expr), unwrapDI<MDNode>(Decl), + true, unwrap<DIExpression>(Expr), unwrapDI<MDNode>(Decl), nullptr, AlignInBits)); } Index: llvm/lib/IR/DIBuilder.cpp =================================================================== --- llvm/lib/IR/DIBuilder.cpp +++ llvm/lib/IR/DIBuilder.cpp @@ -639,13 +639,14 @@ DIGlobalVariableExpression *DIBuilder::createGlobalVariableExpression( DIScope *Context, StringRef Name, StringRef LinkageName, DIFile *F, - unsigned LineNumber, DIType *Ty, bool isLocalToUnit, DIExpression *Expr, + unsigned LineNumber, DIType *Ty, bool isLocalToUnit, + bool isDefined, DIExpression *Expr, MDNode *Decl, MDTuple *templateParams, uint32_t AlignInBits) { checkGlobalVariableScope(Context); auto *GV = DIGlobalVariable::getDistinct( VMContext, cast_or_null<DIScope>(Context), Name, LinkageName, F, - LineNumber, Ty, isLocalToUnit, true, cast_or_null<DIDerivedType>(Decl), + LineNumber, Ty, isLocalToUnit, isDefined, cast_or_null<DIDerivedType>(Decl), templateParams, AlignInBits); if (!Expr) Expr = createExpression(); Index: llvm/include/llvm/IR/DIBuilder.h =================================================================== --- llvm/include/llvm/IR/DIBuilder.h +++ llvm/include/llvm/IR/DIBuilder.h @@ -581,7 +581,7 @@ /// specified) DIGlobalVariableExpression *createGlobalVariableExpression( DIScope *Context, StringRef Name, StringRef LinkageName, DIFile *File, - unsigned LineNo, DIType *Ty, bool isLocalToUnit, + unsigned LineNo, DIType *Ty, bool isLocalToUnit, bool isDefined = true, DIExpression *Expr = nullptr, MDNode *Decl = nullptr, MDTuple *templateParams = nullptr, uint32_t AlignInBits = 0); Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ clang/lib/Sema/SemaDecl.cpp @@ -12149,6 +12149,10 @@ Diag(Var->getLocation(), diag::note_private_extern); } + if (Context.getTargetInfo().allowDebugInfoForDeclOnly() && + !Var->isInvalidDecl()) + TentativeDeclarations.push_back(Var); + return; case VarDecl::TentativeDefinition: Index: clang/lib/Sema/Sema.cpp =================================================================== --- clang/lib/Sema/Sema.cpp +++ clang/lib/Sema/Sema.cpp @@ -1137,6 +1137,13 @@ Consumer.CompleteTentativeDefinition(VD); } + for (auto VD: TentativeDeclarations) { + if (!VD || VD->isInvalidDecl()) + continue; + + Consumer.CompleteTentativeDeclaration(VD); + } + // If there were errors, disable 'unused' warnings since they will mostly be // noise. Don't warn for a use from a module: either we should warn on all // file-scope declarations in modules or not at all, but whether the Index: clang/lib/CodeGen/ModuleBuilder.cpp =================================================================== --- clang/lib/CodeGen/ModuleBuilder.cpp +++ clang/lib/CodeGen/ModuleBuilder.cpp @@ -290,6 +290,10 @@ Builder->EmitTentativeDefinition(D); } + void CompleteTentativeDeclaration(VarDecl *D) override { + Builder->EmitTentativeDeclaration(D); + } + void HandleVTable(CXXRecordDecl *RD) override { if (Diags.hasErrorOccurred()) return; Index: clang/lib/CodeGen/CodeGenModule.h =================================================================== --- clang/lib/CodeGen/CodeGenModule.h +++ clang/lib/CodeGen/CodeGenModule.h @@ -1162,6 +1162,7 @@ StringRef getBlockMangledName(GlobalDecl GD, const BlockDecl *BD); void EmitTentativeDefinition(const VarDecl *D); + void EmitTentativeDeclaration(const VarDecl *D); void EmitVTable(CXXRecordDecl *Class); @@ -1398,6 +1399,7 @@ void EmitMultiVersionFunctionDefinition(GlobalDecl GD, llvm::GlobalValue *GV); void EmitGlobalVarDefinition(const VarDecl *D, bool IsTentative = false); + void EmitGlobalVarDeclaration(const VarDecl *D); void EmitAliasDefinition(GlobalDecl GD); void emitIFuncDefinition(GlobalDecl GD); void emitCPUDispatchDefinition(GlobalDecl GD); Index: clang/lib/CodeGen/CodeGenModule.cpp =================================================================== --- clang/lib/CodeGen/CodeGenModule.cpp +++ clang/lib/CodeGen/CodeGenModule.cpp @@ -3716,6 +3716,10 @@ EmitGlobalVarDefinition(D); } +void CodeGenModule::EmitTentativeDeclaration(const VarDecl *D) { + EmitGlobalVarDeclaration(D); +} + CharUnits CodeGenModule::GetTargetTypeStoreSize(llvm::Type *Ty) const { return Context.toCharUnitsFromBits( getDataLayout().getTypeStoreSizeInBits(Ty)); @@ -4099,6 +4103,19 @@ DI->EmitGlobalVariable(GV, D); } +void CodeGenModule::EmitGlobalVarDeclaration(const VarDecl *D) { + if (CGDebugInfo *DI = getModuleDebugInfo()) + if (getCodeGenOpts().getDebugInfo() >= codegenoptions::LimitedDebugInfo) { + QualType ASTTy = D->getType(); + llvm::Type *Ty = getTypes().ConvertTypeForMem(D->getType()); + llvm::PointerType *PTy = + llvm::PointerType::get(Ty, getContext().getTargetAddressSpace(ASTTy)); + llvm::Constant *GV = GetOrCreateLLVMGlobal(D->getName(), PTy, D); + DI->EmitGlobalDeclVariable( + cast<llvm::GlobalVariable>(GV->stripPointerCasts()), D); + } +} + static bool isVarDeclStrongDefinition(const ASTContext &Context, CodeGenModule &CGM, const VarDecl *D, bool NoCommon) { Index: clang/lib/CodeGen/CodeGenAction.cpp =================================================================== --- clang/lib/CodeGen/CodeGenAction.cpp +++ clang/lib/CodeGen/CodeGenAction.cpp @@ -331,6 +331,10 @@ Gen->CompleteTentativeDefinition(D); } + void CompleteTentativeDeclaration(VarDecl *D) override { + Gen->CompleteTentativeDeclaration(D); + } + void AssignInheritanceModel(CXXRecordDecl *RD) override { Gen->AssignInheritanceModel(RD); } Index: clang/lib/CodeGen/CGDebugInfo.h =================================================================== --- clang/lib/CodeGen/CGDebugInfo.h +++ clang/lib/CodeGen/CGDebugInfo.h @@ -477,6 +477,8 @@ /// Emit a constant global variable's debug info. void EmitGlobalVariable(const ValueDecl *VD, const APValue &Init); + void EmitGlobalDeclVariable(llvm::GlobalVariable *GV, const ValueDecl *VD); + /// Emit C++ using directive. void EmitUsingDirective(const UsingDirectiveDecl &UD); Index: clang/lib/CodeGen/CGDebugInfo.cpp =================================================================== --- clang/lib/CodeGen/CGDebugInfo.cpp +++ clang/lib/CodeGen/CGDebugInfo.cpp @@ -4489,7 +4489,7 @@ GVE = DBuilder.createGlobalVariableExpression( DContext, DeclName, LinkageName, Unit, LineNo, getOrCreateType(T, Unit), - Var->hasLocalLinkage(), + Var->hasLocalLinkage(), true, Expr.empty() ? nullptr : DBuilder.createExpression(Expr), getOrCreateStaticDataMemberDeclarationOrNull(D), TemplateParameters, Align); @@ -4592,10 +4592,29 @@ GV.reset(DBuilder.createGlobalVariableExpression( DContext, Name, StringRef(), Unit, getLineNumber(VD->getLocation()), Ty, - true, InitExpr, getOrCreateStaticDataMemberDeclarationOrNull(VarD), + true, true, InitExpr, getOrCreateStaticDataMemberDeclarationOrNull(VarD), TemplateParameters, Align)); } +void CGDebugInfo::EmitGlobalDeclVariable(llvm::GlobalVariable *Var, + const ValueDecl *VD) { + assert(DebugKind >= codegenoptions::LimitedDebugInfo); + if (VD->hasAttr<NoDebugAttr>()) + return; + + auto Align = getDeclAlignIfRequired(VD, CGM.getContext()); + llvm::DIFile *Unit = getOrCreateFile(VD->getLocation()); + StringRef Name = VD->getName(); + llvm::DIType *Ty = getOrCreateType(VD->getType(), Unit); + + llvm::DIScope *DContext = getDeclContextDescriptor(VD); + llvm::DIGlobalVariableExpression *GVE = + DBuilder.createGlobalVariableExpression( + DContext, Name, StringRef(), Unit, getLineNumber(VD->getLocation()), + Ty, false, false, nullptr, nullptr, nullptr, Align); + Var->addDebugInfo(GVE); +} + llvm::DIScope *CGDebugInfo::getCurrentContextDescriptor(const Decl *D) { if (!LexicalBlockStack.empty()) return LexicalBlockStack.back(); Index: clang/lib/Basic/Targets/BPF.h =================================================================== --- clang/lib/Basic/Targets/BPF.h +++ clang/lib/Basic/Targets/BPF.h @@ -76,6 +76,8 @@ return None; } + bool allowDebugInfoForDeclOnly() const override { return true; } + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { switch (CC) { default: Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -665,6 +665,7 @@ /// All the tentative definitions encountered in the TU. TentativeDefinitionsType TentativeDefinitions; + SmallVector<VarDecl *, 4> TentativeDeclarations; typedef LazyVector<const DeclaratorDecl *, ExternalSemaSource, &ExternalSemaSource::ReadUnusedFileScopedDecls, 2, 2> Index: clang/include/clang/Basic/TargetInfo.h =================================================================== --- clang/include/clang/Basic/TargetInfo.h +++ clang/include/clang/Basic/TargetInfo.h @@ -1395,6 +1395,9 @@ virtual void setAuxTarget(const TargetInfo *Aux) {} + /// Whether target allows debuginfo types for decl only variables. + virtual bool allowDebugInfoForDeclOnly() const { return false; } + protected: /// Copy type and layout related info. void copyAuxTarget(const TargetInfo *Aux); Index: clang/include/clang/AST/ASTConsumer.h =================================================================== --- clang/include/clang/AST/ASTConsumer.h +++ clang/include/clang/AST/ASTConsumer.h @@ -102,6 +102,8 @@ /// modified by the introduction of an implicit zero initializer. virtual void CompleteTentativeDefinition(VarDecl *D) {} + virtual void CompleteTentativeDeclaration(VarDecl *D) {} + /// Callback invoked when an MSInheritanceAttr has been attached to a /// CXXRecordDecl. virtual void AssignInheritanceModel(CXXRecordDecl *RD) {}
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits