diff --git a/lld/ELF/Arch/BPF.cpp b/lld/ELF/Arch/BPF.cpp new file mode 100644 --- /dev/null +++ b/lld/ELF/Arch/BPF.cpp @@ -0,0 +1,113 @@ +//===---- BPF.cpp ---------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "Target.h" +#include "llvm/Object/ELF.h" + +using namespace llvm; +using namespace llvm::ELF; +using namespace lld; +using namespace lld::elf; + +namespace { +class BPF final : public TargetInfo { +public: + BPF(); + int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override; + int64_t getImplicitAddendAlloc(const uint8_t *buf, + RelType type) const override; + void relocate(uint8_t *loc, const Relocation &rel, + uint64_t val) const override; + void relocateAlloc(uint8_t *loc, const Relocation &rel, + uint64_t val) const override; + RelType getDynRel(RelType type) const override; + RelExpr getRelExpr(RelType type, const Symbol &s, + const uint8_t *loc) const override; +}; +} // namespace + +BPF::BPF() { noneRel = R_BPF_NONE; } + +int64_t BPF::getImplicitAddend(const uint8_t *buf, RelType type) const { + switch (type) { + case R_BPF_NONE: + return 0; + case R_BPF_64_64: + return read64(buf); + case R_BPF_64_32: + return read32(buf); + default: + llvm_unreachable("unknown relocation"); + } +} + +void BPF::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { + switch (rel.type) { + case R_BPF_NONE: + break; + case R_BPF_64_64: + write64(loc, val); + break; + case R_BPF_64_32: + write32(loc, (uint32_t)val); + break; + default: + llvm_unreachable("unknown relocation"); + } +} + +int64_t BPF::getImplicitAddendAlloc(const uint8_t *buf, + RelType type) const { + switch (type) { + case R_BPF_NONE: + return 0; + case R_BPF_64_64: + return read32(buf + 4); + case R_BPF_64_32: + // The addend is the (sec_offset/8 - 1) which could be negative. + return (int32_t)(uint32_t)(read32(buf + 4) * 8); + default: + llvm_unreachable("unknown relocation"); + } +} + +void BPF::relocateAlloc(uint8_t *loc, const Relocation &rel, + uint64_t val) const { + switch (rel.type) { + case R_BPF_NONE: + break; + case R_BPF_64_64: + write32(loc + 4, (uint32_t)val); + break; + case R_BPF_64_32: + write32(loc + 4, (uint32_t)(val / 8)); + break; + default: + llvm_unreachable("unknown relocation"); + } +} + +RelType BPF::getDynRel(RelType type) const { return R_BPF_NONE; } + +RelExpr BPF::getRelExpr(RelType type, const Symbol &s, + const uint8_t *loc) const { + switch (type) { + case R_BPF_NONE: + return R_NONE; + case R_BPF_64_32: + case R_BPF_64_64: + return R_ABS; + default: + llvm_unreachable("unknown relocation"); + } +} + +TargetInfo *elf::getBPFTargetInfo() { + static BPF target; + return ⌖ +} diff --git a/lld/ELF/CMakeLists.txt b/lld/ELF/CMakeLists.txt --- a/lld/ELF/CMakeLists.txt +++ b/lld/ELF/CMakeLists.txt @@ -8,6 +8,7 @@ Arch/AMDGPU.cpp Arch/ARM.cpp Arch/AVR.cpp + Arch/BPF.cpp Arch/Hexagon.cpp Arch/Mips.cpp Arch/MipsArchTree.cpp diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -1629,6 +1629,9 @@ return EM_ARM; case Triple::avr: return EM_AVR; + case Triple::bpfel: + case Triple::bpfeb: + return EM_BPF; case Triple::mips: case Triple::mipsel: case Triple::mips64: diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -470,8 +470,12 @@ int64_t addend = getAddend(rel); const uint8_t *bufLoc = sec->data().begin() + rel.r_offset; - if (!RelTy::IsRela) - addend = target->getImplicitAddend(bufLoc, type); + if (!RelTy::IsRela) { + if (sec->flags & SHF_ALLOC) + addend = target->getImplicitAddendAlloc(bufLoc, type); + else + addend = target->getImplicitAddend(bufLoc, type); + } if (config->emachine == EM_MIPS && target->getRelExpr(type, sym, bufLoc) == R_MIPS_GOTREL) { @@ -1054,7 +1058,7 @@ // opportunities but is safe. if (ppc64noTocRelax.count({rel.sym, rel.addend}) || !tryRelaxPPC64TocIndirection(rel, bufLoc)) - target->relocate(bufLoc, rel, targetVA); + target->relocateAlloc(bufLoc, rel, targetVA); break; case R_RELAX_TLS_IE_TO_LE: target->relaxTlsIeToLe(bufLoc, rel, targetVA); @@ -1097,10 +1101,10 @@ } write32(bufLoc + 4, 0xe8410018); // ld %r2, 24(%r1) } - target->relocate(bufLoc, rel, targetVA); + target->relocateAlloc(bufLoc, rel, targetVA); break; default: - target->relocate(bufLoc, rel, targetVA); + target->relocateAlloc(bufLoc, rel, targetVA); break; } } diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp --- a/lld/ELF/LTO.cpp +++ b/lld/ELF/LTO.cpp @@ -84,9 +84,10 @@ c.Options.RelaxELFRelocations = true; c.Options.EmitAddrsig = true; - // Always emit a section per function/datum with LTO. - c.Options.FunctionSections = true; - c.Options.DataSections = true; + if (config->emachine != EM_BPF || !config->relocatable) { + c.Options.FunctionSections = true; + c.Options.DataSections = true; + } // Check if basic block sections must be used. // Allowed values for --lto-basic-block-sections are "all", "labels", diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h --- a/lld/ELF/Target.h +++ b/lld/ELF/Target.h @@ -34,6 +34,10 @@ virtual void writeGotPlt(uint8_t *buf, const Symbol &s) const {}; virtual void writeIgotPlt(uint8_t *buf, const Symbol &s) const {} virtual int64_t getImplicitAddend(const uint8_t *buf, RelType type) const; + virtual int64_t getImplicitAddendAlloc(const uint8_t *buf, + RelType type) const { + return getImplicitAddend(buf, type); + } virtual int getTlsGdRelaxSkip(RelType type) const { return 1; } // If lazy binding is supported, the first entry of the PLT has code @@ -87,6 +91,10 @@ void relocateNoSym(uint8_t *loc, RelType type, uint64_t val) const { relocate(loc, Relocation{R_NONE, type, 0, 0, nullptr}, val); } + virtual void relocateAlloc(uint8_t *loc, const Relocation &rel, + uint64_t val) const { + relocate(loc, rel, val); + } virtual void applyJumpInstrMod(uint8_t *loc, JumpModType type, JumpModType val) const {} @@ -175,6 +183,7 @@ TargetInfo *getAMDGPUTargetInfo(); TargetInfo *getARMTargetInfo(); TargetInfo *getAVRTargetInfo(); +TargetInfo *getBPFTargetInfo(); TargetInfo *getHexagonTargetInfo(); TargetInfo *getMSP430TargetInfo(); TargetInfo *getPPC64TargetInfo(); diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp --- a/lld/ELF/Target.cpp +++ b/lld/ELF/Target.cpp @@ -60,6 +60,8 @@ return getARMTargetInfo(); case EM_AVR: return getAVRTargetInfo(); + case EM_BPF: + return getBPFTargetInfo(); case EM_HEXAGON: return getHexagonTargetInfo(); case EM_MIPS: diff --git a/lld/docs/index.rst b/lld/docs/index.rst --- a/lld/docs/index.rst +++ b/lld/docs/index.rst @@ -33,8 +33,8 @@ machine, you can expect that LLD runs more than twice as fast as the GNU gold linker. Your mileage may vary, though. -- It supports various CPUs/ABIs including AArch64, AMDGPU, ARM, Hexagon, MIPS - 32/64 big/little-endian, PowerPC, PowerPC64, RISC-V, SPARC V9, x86-32 and +- It supports various CPUs/ABIs including AArch64, AMDGPU, ARM, BPF, Hexagon, + MIPS 32/64 big/little-endian, PowerPC, PowerPC64, RISC-V, SPARC V9, x86-32 and x86-64. Among these, AArch64, ARM (>= v6), PowerPC, PowerPC64, x86-32 and x86-64 have production quality. MIPS seems decent too. diff --git a/lld/docs/ld.lld.1 b/lld/docs/ld.lld.1 --- a/lld/docs/ld.lld.1 +++ b/lld/docs/ld.lld.1 @@ -27,7 +27,7 @@ as GNU linkers. .Pp .Nm -currently supports i386, x86-64, ARM, AArch64, PowerPC32, PowerPC64, +currently supports i386, x86-64, ARM, AArch64, BPF, PowerPC32, PowerPC64, MIPS32, MIPS64, RISC-V, AMDGPU, Hexagon and SPARC V9 targets. .Nm acts as a Microsoft link.exe-compatible linker if invoked as diff --git a/lld/test/ELF/bpf-basic.s b/lld/test/ELF/bpf-basic.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/bpf-basic.s @@ -0,0 +1,24 @@ +// REQUIRES: bpf +// RUN: split-file %s %t +// RUN: llc -filetype=obj -mtriple=bpfel %t/a.ll -o %t1.el.o +// RUN: llc -filetype=obj -mtriple=bpfel %t/b.ll -o %t2.el.o +// RUN: ld.lld -r %t1.el.o %t2.el.o -o %t3.el +// RUN: llvm-objdump -d --no-show-raw-insn %t3.el | FileCheck %s +// RUN: llc -filetype=obj -mtriple=bpfeb %t/a.ll -o %t1.eb.o +// RUN: llc -filetype=obj -mtriple=bpfeb %t/b.ll -o %t2.eb.o +// RUN: ld.lld -r %t1.eb.o %t2.eb.o -o %t3.eb +// RUN: llvm-objdump -d --no-show-raw-insn %t5.eb | FileCheck %s + +// CHECK: : +// CHECK: r0 = 0 +// CHECK: exit + +// CHECK: : +// CHECK: r0 = 1 +// CHECK: exit + +//--- a.ll +define dso_local i32 @foo() local_unnamed_addr { entry: ret i32 0 } + +//--- b.ll +define dso_local i32 @bar() local_unnamed_addr { entry: ret i32 1 } diff --git a/lld/test/ELF/lto/bpf-diff-sec.ll b/lld/test/ELF/lto/bpf-diff-sec.ll new file mode 100644 --- /dev/null +++ b/lld/test/ELF/lto/bpf-diff-sec.ll @@ -0,0 +1,111 @@ +; REQUIRES: bpf +; RUN: split-file %s %t +; RUN: llvm-as %t/a.ll -o %t1.bc +; RUN: llvm-as %t/b.ll -o %t2.bc +; RUN: ld.lld -r %t1.bc %t2.bc -o %t3 +; RUN: llvm-objdump -d --no-show-raw-insn %t3 | FileCheck %s +; RUN: llvm-readelf -r %t3 | FileCheck -check-prefix=RELOC %s + +; CHECK: section .text: +; CHECK: r0 = 0 ll +; CHECK: section sec2: +; CHECK: call -1 +; CHECK: call 2 + +; RELOC: .rel.text +; RELOC: R_BPF_64_64 {{[0-9a-f]+}} sec3 +; RELOC: .relsec2 +; RELOC: R_BPF_64_32 {{[0-9a-f]+}} sec1 +; RELOC: R_BPF_64_32 {{[0-9a-f]+}} sec1 + +;--- a.ll +; Source code: +; static __attribute__((noinline)) __attribute__((section("sec1"))) +; int add(int a, int b) { +; return a + b; +; } +; static __attribute__((noinline)) __attribute__((section("sec1"))) +; int sub(int a, int b) { +; return a - b; +; } +; __attribute__((section("sec2"))) +; int bar(int a, int b) { +; return add(a, b) + sub(a, b); +; } +; Compilation flags: +; clang -target bpfel -flto -O2 -S t1.c -o t1.ll + +; ModuleID = 't1.c' +source_filename = "t1.c" +target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128" +target triple = "bpfel" + +; Function Attrs: nofree norecurse nosync nounwind readnone willreturn mustprogress +define dso_local i32 @bar(i32 %a, i32 %b) local_unnamed_addr #0 section "sec2" { +entry: + %call = tail call fastcc i32 @add(i32 %a, i32 %b) + %call1 = tail call fastcc i32 @sub(i32 %a, i32 %b) + %add = add nsw i32 %call1, %call + ret i32 %add +} + +; Function Attrs: nofree noinline norecurse nosync nounwind readnone willreturn mustprogress +define internal fastcc i32 @add(i32 %a, i32 %b) unnamed_addr #1 section "sec1" { +entry: + %add = add nsw i32 %b, %a + ret i32 %add +} + +; Function Attrs: nofree noinline norecurse nosync nounwind readnone willreturn mustprogress +define internal fastcc i32 @sub(i32 %a, i32 %b) unnamed_addr #1 section "sec1" { +entry: + %sub = sub nsw i32 %a, %b + ret i32 %sub +} + +attributes #0 = { nofree norecurse nosync nounwind readnone willreturn mustprogress "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #1 = { nofree noinline norecurse nosync nounwind readnone willreturn mustprogress "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } + +!llvm.module.flags = !{!0, !1} +!llvm.ident = !{!2} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 7, !"frame-pointer", i32 2} +!2 = !{!"clang version 13.0.0 (https://github.com/llvm/llvm-project.git c16909d7d1000413a32d3fcbc765dc082e8b62c0)"} + +;--- b.ll +; Source code: +; static __attribute__((noinline)) __attribute__((section("sec3"))) +; int test() { +; return 0; +; } +; long test2() { return (long)&test; } +; Compilation flags: +; clang -target bpfel -flto -O2 -S t2.c -o t2.ll + +; ModuleID = 't2.c' +source_filename = "t2.c" +target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128" +target triple = "bpfel" + +; Function Attrs: nofree norecurse nosync nounwind readnone willreturn mustprogress +define dso_local i64 @test2() local_unnamed_addr #0 { +entry: + ret i64 ptrtoint (i32 ()* @test to i64) +} + +; Function Attrs: nofree noinline norecurse nosync nounwind readnone willreturn mustprogress +define internal i32 @test() #1 section "sec3" { +entry: + ret i32 0 +} + +attributes #0 = { nofree norecurse nosync nounwind readnone willreturn mustprogress "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #1 = { nofree noinline norecurse nosync nounwind readnone willreturn mustprogress "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } + +!llvm.module.flags = !{!0, !1} +!llvm.ident = !{!2} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 7, !"frame-pointer", i32 2} +!2 = !{!"clang version 13.0.0 (https://github.com/llvm/llvm-project.git c16909d7d1000413a32d3fcbc765dc082e8b62c0)"} diff --git a/lld/test/ELF/lto/bpf-same-sec.ll b/lld/test/ELF/lto/bpf-same-sec.ll new file mode 100644 --- /dev/null +++ b/lld/test/ELF/lto/bpf-same-sec.ll @@ -0,0 +1,178 @@ +; REQUIRES: bpf +; RUN: split-file %s %t +; RUN: llvm-as %t/a.ll -o %t1.bc +; RUN: llvm-as %t/b.ll -o %t2.bc +; RUN: ld.lld -r %t1.bc %t2.bc -o %t3 +; RUN: llvm-objdump -d --no-show-raw-insn %t3 | FileCheck %s +; RUN: llvm-readelf -r %t3 | FileCheck -check-prefix=RELOC %s +; RUN: llvm-readelf -x ".BTF" %t3 | FileCheck -check-prefix=BTF %s + +; CHECK: : +; CHECK: call [[#]] +; CHECK: call -1 +; CHECK: : +; CHECK: : + +; RELOC: R_BPF_64_32 {{[0-9a-f]+}} foo + +; '9feb0100' below is the first 4 bytes of the .BTF section, +; representing BTF Magic value (0x9feb in little endian format), +; version (0x1) and flags (0x0). + +; BTF: 9feb0100 +; BTF-NOT: 9feb0100 + +;--- a.ll +; Source code: +; struct s { +; int a; +; int b; +; }; +; extern int foo(int); +; static __attribute__((noinline)) int add(int a, int b) { +; return a + b; +; } +; int bar(struct s *arg) { +; return add(arg->a, arg->b) + foo(arg->a); +; } +; Compilation flags: +; clang -target bpfel -flto -O2 -g -S t1.c -o t1.ll + +; ModuleID = 't1.c' +source_filename = "t1.c" +target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128" +target triple = "bpfel" + +%struct.s = type { i32, i32 } + +; Function Attrs: nounwind +define dso_local i32 @bar(%struct.s* nocapture readonly %arg) local_unnamed_addr #0 !dbg !8 { +entry: + call void @llvm.dbg.value(metadata %struct.s* %arg, metadata !18, metadata !DIExpression()), !dbg !19 + %a = getelementptr inbounds %struct.s, %struct.s* %arg, i64 0, i32 0, !dbg !20 + %0 = load i32, i32* %a, align 4, !dbg !20, !tbaa !21 + %b = getelementptr inbounds %struct.s, %struct.s* %arg, i64 0, i32 1, !dbg !26 + %1 = load i32, i32* %b, align 4, !dbg !26, !tbaa !27 + %call = tail call fastcc i32 @add(i32 %0, i32 %1), !dbg !28 + %call2 = tail call i32 @foo(i32 %0) #4, !dbg !29 + %add = add nsw i32 %call2, %call, !dbg !30 + ret i32 %add, !dbg !31 +} + +; Function Attrs: nofree noinline norecurse nosync nounwind readnone willreturn mustprogress +define internal fastcc i32 @add(i32 %a, i32 %b) unnamed_addr #1 !dbg !32 { +entry: + call void @llvm.dbg.value(metadata i32 %a, metadata !36, metadata !DIExpression()), !dbg !38 + call void @llvm.dbg.value(metadata i32 %b, metadata !37, metadata !DIExpression()), !dbg !38 + %add = add nsw i32 %b, %a, !dbg !39 + ret i32 %add, !dbg !40 +} + +declare !dbg !41 dso_local i32 @foo(i32) local_unnamed_addr #2 + +; Function Attrs: nofree nosync nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #3 + +attributes #0 = { nounwind "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #1 = { nofree noinline norecurse nosync nounwind readnone willreturn mustprogress "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #2 = { "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #3 = { nofree nosync nounwind readnone speculatable willreturn } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5, !6} +!llvm.ident = !{!7} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 13.0.0 (https://github.com/llvm/llvm-project.git 433a5046a139601b86ac0f5a8ce89c79e153ff06)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "t1.c", directory: "/tmp/home/yhs/work/tests/llvm/lto") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{i32 7, !"frame-pointer", i32 2} +!7 = !{!"clang version 13.0.0 (https://github.com/llvm/llvm-project.git 433a5046a139601b86ac0f5a8ce89c79e153ff06)"} +!8 = distinct !DISubprogram(name: "bar", scope: !1, file: !1, line: 9, type: !9, scopeLine: 9, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !17) +!9 = !DISubroutineType(types: !10) +!10 = !{!11, !12} +!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64) +!13 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s", file: !1, line: 1, size: 64, elements: !14) +!14 = !{!15, !16} +!15 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !13, file: !1, line: 2, baseType: !11, size: 32) +!16 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !13, file: !1, line: 3, baseType: !11, size: 32, offset: 32) +!17 = !{!18} +!18 = !DILocalVariable(name: "arg", arg: 1, scope: !8, file: !1, line: 9, type: !12) +!19 = !DILocation(line: 0, scope: !8) +!20 = !DILocation(line: 10, column: 19, scope: !8) +!21 = !{!22, !23, i64 0} +!22 = !{!"s", !23, i64 0, !23, i64 4} +!23 = !{!"int", !24, i64 0} +!24 = !{!"omnipotent char", !25, i64 0} +!25 = !{!"Simple C/C++ TBAA"} +!26 = !DILocation(line: 10, column: 27, scope: !8) +!27 = !{!22, !23, i64 4} +!28 = !DILocation(line: 10, column: 10, scope: !8) +!29 = !DILocation(line: 10, column: 32, scope: !8) +!30 = !DILocation(line: 10, column: 30, scope: !8) +!31 = !DILocation(line: 10, column: 3, scope: !8) +!32 = distinct !DISubprogram(name: "add", scope: !1, file: !1, line: 6, type: !33, scopeLine: 6, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !35) +!33 = !DISubroutineType(types: !34) +!34 = !{!11, !11, !11} +!35 = !{!36, !37} +!36 = !DILocalVariable(name: "a", arg: 1, scope: !32, file: !1, line: 6, type: !11) +!37 = !DILocalVariable(name: "b", arg: 2, scope: !32, file: !1, line: 6, type: !11) +!38 = !DILocation(line: 0, scope: !32) +!39 = !DILocation(line: 7, column: 12, scope: !32) +!40 = !DILocation(line: 7, column: 3, scope: !32) +!41 = !DISubprogram(name: "foo", scope: !1, file: !1, line: 5, type: !42, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2) +!42 = !DISubroutineType(types: !43) +!43 = !{!11, !11} + +;--- b.ll +; Source code: +; int __attribute__((noinline)) foo(int a) { +; return a * a; +; } +; Compilation flags: +; clang -target bpfel -flto -O2 -g -S t2.c -o t2.ll + +; ModuleID = 't2.c' +source_filename = "t2.c" +target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128" +target triple = "bpfel" + +; Function Attrs: nofree noinline norecurse nosync nounwind readnone willreturn mustprogress +define dso_local i32 @foo(i32 %a) local_unnamed_addr #0 !dbg !8 { +entry: + call void @llvm.dbg.value(metadata i32 %a, metadata !13, metadata !DIExpression()), !dbg !14 + %mul = mul nsw i32 %a, %a, !dbg !15 + ret i32 %mul, !dbg !16 +} + +; Function Attrs: nofree nosync nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #1 + +attributes #0 = { nofree noinline norecurse nosync nounwind readnone willreturn mustprogress "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #1 = { nofree nosync nounwind readnone speculatable willreturn } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5, !6} +!llvm.ident = !{!7} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 13.0.0 (https://github.com/llvm/llvm-project.git 433a5046a139601b86ac0f5a8ce89c79e153ff06)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "t2.c", directory: "/tmp/home/yhs/work/tests/llvm/lto") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{i32 7, !"frame-pointer", i32 2} +!7 = !{!"clang version 13.0.0 (https://github.com/llvm/llvm-project.git 433a5046a139601b86ac0f5a8ce89c79e153ff06)"} +!8 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !9, scopeLine: 1, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !12) +!9 = !DISubroutineType(types: !10) +!10 = !{!11, !11} +!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!12 = !{!13} +!13 = !DILocalVariable(name: "a", arg: 1, scope: !8, file: !1, line: 1, type: !11) +!14 = !DILocation(line: 0, scope: !8) +!15 = !DILocation(line: 2, column: 12, scope: !8) +!16 = !DILocation(line: 2, column: 3, scope: !8) diff --git a/lld/test/lit.cfg.py b/lld/test/lit.cfg.py --- a/lld/test/lit.cfg.py +++ b/lld/test/lit.cfg.py @@ -69,6 +69,7 @@ 'AMDGPU': 'amdgpu', 'ARM': 'arm', 'AVR': 'avr', + 'BPF': 'bpf', 'Hexagon': 'hexagon', 'Mips': 'mips', 'MSP430': 'msp430',