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

Reply via email to