summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYonghong Song <yhs@fb.com>2019-07-09 15:28:41 +0000
committerYonghong Song <yhs@fb.com>2019-07-09 15:28:41 +0000
commitd3d88d08b5d963965488a2c07225671e968dd0ff (patch)
tree2f2509eec6daed6225d33cd64d1432e9e5de44ea
parentd050e456317f751c567d9100b5d3a6ca357a6469 (diff)
downloadbcm5719-llvm-d3d88d08b5d963965488a2c07225671e968dd0ff.tar.gz
bcm5719-llvm-d3d88d08b5d963965488a2c07225671e968dd0ff.zip
[BPF] Support for compile once and run everywhere
Introduction ============ This patch added intial support for bpf program compile once and run everywhere (CO-RE). The main motivation is for bpf program which depends on kernel headers which may vary between different kernel versions. The initial discussion can be found at https://lwn.net/Articles/773198/. Currently, bpf program accesses kernel internal data structure through bpf_probe_read() helper. The idea is to capture the kernel data structure to be accessed through bpf_probe_read() and relocate them on different kernel versions. On each host, right before bpf program load, the bpfloader will look at the types of the native linux through vmlinux BTF, calculates proper access offset and patch the instruction. To accommodate this, three intrinsic functions preserve_{array,union,struct}_access_index are introduced which in clang will preserve the base pointer, struct/union/array access_index and struct/union debuginfo type information. Later, bpf IR pass can reconstruct the whole gep access chains without looking at gep itself. This patch did the following: . An IR pass is added to convert preserve_*_access_index to global variable who name encodes the getelementptr access pattern. The global variable has metadata attached to describe the corresponding struct/union debuginfo type. . An SimplifyPatchable MachineInstruction pass is added to remove unnecessary loads. . The BTF output pass is enhanced to generate relocation records located in .BTF.ext section. Typical CO-RE also needs support of global variables which can be assigned to different values to different hosts. For example, kernel version can be used to guard different versions of codes. This patch added the support for patchable externals as well. Example ======= The following is an example. struct pt_regs { long arg1; long arg2; }; struct sk_buff { int i; struct net_device *dev; }; #define _(x) (__builtin_preserve_access_index(x)) static int (*bpf_probe_read)(void *dst, int size, const void *unsafe_ptr) = (void *) 4; extern __attribute__((section(".BPF.patchable_externs"))) unsigned __kernel_version; int bpf_prog(struct pt_regs *ctx) { struct net_device *dev = 0; // ctx->arg* does not need bpf_probe_read if (__kernel_version >= 41608) bpf_probe_read(&dev, sizeof(dev), _(&((struct sk_buff *)ctx->arg1)->dev)); else bpf_probe_read(&dev, sizeof(dev), _(&((struct sk_buff *)ctx->arg2)->dev)); return dev != 0; } In the above, we want to translate the third argument of bpf_probe_read() as relocations. -bash-4.4$ clang -target bpf -O2 -g -S trace.c The compiler will generate two new subsections in .BTF.ext, OffsetReloc and ExternReloc. OffsetReloc is to record the structure member offset operations, and ExternalReloc is to record the external globals where only u8, u16, u32 and u64 are supported. BPFOffsetReloc Size struct SecLOffsetReloc for ELF section #1 A number of struct BPFOffsetReloc for ELF section #1 struct SecOffsetReloc for ELF section #2 A number of struct BPFOffsetReloc for ELF section #2 ... BPFExternReloc Size struct SecExternReloc for ELF section #1 A number of struct BPFExternReloc for ELF section #1 struct SecExternReloc for ELF section #2 A number of struct BPFExternReloc for ELF section #2 struct BPFOffsetReloc { uint32_t InsnOffset; ///< Byte offset in this section uint32_t TypeID; ///< TypeID for the relocation uint32_t OffsetNameOff; ///< The string to traverse types }; struct BPFExternReloc { uint32_t InsnOffset; ///< Byte offset in this section uint32_t ExternNameOff; ///< The string for external variable }; Note that only externs with attribute section ".BPF.patchable_externs" are considered for Extern Reloc which will be patched by bpf loader right before the load. For the above test case, two offset records and one extern record will be generated: OffsetReloc records: .long .Ltmp12 # Insn Offset .long 7 # TypeId .long 242 # Type Decode String .long .Ltmp18 # Insn Offset .long 7 # TypeId .long 242 # Type Decode String ExternReloc record: .long .Ltmp5 # Insn Offset .long 165 # External Variable In string table: .ascii "0:1" # string offset=242 .ascii "__kernel_version" # string offset=165 The default member offset can be calculated as the 2nd member offset (0 representing the 1st member) of struct "sk_buff". The asm code: .Ltmp5: .Ltmp6: r2 = 0 r3 = 41608 .Ltmp7: .Ltmp8: .loc 1 18 9 is_stmt 0 # t.c:18:9 .Ltmp9: if r3 > r2 goto LBB0_2 .Ltmp10: .Ltmp11: .loc 1 0 9 # t.c:0:9 .Ltmp12: r2 = 8 .Ltmp13: .loc 1 19 66 is_stmt 1 # t.c:19:66 .Ltmp14: .Ltmp15: r3 = *(u64 *)(r1 + 0) goto LBB0_3 .Ltmp16: .Ltmp17: LBB0_2: .loc 1 0 66 is_stmt 0 # t.c:0:66 .Ltmp18: r2 = 8 .loc 1 21 66 is_stmt 1 # t.c:21:66 .Ltmp19: r3 = *(u64 *)(r1 + 8) .Ltmp20: .Ltmp21: LBB0_3: .loc 1 0 66 is_stmt 0 # t.c:0:66 r3 += r2 r1 = r10 .Ltmp22: .Ltmp23: .Ltmp24: r1 += -8 r2 = 8 call 4 For instruction .Ltmp12 and .Ltmp18, "r2 = 8", the number 8 is the structure offset based on the current BTF. Loader needs to adjust it if it changes on the host. For instruction .Ltmp5, "r2 = 0", the external variable got a default value 0, loader needs to supply an appropriate value for the particular host. Compiling to generate object code and disassemble: 0000000000000000 bpf_prog: 0: b7 02 00 00 00 00 00 00 r2 = 0 1: 7b 2a f8 ff 00 00 00 00 *(u64 *)(r10 - 8) = r2 2: b7 02 00 00 00 00 00 00 r2 = 0 3: b7 03 00 00 88 a2 00 00 r3 = 41608 4: 2d 23 03 00 00 00 00 00 if r3 > r2 goto +3 <LBB0_2> 5: b7 02 00 00 08 00 00 00 r2 = 8 6: 79 13 00 00 00 00 00 00 r3 = *(u64 *)(r1 + 0) 7: 05 00 02 00 00 00 00 00 goto +2 <LBB0_3> 0000000000000040 LBB0_2: 8: b7 02 00 00 08 00 00 00 r2 = 8 9: 79 13 08 00 00 00 00 00 r3 = *(u64 *)(r1 + 8) 0000000000000050 LBB0_3: 10: 0f 23 00 00 00 00 00 00 r3 += r2 11: bf a1 00 00 00 00 00 00 r1 = r10 12: 07 01 00 00 f8 ff ff ff r1 += -8 13: b7 02 00 00 08 00 00 00 r2 = 8 14: 85 00 00 00 04 00 00 00 call 4 Instructions #2, #5 and #8 need relocation resoutions from the loader. Signed-off-by: Yonghong Song <yhs@fb.com> Differential Revision: https://reviews.llvm.org/D61524 llvm-svn: 365503
-rw-r--r--llvm/lib/Target/BPF/BPF.h5
-rw-r--r--llvm/lib/Target/BPF/BPFAbstrctMemberAccess.cpp482
-rw-r--r--llvm/lib/Target/BPF/BPFAsmPrinter.cpp20
-rw-r--r--llvm/lib/Target/BPF/BPFCORE.h24
-rw-r--r--llvm/lib/Target/BPF/BPFMISimplifyPatchable.cpp163
-rw-r--r--llvm/lib/Target/BPF/BPFTargetMachine.cpp12
-rw-r--r--llvm/lib/Target/BPF/BTF.h63
-rw-r--r--llvm/lib/Target/BPF/BTFDebug.cpp489
-rw-r--r--llvm/lib/Target/BPF/BTFDebug.h63
-rw-r--r--llvm/lib/Target/BPF/CMakeLists.txt2
-rw-r--r--llvm/test/CodeGen/BPF/BTF/binary-format.ll44
-rw-r--r--llvm/test/CodeGen/BPF/BTF/extern-global-var.ll12
-rw-r--r--llvm/test/CodeGen/BPF/BTF/filename.ll24
-rw-r--r--llvm/test/CodeGen/BPF/BTF/func-func-ptr.ll30
-rw-r--r--llvm/test/CodeGen/BPF/BTF/func-non-void.ll30
-rw-r--r--llvm/test/CodeGen/BPF/BTF/func-source.ll24
-rw-r--r--llvm/test/CodeGen/BPF/BTF/func-typedef.ll39
-rw-r--r--llvm/test/CodeGen/BPF/BTF/func-unused-arg.ll28
-rw-r--r--llvm/test/CodeGen/BPF/BTF/func-void.ll20
-rw-r--r--llvm/test/CodeGen/BPF/BTF/local-var.ll20
-rw-r--r--llvm/test/CodeGen/BPF/BTF/map-def.ll120
-rw-r--r--llvm/test/CodeGen/BPF/BTF/ptr-prune-type.ll84
-rw-r--r--llvm/test/CodeGen/BPF/BTF/static-var-derived-type.ll12
-rw-r--r--llvm/test/CodeGen/BPF/BTF/static-var-inited-sec.ll12
-rw-r--r--llvm/test/CodeGen/BPF/BTF/static-var-inited.ll12
-rw-r--r--llvm/test/CodeGen/BPF/BTF/static-var-readonly-sec.ll12
-rw-r--r--llvm/test/CodeGen/BPF/BTF/static-var-readonly.ll12
-rw-r--r--llvm/test/CodeGen/BPF/BTF/static-var-sec.ll12
-rw-r--r--llvm/test/CodeGen/BPF/BTF/static-var-zerolen-array.ll12
-rw-r--r--llvm/test/CodeGen/BPF/BTF/static-var.ll12
-rw-r--r--llvm/test/CodeGen/BPF/CORE/offset-reloc-basic.ll186
-rw-r--r--llvm/test/CodeGen/BPF/CORE/offset-reloc-multilevel.ll197
-rw-r--r--llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-anonymous.ll213
-rw-r--r--llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-array.ll216
-rw-r--r--llvm/test/CodeGen/BPF/CORE/offset-reloc-union.ll220
-rw-r--r--llvm/test/CodeGen/BPF/CORE/patchable-extern-char.ll107
-rw-r--r--llvm/test/CodeGen/BPF/CORE/patchable-extern-uint.ll102
-rw-r--r--llvm/test/CodeGen/BPF/CORE/patchable-extern-ulonglong.ll103
-rw-r--r--llvm/test/CodeGen/BPF/reloc-btf-2.ll2
39 files changed, 3016 insertions, 224 deletions
diff --git a/llvm/lib/Target/BPF/BPF.h b/llvm/lib/Target/BPF/BPF.h
index 6c75fff9c7a..d311fc15409 100644
--- a/llvm/lib/Target/BPF/BPF.h
+++ b/llvm/lib/Target/BPF/BPF.h
@@ -15,11 +15,16 @@
namespace llvm {
class BPFTargetMachine;
+ModulePass *createBPFAbstractMemberAccess();
+
FunctionPass *createBPFISelDag(BPFTargetMachine &TM);
+FunctionPass *createBPFMISimplifyPatchablePass();
FunctionPass *createBPFMIPeepholePass();
FunctionPass *createBPFMIPreEmitPeepholePass();
FunctionPass *createBPFMIPreEmitCheckingPass();
+void initializeBPFAbstractMemberAccessPass(PassRegistry&);
+void initializeBPFMISimplifyPatchablePass(PassRegistry&);
void initializeBPFMIPeepholePass(PassRegistry&);
void initializeBPFMIPreEmitPeepholePass(PassRegistry&);
void initializeBPFMIPreEmitCheckingPass(PassRegistry&);
diff --git a/llvm/lib/Target/BPF/BPFAbstrctMemberAccess.cpp b/llvm/lib/Target/BPF/BPFAbstrctMemberAccess.cpp
new file mode 100644
index 00000000000..51d4cbc8a42
--- /dev/null
+++ b/llvm/lib/Target/BPF/BPFAbstrctMemberAccess.cpp
@@ -0,0 +1,482 @@
+//===------ BPFAbstractMemberAccess.cpp - Abstracting Member Accesses -----===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This pass abstracted struct/union member accesses in order to support
+// compile-once run-everywhere (CO-RE). The CO-RE intends to compile the program
+// which can run on different kernels. In particular, if bpf program tries to
+// access a particular kernel data structure member, the details of the
+// intermediate member access will be remembered so bpf loader can do
+// necessary adjustment right before program loading.
+//
+// For example,
+//
+// struct s {
+// int a;
+// int b;
+// };
+// struct t {
+// struct s c;
+// int d;
+// };
+// struct t e;
+//
+// For the member access e.c.b, the compiler will generate code
+// &e + 4
+//
+// The compile-once run-everywhere instead generates the following code
+// r = 4
+// &e + r
+// The "4" in "r = 4" can be changed based on a particular kernel version.
+// For example, on a particular kernel version, if struct s is changed to
+//
+// struct s {
+// int new_field;
+// int a;
+// int b;
+// }
+//
+// By repeating the member access on the host, the bpf loader can
+// adjust "r = 4" as "r = 8".
+//
+// This feature relies on the following three intrinsic calls:
+// addr = preserve_array_access_index(base, dimension, index)
+// addr = preserve_union_access_index(base, di_index)
+// !llvm.preserve.access.index <union_ditype>
+// addr = preserve_struct_access_index(base, gep_index, di_index)
+// !llvm.preserve.access.index <struct_ditype>
+//
+//===----------------------------------------------------------------------===//
+
+#include "BPF.h"
+#include "BPFCORE.h"
+#include "BPFTargetMachine.h"
+#include "llvm/IR/DebugInfoMetadata.h"
+#include "llvm/IR/GlobalVariable.h"
+#include "llvm/IR/Instruction.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/Type.h"
+#include "llvm/IR/User.h"
+#include "llvm/IR/Value.h"
+#include "llvm/Pass.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+
+#define DEBUG_TYPE "bpf-abstract-member-access"
+
+namespace llvm {
+const std::string BPFCoreSharedInfo::AmaAttr = "btf_ama";
+const std::string BPFCoreSharedInfo::PatchableExtSecName =
+ ".BPF.patchable_externs";
+} // namespace llvm
+
+using namespace llvm;
+
+namespace {
+
+class BPFAbstractMemberAccess final : public ModulePass {
+ StringRef getPassName() const override {
+ return "BPF Abstract Member Access";
+ }
+
+ bool runOnModule(Module &M) override;
+
+public:
+ static char ID;
+ BPFAbstractMemberAccess() : ModulePass(ID) {}
+
+private:
+ enum : uint32_t {
+ BPFPreserveArrayAI = 1,
+ BPFPreserveUnionAI = 2,
+ BPFPreserveStructAI = 3,
+ };
+
+ std::map<std::string, GlobalVariable *> GEPGlobals;
+ // A map to link preserve_*_access_index instrinsic calls.
+ std::map<CallInst *, std::pair<CallInst *, uint32_t>> AIChain;
+ // A map to hold all the base preserve_*_access_index instrinsic calls.
+ // The base call is not an input of any other preserve_*_access_index
+ // intrinsics.
+ std::map<CallInst *, uint32_t> BaseAICalls;
+
+ bool doTransformation(Module &M);
+
+ void traceAICall(CallInst *Call, uint32_t Kind);
+ void traceBitCast(BitCastInst *BitCast, CallInst *Parent, uint32_t Kind);
+ void traceGEP(GetElementPtrInst *GEP, CallInst *Parent, uint32_t Kind);
+ void collectAICallChains(Module &M, Function &F);
+
+ bool IsPreserveDIAccessIndexCall(const CallInst *Call, uint32_t &Kind);
+ bool removePreserveAccessIndexIntrinsic(Module &M);
+ void replaceWithGEP(std::vector<CallInst *> &CallList,
+ uint32_t NumOfZerosIndex, uint32_t DIIndex);
+
+ Value *computeBaseAndAccessStr(CallInst *Call, std::string &AccessStr,
+ std::string &AccessKey, uint32_t Kind,
+ MDNode *&TypeMeta);
+ bool getAccessIndex(const Value *IndexValue, uint64_t &AccessIndex);
+ bool transformGEPChain(Module &M, CallInst *Call, uint32_t Kind);
+};
+} // End anonymous namespace
+
+char BPFAbstractMemberAccess::ID = 0;
+INITIALIZE_PASS(BPFAbstractMemberAccess, DEBUG_TYPE,
+ "abstracting struct/union member accessees", false, false)
+
+ModulePass *llvm::createBPFAbstractMemberAccess() {
+ return new BPFAbstractMemberAccess();
+}
+
+bool BPFAbstractMemberAccess::runOnModule(Module &M) {
+ LLVM_DEBUG(dbgs() << "********** Abstract Member Accesses **********\n");
+
+ // Bail out if no debug info.
+ if (empty(M.debug_compile_units()))
+ return false;
+
+ return doTransformation(M);
+}
+
+/// Check whether a call is a preserve_*_access_index intrinsic call or not.
+bool BPFAbstractMemberAccess::IsPreserveDIAccessIndexCall(const CallInst *Call,
+ uint32_t &Kind) {
+ if (!Call)
+ return false;
+
+ const auto *GV = dyn_cast<GlobalValue>(Call->getCalledValue());
+ if (!GV)
+ return false;
+ if (GV->getName().startswith("llvm.preserve.array.access.index")) {
+ Kind = BPFPreserveArrayAI;
+ return true;
+ }
+ if (GV->getName().startswith("llvm.preserve.union.access.index")) {
+ Kind = BPFPreserveUnionAI;
+ return true;
+ }
+ if (GV->getName().startswith("llvm.preserve.struct.access.index")) {
+ Kind = BPFPreserveStructAI;
+ return true;
+ }
+
+ return false;
+}
+
+void BPFAbstractMemberAccess::replaceWithGEP(std::vector<CallInst *> &CallList,
+ uint32_t DimensionIndex,
+ uint32_t GEPIndex) {
+ for (auto Call : CallList) {
+ uint32_t Dimension = 1;
+ if (DimensionIndex > 0)
+ Dimension = cast<ConstantInt>(Call->getArgOperand(DimensionIndex))
+ ->getZExtValue();
+
+ Constant *Zero =
+ ConstantInt::get(Type::getInt32Ty(Call->getParent()->getContext()), 0);
+ SmallVector<Value *, 4> IdxList;
+ for (unsigned I = 0; I < Dimension; ++I)
+ IdxList.push_back(Zero);
+ IdxList.push_back(Call->getArgOperand(GEPIndex));
+
+ auto *GEP = GetElementPtrInst::CreateInBounds(Call->getArgOperand(0),
+ IdxList, "", Call);
+ Call->replaceAllUsesWith(GEP);
+ Call->eraseFromParent();
+ }
+}
+
+bool BPFAbstractMemberAccess::removePreserveAccessIndexIntrinsic(Module &M) {
+ std::vector<CallInst *> PreserveArrayIndexCalls;
+ std::vector<CallInst *> PreserveUnionIndexCalls;
+ std::vector<CallInst *> PreserveStructIndexCalls;
+ bool Found = false;
+
+ for (Function &F : M)
+ for (auto &BB : F)
+ for (auto &I : BB) {
+ auto *Call = dyn_cast<CallInst>(&I);
+ uint32_t Kind;
+ if (!IsPreserveDIAccessIndexCall(Call, Kind))
+ continue;
+
+ Found = true;
+ if (Kind == BPFPreserveArrayAI)
+ PreserveArrayIndexCalls.push_back(Call);
+ else if (Kind == BPFPreserveUnionAI)
+ PreserveUnionIndexCalls.push_back(Call);
+ else
+ PreserveStructIndexCalls.push_back(Call);
+ }
+
+ // do the following transformation:
+ // . addr = preserve_array_access_index(base, dimension, index)
+ // is transformed to
+ // addr = GEP(base, dimenion's zero's, index)
+ // . addr = preserve_union_access_index(base, di_index)
+ // is transformed to
+ // addr = base, i.e., all usages of "addr" are replaced by "base".
+ // . addr = preserve_struct_access_index(base, gep_index, di_index)
+ // is transformed to
+ // addr = GEP(base, 0, gep_index)
+ replaceWithGEP(PreserveArrayIndexCalls, 1, 2);
+ replaceWithGEP(PreserveStructIndexCalls, 0, 1);
+ for (auto Call : PreserveUnionIndexCalls) {
+ Call->replaceAllUsesWith(Call->getArgOperand(0));
+ Call->eraseFromParent();
+ }
+
+ return Found;
+}
+
+void BPFAbstractMemberAccess::traceAICall(CallInst *Call, uint32_t Kind) {
+ for (User *U : Call->users()) {
+ Instruction *Inst = dyn_cast<Instruction>(U);
+ if (!Inst)
+ continue;
+
+ if (auto *BI = dyn_cast<BitCastInst>(Inst)) {
+ traceBitCast(BI, Call, Kind);
+ } else if (auto *CI = dyn_cast<CallInst>(Inst)) {
+ uint32_t CIKind;
+ if (IsPreserveDIAccessIndexCall(CI, CIKind)) {
+ AIChain[CI] = std::make_pair(Call, Kind);
+ traceAICall(CI, CIKind);
+ } else {
+ BaseAICalls[Call] = Kind;
+ }
+ } else if (auto *GI = dyn_cast<GetElementPtrInst>(Inst)) {
+ if (GI->hasAllZeroIndices())
+ traceGEP(GI, Call, Kind);
+ else
+ BaseAICalls[Call] = Kind;
+ }
+ }
+}
+
+void BPFAbstractMemberAccess::traceBitCast(BitCastInst *BitCast,
+ CallInst *Parent, uint32_t Kind) {
+ for (User *U : BitCast->users()) {
+ Instruction *Inst = dyn_cast<Instruction>(U);
+ if (!Inst)
+ continue;
+
+ if (auto *BI = dyn_cast<BitCastInst>(Inst)) {
+ traceBitCast(BI, Parent, Kind);
+ } else if (auto *CI = dyn_cast<CallInst>(Inst)) {
+ uint32_t CIKind;
+ if (IsPreserveDIAccessIndexCall(CI, CIKind)) {
+ AIChain[CI] = std::make_pair(Parent, Kind);
+ traceAICall(CI, CIKind);
+ } else {
+ BaseAICalls[Parent] = Kind;
+ }
+ } else if (auto *GI = dyn_cast<GetElementPtrInst>(Inst)) {
+ if (GI->hasAllZeroIndices())
+ traceGEP(GI, Parent, Kind);
+ else
+ BaseAICalls[Parent] = Kind;
+ }
+ }
+}
+
+void BPFAbstractMemberAccess::traceGEP(GetElementPtrInst *GEP, CallInst *Parent,
+ uint32_t Kind) {
+ for (User *U : GEP->users()) {
+ Instruction *Inst = dyn_cast<Instruction>(U);
+ if (!Inst)
+ continue;
+
+ if (auto *BI = dyn_cast<BitCastInst>(Inst)) {
+ traceBitCast(BI, Parent, Kind);
+ } else if (auto *CI = dyn_cast<CallInst>(Inst)) {
+ uint32_t CIKind;
+ if (IsPreserveDIAccessIndexCall(CI, CIKind)) {
+ AIChain[CI] = std::make_pair(Parent, Kind);
+ traceAICall(CI, CIKind);
+ } else {
+ BaseAICalls[Parent] = Kind;
+ }
+ } else if (auto *GI = dyn_cast<GetElementPtrInst>(Inst)) {
+ if (GI->hasAllZeroIndices())
+ traceGEP(GI, Parent, Kind);
+ else
+ BaseAICalls[Parent] = Kind;
+ }
+ }
+}
+
+void BPFAbstractMemberAccess::collectAICallChains(Module &M, Function &F) {
+ AIChain.clear();
+ BaseAICalls.clear();
+
+ for (auto &BB : F)
+ for (auto &I : BB) {
+ uint32_t Kind;
+ auto *Call = dyn_cast<CallInst>(&I);
+ if (!IsPreserveDIAccessIndexCall(Call, Kind) ||
+ AIChain.find(Call) != AIChain.end())
+ continue;
+
+ traceAICall(Call, Kind);
+ }
+}
+
+/// Get access index from the preserve_*_access_index intrinsic calls.
+bool BPFAbstractMemberAccess::getAccessIndex(const Value *IndexValue,
+ uint64_t &AccessIndex) {
+ const ConstantInt *CV = dyn_cast<ConstantInt>(IndexValue);
+ if (!CV)
+ return false;
+
+ AccessIndex = CV->getValue().getZExtValue();
+ return true;
+}
+
+/// Compute the base of the whole preserve_*_access_index chains, i.e., the base
+/// pointer of the first preserve_*_access_index call, and construct the access
+/// string, which will be the name of a global variable.
+Value *BPFAbstractMemberAccess::computeBaseAndAccessStr(CallInst *Call,
+ std::string &AccessStr,
+ std::string &AccessKey,
+ uint32_t Kind,
+ MDNode *&TypeMeta) {
+ Value *Base = nullptr;
+ std::vector<uint64_t> AccessIndices;
+ uint64_t TypeNameIndex = 0;
+ std::string LastTypeName;
+
+ while (Call) {
+ // Base of original corresponding GEP
+ Base = Call->getArgOperand(0);
+
+ // Type Name
+ std::string TypeName;
+ MDNode *MDN;
+ if (Kind == BPFPreserveUnionAI || Kind == BPFPreserveStructAI) {
+ MDN = Call->getMetadata(LLVMContext::MD_preserve_access_index);
+ if (!MDN)
+ return nullptr;
+
+ DIType *Ty = dyn_cast<DIType>(MDN);
+ if (!Ty)
+ return nullptr;
+
+ TypeName = Ty->getName();
+ }
+
+ // Access Index
+ uint64_t AccessIndex;
+ uint32_t ArgIndex = (Kind == BPFPreserveUnionAI) ? 1 : 2;
+ if (!getAccessIndex(Call->getArgOperand(ArgIndex), AccessIndex))
+ return nullptr;
+
+ AccessIndices.push_back(AccessIndex);
+ if (TypeName.size()) {
+ TypeNameIndex = AccessIndices.size() - 1;
+ LastTypeName = TypeName;
+ TypeMeta = MDN;
+ }
+
+ Kind = AIChain[Call].second;
+ Call = AIChain[Call].first;
+ }
+
+ // The intial type name is required.
+ // FIXME: if the initial type access is an array index, e.g.,
+ // &a[3].b.c, only one dimentional array is supported.
+ if (!LastTypeName.size() || AccessIndices.size() > TypeNameIndex + 2)
+ return nullptr;
+
+ // Construct the type string AccessStr.
+ for (unsigned I = 0; I < AccessIndices.size(); ++I)
+ AccessStr = std::to_string(AccessIndices[I]) + ":" + AccessStr;
+
+ if (TypeNameIndex == AccessIndices.size() - 1)
+ AccessStr = "0:" + AccessStr;
+
+ // Access key is the type name + access string, uniquely identifying
+ // one kernel memory access.
+ AccessKey = LastTypeName + ":" + AccessStr;
+
+ return Base;
+}
+
+/// Call/Kind is the base preserve_*_access_index() call. Attempts to do
+/// transformation to a chain of relocable GEPs.
+bool BPFAbstractMemberAccess::transformGEPChain(Module &M, CallInst *Call,
+ uint32_t Kind) {
+ std::string AccessStr, AccessKey;
+ MDNode *TypeMeta = nullptr;
+ Value *Base =
+ computeBaseAndAccessStr(Call, AccessStr, AccessKey, Kind, TypeMeta);
+ if (!Base)
+ return false;
+
+ // Do the transformation
+ // For any original GEP Call and Base %2 like
+ // %4 = bitcast %struct.net_device** %dev1 to i64*
+ // it is transformed to:
+ // %6 = load __BTF_0:sk_buff:0:0:2:0:
+ // %7 = bitcast %struct.sk_buff* %2 to i8*
+ // %8 = getelementptr i8, i8* %7, %6
+ // %9 = bitcast i8* %8 to i64*
+ // using %9 instead of %4
+ // The original Call inst is removed.
+ BasicBlock *BB = Call->getParent();
+ GlobalVariable *GV;
+
+ if (GEPGlobals.find(AccessKey) == GEPGlobals.end()) {
+ GV = new GlobalVariable(M, Type::getInt64Ty(BB->getContext()), false,
+ GlobalVariable::ExternalLinkage, NULL, AccessStr);
+ GV->addAttribute(BPFCoreSharedInfo::AmaAttr);
+ // Set the metadata (debuginfo types) for the global.
+ if (TypeMeta)
+ GV->setMetadata(LLVMContext::MD_preserve_access_index, TypeMeta);
+ GEPGlobals[AccessKey] = GV;
+ } else {
+ GV = GEPGlobals[AccessKey];
+ }
+
+ // Load the global variable.
+ auto *LDInst = new LoadInst(Type::getInt64Ty(BB->getContext()), GV);
+ BB->getInstList().insert(Call->getIterator(), LDInst);
+
+ // Generate a BitCast
+ auto *BCInst = new BitCastInst(Base, Type::getInt8PtrTy(BB->getContext()));
+ BB->getInstList().insert(Call->getIterator(), BCInst);
+
+ // Generate a GetElementPtr
+ auto *GEP = GetElementPtrInst::Create(Type::getInt8Ty(BB->getContext()),
+ BCInst, LDInst);
+ BB->getInstList().insert(Call->getIterator(), GEP);
+
+ // Generate a BitCast
+ auto *BCInst2 = new BitCastInst(GEP, Call->getType());
+ BB->getInstList().insert(Call->getIterator(), BCInst2);
+
+ Call->replaceAllUsesWith(BCInst2);
+ Call->eraseFromParent();
+
+ return true;
+}
+
+bool BPFAbstractMemberAccess::doTransformation(Module &M) {
+ bool Transformed = false;
+
+ for (Function &F : M) {
+ // Collect PreserveDIAccessIndex Intrinsic call chains.
+ // The call chains will be used to generate the access
+ // patterns similar to GEP.
+ collectAICallChains(M, F);
+
+ for (auto &C : BaseAICalls)
+ Transformed = transformGEPChain(M, C.first, C.second) || Transformed;
+ }
+
+ return removePreserveAccessIndexIntrinsic(M) || Transformed;
+}
diff --git a/llvm/lib/Target/BPF/BPFAsmPrinter.cpp b/llvm/lib/Target/BPF/BPFAsmPrinter.cpp
index 129a8c0704d..e61e7346805 100644
--- a/llvm/lib/Target/BPF/BPFAsmPrinter.cpp
+++ b/llvm/lib/Target/BPF/BPFAsmPrinter.cpp
@@ -38,7 +38,7 @@ class BPFAsmPrinter : public AsmPrinter {
public:
explicit BPFAsmPrinter(TargetMachine &TM,
std::unique_ptr<MCStreamer> Streamer)
- : AsmPrinter(TM, std::move(Streamer)) {}
+ : AsmPrinter(TM, std::move(Streamer)), BTF(nullptr) {}
StringRef getPassName() const override { return "BPF Assembly Printer"; }
bool doInitialization(Module &M) override;
@@ -49,6 +49,9 @@ public:
const char *ExtraCode, raw_ostream &O) override;
void EmitInstruction(const MachineInstr *MI) override;
+
+private:
+ BTFDebug *BTF;
};
} // namespace
@@ -57,8 +60,10 @@ bool BPFAsmPrinter::doInitialization(Module &M) {
// Only emit BTF when debuginfo available.
if (MAI->doesSupportDebugInformation() && !empty(M.debug_compile_units())) {
- Handlers.emplace_back(llvm::make_unique<BTFDebug>(this), "emit",
- "Debug Info Emission", "BTF", "BTF Emission");
+ BTF = new BTFDebug(this);
+ Handlers.push_back(HandlerInfo(std::unique_ptr<BTFDebug>(BTF), "emit",
+ "Debug Info Emission", "BTF",
+ "BTF Emission"));
}
return false;
@@ -133,11 +138,12 @@ bool BPFAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
}
void BPFAsmPrinter::EmitInstruction(const MachineInstr *MI) {
-
- BPFMCInstLower MCInstLowering(OutContext, *this);
-
MCInst TmpInst;
- MCInstLowering.Lower(MI, TmpInst);
+
+ if (!BTF || !BTF->InstLower(MI, TmpInst)) {
+ BPFMCInstLower MCInstLowering(OutContext, *this);
+ MCInstLowering.Lower(MI, TmpInst);
+ }
EmitToStreamer(*OutStreamer, TmpInst);
}
diff --git a/llvm/lib/Target/BPF/BPFCORE.h b/llvm/lib/Target/BPF/BPFCORE.h
new file mode 100644
index 00000000000..e0950d95f8d
--- /dev/null
+++ b/llvm/lib/Target/BPF/BPFCORE.h
@@ -0,0 +1,24 @@
+//===- BPFCORE.h - Common info for Compile-Once Run-EveryWhere -*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_BPF_BPFCORE_H
+#define LLVM_LIB_TARGET_BPF_BPFCORE_H
+
+namespace llvm {
+
+class BPFCoreSharedInfo {
+public:
+ /// The attribute attached to globals representing a member offset
+ static const std::string AmaAttr;
+ /// The section name to identify a patchable external global
+ static const std::string PatchableExtSecName;
+};
+
+} // namespace llvm
+
+#endif
diff --git a/llvm/lib/Target/BPF/BPFMISimplifyPatchable.cpp b/llvm/lib/Target/BPF/BPFMISimplifyPatchable.cpp
new file mode 100644
index 00000000000..e9114d7187e
--- /dev/null
+++ b/llvm/lib/Target/BPF/BPFMISimplifyPatchable.cpp
@@ -0,0 +1,163 @@
+//===----- BPFMISimplifyPatchable.cpp - MI Simplify Patchable Insts -------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This pass targets a subset of instructions like below
+// ld_imm64 r1, @global
+// ldd r2, r1, 0
+// add r3, struct_base_reg, r2
+//
+// Here @global should either present a AMA (abstruct member access) or
+// a patchable extern variable. And these two kinds of accesses
+// are subject to bpf load time patching. After this pass, the
+// code becomes
+// ld_imm64 r1, @global
+// add r3, struct_base_reg, r1
+//
+// Eventually, at BTF output stage, a relocation record will be generated
+// for ld_imm64 which should be replaced later by bpf loader:
+// r1 = <calculated offset> or <to_be_patched_extern_val>
+// add r3, struct_base_reg, r1
+// or
+// ld_imm64 r1, <to_be_patched_extern_val>
+// add r3, struct_base_reg, r1
+//
+//===----------------------------------------------------------------------===//
+
+#include "BPF.h"
+#include "BPFCORE.h"
+#include "BPFInstrInfo.h"
+#include "BPFTargetMachine.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "bpf-mi-simplify-patchable"
+
+namespace {
+
+struct BPFMISimplifyPatchable : public MachineFunctionPass {
+
+ static char ID;
+ const BPFInstrInfo *TII;
+ MachineFunction *MF;
+
+ BPFMISimplifyPatchable() : MachineFunctionPass(ID) {
+ initializeBPFMISimplifyPatchablePass(*PassRegistry::getPassRegistry());
+ }
+
+private:
+ // Initialize class variables.
+ void initialize(MachineFunction &MFParm);
+
+ bool removeLD(void);
+
+public:
+ // Main entry point for this pass.
+ bool runOnMachineFunction(MachineFunction &MF) override {
+ if (!skipFunction(MF.getFunction())) {
+ initialize(MF);
+ }
+ return removeLD();
+ }
+};
+
+// Initialize class variables.
+void BPFMISimplifyPatchable::initialize(MachineFunction &MFParm) {
+ MF = &MFParm;
+ TII = MF->getSubtarget<BPFSubtarget>().getInstrInfo();
+ LLVM_DEBUG(dbgs() << "*** BPF simplify patchable insts pass ***\n\n");
+}
+
+/// Remove unneeded Load instructions.
+bool BPFMISimplifyPatchable::removeLD() {
+ MachineRegisterInfo *MRI = &MF->getRegInfo();
+ MachineInstr *ToErase = nullptr;
+ bool Changed = false;
+
+ for (MachineBasicBlock &MBB : *MF) {
+ for (MachineInstr &MI : MBB) {
+ if (ToErase) {
+ ToErase->eraseFromParent();
+ ToErase = nullptr;
+ }
+
+ // Ensure the register format is LOAD <reg>, <reg>, 0
+ if (MI.getOpcode() != BPF::LDD && MI.getOpcode() != BPF::LDW &&
+ MI.getOpcode() != BPF::LDH && MI.getOpcode() != BPF::LDB &&
+ MI.getOpcode() != BPF::LDW32 && MI.getOpcode() != BPF::LDH32 &&
+ MI.getOpcode() != BPF::LDB32)
+ continue;
+
+ if (!MI.getOperand(0).isReg() || !MI.getOperand(1).isReg())
+ continue;
+
+ if (!MI.getOperand(2).isImm() || MI.getOperand(2).getImm())
+ continue;
+
+ unsigned DstReg = MI.getOperand(0).getReg();
+ unsigned SrcReg = MI.getOperand(1).getReg();
+ int64_t ImmVal = MI.getOperand(2).getImm();
+
+ MachineInstr *DefInst = MRI->getUniqueVRegDef(SrcReg);
+ if (!DefInst)
+ continue;
+
+ bool IsCandidate = false;
+ if (DefInst->getOpcode() == BPF::LD_imm64) {
+ const MachineOperand &MO = DefInst->getOperand(1);
+ if (MO.isGlobal()) {
+ const GlobalValue *GVal = MO.getGlobal();
+ auto *GVar = dyn_cast<GlobalVariable>(GVal);
+ if (GVar) {
+ // Global variables representing structure offset or
+ // patchable extern globals.
+ if (GVar->hasAttribute(BPFCoreSharedInfo::AmaAttr)) {
+ assert(ImmVal == 0);
+ IsCandidate = true;
+ } else if (!GVar->hasInitializer() && GVar->hasExternalLinkage() &&
+ GVar->getSection() ==
+ BPFCoreSharedInfo::PatchableExtSecName) {
+ if (ImmVal == 0)
+ IsCandidate = true;
+ else
+ errs() << "WARNING: unhandled patchable extern "
+ << GVar->getName() << " with load offset " << ImmVal
+ << "\n";
+ }
+ }
+ }
+ }
+
+ if (!IsCandidate)
+ continue;
+
+ auto Begin = MRI->use_begin(DstReg), End = MRI->use_end();
+ decltype(End) NextI;
+ for (auto I = Begin; I != End; I = NextI) {
+ NextI = std::next(I);
+ I->setReg(SrcReg);
+ }
+
+ ToErase = &MI;
+ Changed = true;
+ }
+ }
+
+ return Changed;
+}
+
+} // namespace
+
+INITIALIZE_PASS(BPFMISimplifyPatchable, DEBUG_TYPE,
+ "BPF PreEmit SimplifyPatchable", false, false)
+
+char BPFMISimplifyPatchable::ID = 0;
+FunctionPass *llvm::createBPFMISimplifyPatchablePass() {
+ return new BPFMISimplifyPatchable();
+}
diff --git a/llvm/lib/Target/BPF/BPFTargetMachine.cpp b/llvm/lib/Target/BPF/BPFTargetMachine.cpp
index e5d2e72e451..24c0ff0f7f1 100644
--- a/llvm/lib/Target/BPF/BPFTargetMachine.cpp
+++ b/llvm/lib/Target/BPF/BPFTargetMachine.cpp
@@ -34,6 +34,7 @@ extern "C" void LLVMInitializeBPFTarget() {
RegisterTargetMachine<BPFTargetMachine> Z(getTheBPFTarget());
PassRegistry &PR = *PassRegistry::getPassRegistry();
+ initializeBPFAbstractMemberAccessPass(PR);
initializeBPFMIPeepholePass(PR);
}
@@ -68,6 +69,7 @@ BPFTargetMachine::BPFTargetMachine(const Target &T, const Triple &TT,
static_cast<BPFMCAsmInfo *>(const_cast<MCAsmInfo *>(AsmInfo.get()));
MAI->setDwarfUsesRelocationsAcrossSections(!Subtarget.getUseDwarfRIS());
}
+
namespace {
// BPF Code Generator Pass Configuration Options.
class BPFPassConfig : public TargetPassConfig {
@@ -79,6 +81,7 @@ public:
return getTM<BPFTargetMachine>();
}
+ void addIRPasses() override;
bool addInstSelector() override;
void addMachineSSAOptimization() override;
void addPreEmitPass() override;
@@ -89,6 +92,13 @@ TargetPassConfig *BPFTargetMachine::createPassConfig(PassManagerBase &PM) {
return new BPFPassConfig(*this, PM);
}
+void BPFPassConfig::addIRPasses() {
+
+ addPass(createBPFAbstractMemberAccess());
+
+ TargetPassConfig::addIRPasses();
+}
+
// Install an instruction selector pass using
// the ISelDag to gen BPF code.
bool BPFPassConfig::addInstSelector() {
@@ -98,6 +108,8 @@ bool BPFPassConfig::addInstSelector() {
}
void BPFPassConfig::addMachineSSAOptimization() {
+ addPass(createBPFMISimplifyPatchablePass());
+
// The default implementation must be called first as we want eBPF
// Peephole ran at last.
TargetPassConfig::addMachineSSAOptimization();
diff --git a/llvm/lib/Target/BPF/BTF.h b/llvm/lib/Target/BPF/BTF.h
index 23af0f07b4a..ad56716710a 100644
--- a/llvm/lib/Target/BPF/BTF.h
+++ b/llvm/lib/Target/BPF/BTF.h
@@ -17,7 +17,7 @@
///
/// The binary layout for .BTF.ext section:
/// struct ExtHeader
-/// FuncInfo and LineInfo subsections
+/// FuncInfo, LineInfo, OffsetReloc and ExternReloc subsections
/// The FuncInfo subsection is defined as below:
/// BTFFuncInfo Size
/// struct SecFuncInfo for ELF section #1
@@ -32,6 +32,20 @@
/// struct SecLineInfo for ELF section #2
/// A number of struct BPFLineInfo for ELF section #2
/// ...
+/// The OffsetReloc subsection is defined as below:
+/// BPFOffsetReloc Size
+/// struct SecOffsetReloc for ELF section #1
+/// A number of struct BPFOffsetReloc for ELF section #1
+/// struct SecOffsetReloc for ELF section #2
+/// A number of struct BPFOffsetReloc for ELF section #2
+/// ...
+/// The ExternReloc subsection is defined as below:
+/// BPFExternReloc Size
+/// struct SecExternReloc for ELF section #1
+/// A number of struct BPFExternReloc for ELF section #1
+/// struct SecExternReloc for ELF section #2
+/// A number of struct BPFExternReloc for ELF section #2
+/// ...
///
/// The section formats are also defined at
/// https://github.com/torvalds/linux/blob/master/include/uapi/linux/btf.h
@@ -49,7 +63,7 @@ enum : uint32_t { MAGIC = 0xeB9F, VERSION = 1 };
/// Sizes in bytes of various things in the BTF format.
enum {
HeaderSize = 24,
- ExtHeaderSize = 24,
+ ExtHeaderSize = 40,
CommonTypeSize = 12,
BTFArraySize = 12,
BTFEnumSize = 8,
@@ -58,8 +72,12 @@ enum {
BTFDataSecVarSize = 12,
SecFuncInfoSize = 8,
SecLineInfoSize = 8,
+ SecOffsetRelocSize = 8,
+ SecExternRelocSize = 8,
BPFFuncInfoSize = 8,
- BPFLineInfoSize = 16
+ BPFLineInfoSize = 16,
+ BPFOffsetRelocSize = 12,
+ BPFExternRelocSize = 8,
};
/// The .BTF section header definition.
@@ -191,10 +209,14 @@ struct ExtHeader {
uint8_t Flags;
uint32_t HdrLen;
- uint32_t FuncInfoOff; ///< Offset of func info section
- uint32_t FuncInfoLen; ///< Length of func info section
- uint32_t LineInfoOff; ///< Offset of line info section
- uint32_t LineInfoLen; ///< Length of line info section
+ uint32_t FuncInfoOff; ///< Offset of func info section
+ uint32_t FuncInfoLen; ///< Length of func info section
+ uint32_t LineInfoOff; ///< Offset of line info section
+ uint32_t LineInfoLen; ///< Length of line info section
+ uint32_t OffsetRelocOff; ///< Offset of offset reloc section
+ uint32_t OffsetRelocLen; ///< Length of offset reloc section
+ uint32_t ExternRelocOff; ///< Offset of extern reloc section
+ uint32_t ExternRelocLen; ///< Length of extern reloc section
};
/// Specifying one function info.
@@ -220,10 +242,35 @@ struct BPFLineInfo {
/// Specifying line info's in one section.
struct SecLineInfo {
- uint32_t SecNameOff; ///< Section name index in the .BTF string tble
+ uint32_t SecNameOff; ///< Section name index in the .BTF string table
uint32_t NumLineInfo; ///< Number of line info's in this section
};
+/// Specifying one offset relocation.
+struct BPFOffsetReloc {
+ uint32_t InsnOffset; ///< Byte offset in this section
+ uint32_t TypeID; ///< TypeID for the relocation
+ uint32_t OffsetNameOff; ///< The string to traverse types
+};
+
+/// Specifying offset relocation's in one section.
+struct SecOffsetReloc {
+ uint32_t SecNameOff; ///< Section name index in the .BTF string table
+ uint32_t NumOffsetReloc; ///< Number of offset reloc's in this section
+};
+
+/// Specifying one offset relocation.
+struct BPFExternReloc {
+ uint32_t InsnOffset; ///< Byte offset in this section
+ uint32_t ExternNameOff; ///< The string for external variable
+};
+
+/// Specifying extern relocation's in one section.
+struct SecExternReloc {
+ uint32_t SecNameOff; ///< Section name index in the .BTF string table
+ uint32_t NumExternReloc; ///< Number of extern reloc's in this section
+};
+
} // End namespace BTF.
} // End namespace llvm.
diff --git a/llvm/lib/Target/BPF/BTFDebug.cpp b/llvm/lib/Target/BPF/BTFDebug.cpp
index 1442dc3123e..fa35c6619e2 100644
--- a/llvm/lib/Target/BPF/BTFDebug.cpp
+++ b/llvm/lib/Target/BPF/BTFDebug.cpp
@@ -11,6 +11,9 @@
//===----------------------------------------------------------------------===//
#include "BTFDebug.h"
+#include "BPF.h"
+#include "BPFCORE.h"
+#include "MCTargetDesc/BPFMCTargetDesc.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
@@ -37,8 +40,9 @@ void BTFTypeBase::emitType(MCStreamer &OS) {
OS.EmitIntValue(BTFType.Size, 4);
}
-BTFTypeDerived::BTFTypeDerived(const DIDerivedType *DTy, unsigned Tag)
- : DTy(DTy) {
+BTFTypeDerived::BTFTypeDerived(const DIDerivedType *DTy, unsigned Tag,
+ bool NeedsFixup)
+ : DTy(DTy), NeedsFixup(NeedsFixup) {
switch (Tag) {
case dwarf::DW_TAG_pointer_type:
Kind = BTF::BTF_KIND_PTR;
@@ -62,8 +66,15 @@ BTFTypeDerived::BTFTypeDerived(const DIDerivedType *DTy, unsigned Tag)
}
void BTFTypeDerived::completeType(BTFDebug &BDebug) {
+ if (IsCompleted)
+ return;
+ IsCompleted = true;
+
BTFType.NameOff = BDebug.addString(DTy->getName());
+ if (NeedsFixup)
+ return;
+
// The base type for PTR/CONST/VOLATILE could be void.
const DIType *ResolvedType = DTy->getBaseType();
if (!ResolvedType) {
@@ -78,6 +89,10 @@ void BTFTypeDerived::completeType(BTFDebug &BDebug) {
void BTFTypeDerived::emitType(MCStreamer &OS) { BTFTypeBase::emitType(OS); }
+void BTFTypeDerived::setPointeeType(uint32_t PointeeType) {
+ BTFType.Type = PointeeType;
+}
+
/// Represent a struct/union forward declaration.
BTFTypeFwd::BTFTypeFwd(StringRef Name, bool IsUnion) : Name(Name) {
Kind = BTF::BTF_KIND_FWD;
@@ -86,6 +101,10 @@ BTFTypeFwd::BTFTypeFwd(StringRef Name, bool IsUnion) : Name(Name) {
}
void BTFTypeFwd::completeType(BTFDebug &BDebug) {
+ if (IsCompleted)
+ return;
+ IsCompleted = true;
+
BTFType.NameOff = BDebug.addString(Name);
}
@@ -119,6 +138,10 @@ BTFTypeInt::BTFTypeInt(uint32_t Encoding, uint32_t SizeInBits,
}
void BTFTypeInt::completeType(BTFDebug &BDebug) {
+ if (IsCompleted)
+ return;
+ IsCompleted = true;
+
BTFType.NameOff = BDebug.addString(Name);
}
@@ -135,6 +158,10 @@ BTFTypeEnum::BTFTypeEnum(const DICompositeType *ETy, uint32_t VLen) : ETy(ETy) {
}
void BTFTypeEnum::completeType(BTFDebug &BDebug) {
+ if (IsCompleted)
+ return;
+ IsCompleted = true;
+
BTFType.NameOff = BDebug.addString(ETy->getName());
DINodeArray Elements = ETy->getElements();
@@ -157,7 +184,9 @@ void BTFTypeEnum::emitType(MCStreamer &OS) {
}
}
-BTFTypeArray::BTFTypeArray(uint32_t ElemTypeId, uint32_t NumElems) {
+BTFTypeArray::BTFTypeArray(uint32_t ElemTypeId, uint32_t ElemSize,
+ uint32_t NumElems)
+ : ElemSize(ElemSize) {
Kind = BTF::BTF_KIND_ARRAY;
BTFType.NameOff = 0;
BTFType.Info = Kind << 24;
@@ -169,6 +198,9 @@ BTFTypeArray::BTFTypeArray(uint32_t ElemTypeId, uint32_t NumElems) {
/// Represent a BTF array.
void BTFTypeArray::completeType(BTFDebug &BDebug) {
+ if (IsCompleted)
+ return;
+ IsCompleted = true;
// The IR does not really have a type for the index.
// A special type for array index should have been
@@ -184,6 +216,12 @@ void BTFTypeArray::emitType(MCStreamer &OS) {
OS.EmitIntValue(ArrayInfo.Nelems, 4);
}
+void BTFTypeArray::getLocInfo(uint32_t Loc, uint32_t &LocOffset,
+ uint32_t &ElementTypeId) {
+ ElementTypeId = ArrayInfo.ElemType;
+ LocOffset = Loc * ElemSize;
+}
+
/// Represent either a struct or a union.
BTFTypeStruct::BTFTypeStruct(const DICompositeType *STy, bool IsStruct,
bool HasBitField, uint32_t Vlen)
@@ -194,6 +232,10 @@ BTFTypeStruct::BTFTypeStruct(const DICompositeType *STy, bool IsStruct,
}
void BTFTypeStruct::completeType(BTFDebug &BDebug) {
+ if (IsCompleted)
+ return;
+ IsCompleted = true;
+
BTFType.NameOff = BDebug.addString(STy->getName());
// Add struct/union members.
@@ -224,6 +266,17 @@ void BTFTypeStruct::emitType(MCStreamer &OS) {
}
}
+std::string BTFTypeStruct::getName() { return STy->getName(); }
+
+void BTFTypeStruct::getMemberInfo(uint32_t Loc, uint32_t &MemberOffset,
+ uint32_t &MemberType) {
+ MemberType = Members[Loc].Type;
+ MemberOffset =
+ HasBitField ? Members[Loc].Offset & 0xffffff : Members[Loc].Offset;
+}
+
+uint32_t BTFTypeStruct::getStructSize() { return STy->getSizeInBits() >> 3; }
+
/// The Func kind represents both subprogram and pointee of function
/// pointers. If the FuncName is empty, it represents a pointee of function
/// pointer. Otherwise, it represents a subprogram. The func arg names
@@ -238,6 +291,10 @@ BTFTypeFuncProto::BTFTypeFuncProto(
}
void BTFTypeFuncProto::completeType(BTFDebug &BDebug) {
+ if (IsCompleted)
+ return;
+ IsCompleted = true;
+
DITypeRefArray Elements = STy->getTypeArray();
auto RetType = Elements[0];
BTFType.Type = RetType ? BDebug.getTypeId(RetType) : 0;
@@ -275,6 +332,10 @@ BTFTypeFunc::BTFTypeFunc(StringRef FuncName, uint32_t ProtoTypeId)
}
void BTFTypeFunc::completeType(BTFDebug &BDebug) {
+ if (IsCompleted)
+ return;
+ IsCompleted = true;
+
BTFType.NameOff = BDebug.addString(Name);
}
@@ -335,7 +396,8 @@ uint32_t BTFStringTable::addString(StringRef S) {
BTFDebug::BTFDebug(AsmPrinter *AP)
: DebugHandlerBase(AP), OS(*Asm->OutStreamer), SkipInstruction(false),
- LineInfoGenerated(false), SecNameOff(0), ArrayIndexTypeId(0) {
+ LineInfoGenerated(false), SecNameOff(0), ArrayIndexTypeId(0),
+ MapDefNotCollected(true) {
addString("\0");
}
@@ -417,6 +479,7 @@ void BTFDebug::visitStructType(const DICompositeType *CTy, bool IsStruct,
auto TypeEntry =
llvm::make_unique<BTFTypeStruct>(CTy, IsStruct, HasBitField, VLen);
+ StructTypes.push_back(TypeEntry.get());
TypeId = addType(std::move(TypeEntry), CTy);
// Visit all struct members.
@@ -426,11 +489,14 @@ void BTFDebug::visitStructType(const DICompositeType *CTy, bool IsStruct,
void BTFDebug::visitArrayType(const DICompositeType *CTy, uint32_t &TypeId) {
// Visit array element type.
- uint32_t ElemTypeId;
- visitTypeEntry(CTy->getBaseType(), ElemTypeId);
+ uint32_t ElemTypeId, ElemSize;
+ const DIType *ElemType = CTy->getBaseType();
+ visitTypeEntry(ElemType, ElemTypeId, false, false);
+ ElemSize = ElemType->getSizeInBits() >> 3;
if (!CTy->getSizeInBits()) {
- auto TypeEntry = llvm::make_unique<BTFTypeArray>(ElemTypeId, 0);
+ auto TypeEntry = llvm::make_unique<BTFTypeArray>(ElemTypeId, 0, 0);
+ ArrayTypes.push_back(TypeEntry.get());
ElemTypeId = addType(std::move(TypeEntry), CTy);
} else {
// Visit array dimensions.
@@ -442,11 +508,14 @@ void BTFDebug::visitArrayType(const DICompositeType *CTy, uint32_t &TypeId) {
auto *CI = SR->getCount().dyn_cast<ConstantInt *>();
int64_t Count = CI->getSExtValue();
- auto TypeEntry = llvm::make_unique<BTFTypeArray>(ElemTypeId, Count);
+ auto TypeEntry =
+ llvm::make_unique<BTFTypeArray>(ElemTypeId, ElemSize, Count);
+ ArrayTypes.push_back(TypeEntry.get());
if (I == 0)
ElemTypeId = addType(std::move(TypeEntry), CTy);
else
ElemTypeId = addType(std::move(TypeEntry));
+ ElemSize = ElemSize * Count;
}
}
}
@@ -498,13 +567,42 @@ void BTFDebug::visitCompositeType(const DICompositeType *CTy,
}
/// Handle pointer, typedef, const, volatile, restrict and member types.
-void BTFDebug::visitDerivedType(const DIDerivedType *DTy, uint32_t &TypeId) {
+void BTFDebug::visitDerivedType(const DIDerivedType *DTy, uint32_t &TypeId,
+ bool CheckPointer, bool SeenPointer) {
unsigned Tag = DTy->getTag();
+ /// Try to avoid chasing pointees, esp. structure pointees which may
+ /// unnecessary bring in a lot of types.
+ if (CheckPointer && !SeenPointer) {
+ SeenPointer = Tag == dwarf::DW_TAG_pointer_type;
+ }
+
+ if (CheckPointer && SeenPointer) {
+ const DIType *Base = DTy->getBaseType();
+ if (Base) {
+ if (const auto *CTy = dyn_cast<DICompositeType>(Base)) {
+ auto CTag = CTy->getTag();
+ if ((CTag == dwarf::DW_TAG_structure_type ||
+ CTag == dwarf::DW_TAG_union_type) &&
+ !CTy->isForwardDecl()) {
+ /// Find a candidate, generate a fixup. Later on the struct/union
+ /// pointee type will be replaced with either a real type or
+ /// a forward declaration.
+ auto TypeEntry = llvm::make_unique<BTFTypeDerived>(DTy, Tag, true);
+ auto &Fixup = FixupDerivedTypes[CTy->getName()];
+ Fixup.first = CTag == dwarf::DW_TAG_union_type;
+ Fixup.second.push_back(TypeEntry.get());
+ TypeId = addType(std::move(TypeEntry), DTy);
+ return;
+ }
+ }
+ }
+ }
+
if (Tag == dwarf::DW_TAG_pointer_type || Tag == dwarf::DW_TAG_typedef ||
Tag == dwarf::DW_TAG_const_type || Tag == dwarf::DW_TAG_volatile_type ||
Tag == dwarf::DW_TAG_restrict_type) {
- auto TypeEntry = llvm::make_unique<BTFTypeDerived>(DTy, Tag);
+ auto TypeEntry = llvm::make_unique<BTFTypeDerived>(DTy, Tag, false);
TypeId = addType(std::move(TypeEntry), DTy);
} else if (Tag != dwarf::DW_TAG_member) {
return;
@@ -513,10 +611,14 @@ void BTFDebug::visitDerivedType(const DIDerivedType *DTy, uint32_t &TypeId) {
// Visit base type of pointer, typedef, const, volatile, restrict or
// struct/union member.
uint32_t TempTypeId = 0;
- visitTypeEntry(DTy->getBaseType(), TempTypeId);
+ if (Tag == dwarf::DW_TAG_member)
+ visitTypeEntry(DTy->getBaseType(), TempTypeId, true, false);
+ else
+ visitTypeEntry(DTy->getBaseType(), TempTypeId, CheckPointer, SeenPointer);
}
-void BTFDebug::visitTypeEntry(const DIType *Ty, uint32_t &TypeId) {
+void BTFDebug::visitTypeEntry(const DIType *Ty, uint32_t &TypeId,
+ bool CheckPointer, bool SeenPointer) {
if (!Ty || DIToIdMap.find(Ty) != DIToIdMap.end()) {
TypeId = DIToIdMap[Ty];
return;
@@ -530,14 +632,52 @@ void BTFDebug::visitTypeEntry(const DIType *Ty, uint32_t &TypeId) {
else if (const auto *CTy = dyn_cast<DICompositeType>(Ty))
visitCompositeType(CTy, TypeId);
else if (const auto *DTy = dyn_cast<DIDerivedType>(Ty))
- visitDerivedType(DTy, TypeId);
+ visitDerivedType(DTy, TypeId, CheckPointer, SeenPointer);
else
llvm_unreachable("Unknown DIType");
}
void BTFDebug::visitTypeEntry(const DIType *Ty) {
uint32_t TypeId;
- visitTypeEntry(Ty, TypeId);
+ visitTypeEntry(Ty, TypeId, false, false);
+}
+
+void BTFDebug::visitMapDefType(const DIType *Ty, uint32_t &TypeId) {
+ if (!Ty || DIToIdMap.find(Ty) != DIToIdMap.end()) {
+ TypeId = DIToIdMap[Ty];
+ return;
+ }
+
+ // MapDef type is a struct type
+ const auto *CTy = dyn_cast<DICompositeType>(Ty);
+ if (!CTy)
+ return;
+
+ auto Tag = CTy->getTag();
+ if (Tag != dwarf::DW_TAG_structure_type || CTy->isForwardDecl())
+ return;
+
+ // Record this type
+ const DINodeArray Elements = CTy->getElements();
+ bool HasBitField = false;
+ for (const auto *Element : Elements) {
+ auto E = cast<DIDerivedType>(Element);
+ if (E->isBitField()) {
+ HasBitField = true;
+ break;
+ }
+ }
+
+ auto TypeEntry =
+ llvm::make_unique<BTFTypeStruct>(CTy, true, HasBitField, Elements.size());
+ StructTypes.push_back(TypeEntry.get());
+ TypeId = addType(std::move(TypeEntry), CTy);
+
+ // Visit all struct members
+ for (const auto *Element : Elements) {
+ const auto *MemberType = cast<DIDerivedType>(Element);
+ visitTypeEntry(MemberType->getBaseType());
+ }
}
/// Read file contents from the actual file or from the source
@@ -635,7 +775,8 @@ void BTFDebug::emitBTFSection() {
void BTFDebug::emitBTFExtSection() {
// Do not emit section if empty FuncInfoTable and LineInfoTable.
- if (!FuncInfoTable.size() && !LineInfoTable.size())
+ if (!FuncInfoTable.size() && !LineInfoTable.size() &&
+ !OffsetRelocTable.size() && !ExternRelocTable.size())
return;
MCContext &Ctx = OS.getContext();
@@ -647,6 +788,8 @@ void BTFDebug::emitBTFExtSection() {
// Account for FuncInfo/LineInfo record size as well.
uint32_t FuncLen = 4, LineLen = 4;
+ // Do not account for optional OffsetReloc/ExternReloc.
+ uint32_t OffsetRelocLen = 0, ExternRelocLen = 0;
for (const auto &FuncSec : FuncInfoTable) {
FuncLen += BTF::SecFuncInfoSize;
FuncLen += FuncSec.second.size() * BTF::BPFFuncInfoSize;
@@ -655,11 +798,28 @@ void BTFDebug::emitBTFExtSection() {
LineLen += BTF::SecLineInfoSize;
LineLen += LineSec.second.size() * BTF::BPFLineInfoSize;
}
+ for (const auto &OffsetRelocSec : OffsetRelocTable) {
+ OffsetRelocLen += BTF::SecOffsetRelocSize;
+ OffsetRelocLen += OffsetRelocSec.second.size() * BTF::BPFOffsetRelocSize;
+ }
+ for (const auto &ExternRelocSec : ExternRelocTable) {
+ ExternRelocLen += BTF::SecExternRelocSize;
+ ExternRelocLen += ExternRelocSec.second.size() * BTF::BPFExternRelocSize;
+ }
+
+ if (OffsetRelocLen)
+ OffsetRelocLen += 4;
+ if (ExternRelocLen)
+ ExternRelocLen += 4;
OS.EmitIntValue(0, 4);
OS.EmitIntValue(FuncLen, 4);
OS.EmitIntValue(FuncLen, 4);
OS.EmitIntValue(LineLen, 4);
+ OS.EmitIntValue(FuncLen + LineLen, 4);
+ OS.EmitIntValue(OffsetRelocLen, 4);
+ OS.EmitIntValue(FuncLen + LineLen + OffsetRelocLen, 4);
+ OS.EmitIntValue(ExternRelocLen, 4);
// Emit func_info table.
OS.AddComment("FuncInfo");
@@ -692,6 +852,39 @@ void BTFDebug::emitBTFExtSection() {
OS.EmitIntValue(LineInfo.LineNum << 10 | LineInfo.ColumnNum, 4);
}
}
+
+ // Emit offset reloc table.
+ if (OffsetRelocLen) {
+ OS.AddComment("OffsetReloc");
+ OS.EmitIntValue(BTF::BPFOffsetRelocSize, 4);
+ for (const auto &OffsetRelocSec : OffsetRelocTable) {
+ OS.AddComment("Offset reloc section string offset=" +
+ std::to_string(OffsetRelocSec.first));
+ OS.EmitIntValue(OffsetRelocSec.first, 4);
+ OS.EmitIntValue(OffsetRelocSec.second.size(), 4);
+ for (const auto &OffsetRelocInfo : OffsetRelocSec.second) {
+ Asm->EmitLabelReference(OffsetRelocInfo.Label, 4);
+ OS.EmitIntValue(OffsetRelocInfo.TypeID, 4);
+ OS.EmitIntValue(OffsetRelocInfo.OffsetNameOff, 4);
+ }
+ }
+ }
+
+ // Emit extern reloc table.
+ if (ExternRelocLen) {
+ OS.AddComment("ExternReloc");
+ OS.EmitIntValue(BTF::BPFExternRelocSize, 4);
+ for (const auto &ExternRelocSec : ExternRelocTable) {
+ OS.AddComment("Extern reloc section string offset=" +
+ std::to_string(ExternRelocSec.first));
+ OS.EmitIntValue(ExternRelocSec.first, 4);
+ OS.EmitIntValue(ExternRelocSec.second.size(), 4);
+ for (const auto &ExternRelocInfo : ExternRelocSec.second) {
+ Asm->EmitLabelReference(ExternRelocInfo.Label, 4);
+ OS.EmitIntValue(ExternRelocInfo.ExternNameOff, 4);
+ }
+ }
+ }
}
void BTFDebug::beginFunctionImpl(const MachineFunction *MF) {
@@ -704,6 +897,30 @@ void BTFDebug::beginFunctionImpl(const MachineFunction *MF) {
}
SkipInstruction = false;
+ // Collect MapDef types. Map definition needs to collect
+ // pointee types. Do it first. Otherwise, for the following
+ // case:
+ // struct m { ...};
+ // struct t {
+ // struct m *key;
+ // };
+ // foo(struct t *arg);
+ //
+ // struct mapdef {
+ // ...
+ // struct m *key;
+ // ...
+ // } __attribute__((section(".maps"))) hash_map;
+ //
+ // If subroutine foo is traversed first, a type chain
+ // "ptr->struct m(fwd)" will be created and later on
+ // when traversing mapdef, since "ptr->struct m" exists,
+ // the traversal of "struct m" will be omitted.
+ if (MapDefNotCollected) {
+ processGlobals(true);
+ MapDefNotCollected = false;
+ }
+
// Collect all types locally referenced in this function.
// Use RetainedNodes so we can collect all argument names
// even if the argument is not used.
@@ -728,6 +945,9 @@ void BTFDebug::beginFunctionImpl(const MachineFunction *MF) {
llvm::make_unique<BTFTypeFunc>(SP->getName(), ProtoTypeId);
uint32_t FuncTypeId = addType(std::move(FuncTypeEntry));
+ for (const auto &TypeEntry : TypeEntries)
+ TypeEntry->completeType(*this);
+
// Construct funcinfo and the first lineinfo for the function.
MCSymbol *FuncLabel = Asm->getFunctionBegin();
BTFFuncInfo FuncInfo;
@@ -750,6 +970,133 @@ void BTFDebug::endFunctionImpl(const MachineFunction *MF) {
SecNameOff = 0;
}
+/// On-demand populate struct types as requested from abstract member
+/// accessing.
+unsigned BTFDebug::populateStructType(const DIType *Ty) {
+ unsigned Id;
+ visitTypeEntry(Ty, Id, false, false);
+ for (const auto &TypeEntry : TypeEntries)
+ TypeEntry->completeType(*this);
+ return Id;
+}
+
+// Find struct/array debuginfo types given a type id.
+void BTFDebug::setTypeFromId(uint32_t TypeId, BTFTypeStruct **PrevStructType,
+ BTFTypeArray **PrevArrayType) {
+ for (const auto &StructType : StructTypes) {
+ if (StructType->getId() == TypeId) {
+ *PrevStructType = StructType;
+ return;
+ }
+ }
+ for (const auto &ArrayType : ArrayTypes) {
+ if (ArrayType->getId() == TypeId) {
+ *PrevArrayType = ArrayType;
+ return;
+ }
+ }
+}
+
+/// Generate a struct member offset relocation.
+void BTFDebug::generateOffsetReloc(const MachineInstr *MI,
+ const MCSymbol *ORSym, DIType *RootTy,
+ StringRef AccessPattern) {
+ BTFTypeStruct *PrevStructType = nullptr;
+ BTFTypeArray *PrevArrayType = nullptr;
+ unsigned RootId = populateStructType(RootTy);
+ setTypeFromId(RootId, &PrevStructType, &PrevArrayType);
+ unsigned RootTySize = PrevStructType->getStructSize();
+
+ BTFOffsetReloc OffsetReloc;
+ OffsetReloc.Label = ORSym;
+ OffsetReloc.OffsetNameOff = addString(AccessPattern.drop_back());
+ OffsetReloc.TypeID = RootId;
+
+ uint32_t Start = 0, End = 0, Offset = 0;
+ bool FirstAccess = true;
+ for (auto C : AccessPattern) {
+ if (C != ':') {
+ End++;
+ } else {
+ std::string SubStr = AccessPattern.substr(Start, End - Start);
+ int Loc = std::stoi(SubStr);
+
+ if (FirstAccess) {
+ Offset = Loc * RootTySize;
+ FirstAccess = false;
+ } else if (PrevStructType) {
+ uint32_t MemberOffset, MemberTypeId;
+ PrevStructType->getMemberInfo(Loc, MemberOffset, MemberTypeId);
+
+ Offset += MemberOffset >> 3;
+ PrevStructType = nullptr;
+ setTypeFromId(MemberTypeId, &PrevStructType, &PrevArrayType);
+ } else if (PrevArrayType) {
+ uint32_t LocOffset, ElementTypeId;
+ PrevArrayType->getLocInfo(Loc, LocOffset, ElementTypeId);
+
+ Offset += LocOffset;
+ PrevArrayType = nullptr;
+ setTypeFromId(ElementTypeId, &PrevStructType, &PrevArrayType);
+ }
+ Start = End + 1;
+ End = Start;
+ }
+ }
+ AccessOffsets[RootTy->getName().str() + ":" + AccessPattern.str()] = Offset;
+ OffsetRelocTable[SecNameOff].push_back(OffsetReloc);
+}
+
+void BTFDebug::processLDimm64(const MachineInstr *MI) {
+ // If the insn is an LD_imm64, the following two cases
+ // will generate an .BTF.ext record.
+ //
+ // If the insn is "r2 = LD_imm64 @__BTF_...",
+ // add this insn into the .BTF.ext OffsetReloc subsection.
+ // Relocation looks like:
+ // . SecName:
+ // . InstOffset
+ // . TypeID
+ // . OffSetNameOff
+ // Later, the insn is replaced with "r2 = <offset>"
+ // where "<offset>" equals to the offset based on current
+ // type definitions.
+ //
+ // If the insn is "r2 = LD_imm64 @VAR" and VAR is
+ // a patchable external global, add this insn into the .BTF.ext
+ // ExternReloc subsection.
+ // Relocation looks like:
+ // . SecName:
+ // . InstOffset
+ // . ExternNameOff
+ // Later, the insn is replaced with "r2 = <value>" or
+ // "LD_imm64 r2, <value>" where "<value>" = 0.
+
+ // check whether this is a candidate or not
+ const MachineOperand &MO = MI->getOperand(1);
+ if (MO.isGlobal()) {
+ const GlobalValue *GVal = MO.getGlobal();
+ auto *GVar = dyn_cast<GlobalVariable>(GVal);
+ if (GVar && GVar->hasAttribute(BPFCoreSharedInfo::AmaAttr)) {
+ MCSymbol *ORSym = OS.getContext().createTempSymbol();
+ OS.EmitLabel(ORSym);
+
+ MDNode *MDN = GVar->getMetadata(LLVMContext::MD_preserve_access_index);
+ DIType *Ty = dyn_cast<DIType>(MDN);
+ generateOffsetReloc(MI, ORSym, Ty, GVar->getName());
+ } else if (GVar && !GVar->hasInitializer() && GVar->hasExternalLinkage() &&
+ GVar->getSection() == BPFCoreSharedInfo::PatchableExtSecName) {
+ MCSymbol *ORSym = OS.getContext().createTempSymbol();
+ OS.EmitLabel(ORSym);
+
+ BTFExternReloc ExternReloc;
+ ExternReloc.Label = ORSym;
+ ExternReloc.ExternNameOff = addString(GVar->getName());
+ ExternRelocTable[SecNameOff].push_back(ExternReloc);
+ }
+ }
+}
+
void BTFDebug::beginInstruction(const MachineInstr *MI) {
DebugHandlerBase::beginInstruction(MI);
@@ -770,6 +1117,9 @@ void BTFDebug::beginInstruction(const MachineInstr *MI) {
return;
}
+ if (MI->getOpcode() == BPF::LD_imm64)
+ processLDimm64(MI);
+
// Skip this instruction if no DebugLoc or the DebugLoc
// is the same as the previous instruction.
const DebugLoc &DL = MI->getDebugLoc();
@@ -798,7 +1148,7 @@ void BTFDebug::beginInstruction(const MachineInstr *MI) {
PrevInstLoc = DL;
}
-void BTFDebug::processGlobals() {
+void BTFDebug::processGlobals(bool ProcessingMapDef) {
// Collect all types referenced by globals.
const Module *M = MMI->getModule();
for (const GlobalVariable &Global : M->globals()) {
@@ -806,11 +1156,29 @@ void BTFDebug::processGlobals() {
if (!Global.hasInitializer() && Global.hasExternalLinkage())
continue;
+ // Decide the section name.
+ StringRef SecName;
+ if (Global.hasSection()) {
+ SecName = Global.getSection();
+ } else {
+ // data, bss, or readonly sections
+ if (Global.isConstant())
+ SecName = ".rodata";
+ else
+ SecName = Global.getInitializer()->isZeroValue() ? ".bss" : ".data";
+ }
+
+ if (ProcessingMapDef != SecName.startswith(".maps"))
+ continue;
+
SmallVector<DIGlobalVariableExpression *, 1> GVs;
Global.getDebugInfo(GVs);
uint32_t GVTypeId = 0;
for (auto *GVE : GVs) {
- visitTypeEntry(GVE->getVariable()->getType(), GVTypeId);
+ if (SecName.startswith(".maps"))
+ visitMapDefType(GVE->getVariable()->getType(), GVTypeId);
+ else
+ visitTypeEntry(GVE->getVariable()->getType(), GVTypeId, false, false);
break;
}
@@ -835,18 +1203,6 @@ void BTFDebug::processGlobals() {
llvm::make_unique<BTFKindVar>(Global.getName(), GVTypeId, GVarInfo);
uint32_t VarId = addType(std::move(VarEntry));
- // Decide the section name.
- std::string SecName;
- if (Global.hasSection()) {
- SecName = Global.getSection().str();
- } else {
- // data, bss, or readonly sections
- if (Global.isConstant())
- SecName += ".rodata";
- else
- SecName += Global.getInitializer()->isZeroValue() ? ".bss" : ".data";
- }
-
// Find or create a DataSec
if (DataSecEntries.find(SecName) == DataSecEntries.end()) {
DataSecEntries[SecName] = llvm::make_unique<BTFKindDataSec>(Asm, SecName);
@@ -858,14 +1214,81 @@ void BTFDebug::processGlobals() {
DataSecEntries[SecName]->addVar(VarId, Asm->getSymbol(&Global), Size);
}
+}
+
+/// Emit proper patchable instructions.
+bool BTFDebug::InstLower(const MachineInstr *MI, MCInst &OutMI) {
+ if (MI->getOpcode() == BPF::LD_imm64) {
+ const MachineOperand &MO = MI->getOperand(1);
+ if (MO.isGlobal()) {
+ const GlobalValue *GVal = MO.getGlobal();
+ auto *GVar = dyn_cast<GlobalVariable>(GVal);
+ if (GVar && GVar->hasAttribute(BPFCoreSharedInfo::AmaAttr)) {
+ MDNode *MDN = GVar->getMetadata(LLVMContext::MD_preserve_access_index);
+ DIType *Ty = dyn_cast<DIType>(MDN);
+ std::string TypeName = Ty->getName();
+ int64_t Imm = AccessOffsets[TypeName + ":" + GVar->getName().str()];
+
+ // Emit "mov ri, <imm>" for abstract member accesses.
+ OutMI.setOpcode(BPF::MOV_ri);
+ OutMI.addOperand(MCOperand::createReg(MI->getOperand(0).getReg()));
+ OutMI.addOperand(MCOperand::createImm(Imm));
+ return true;
+ } else if (GVar && !GVar->hasInitializer() &&
+ GVar->hasExternalLinkage() &&
+ GVar->getSection() == BPFCoreSharedInfo::PatchableExtSecName) {
+ const IntegerType *IntTy = dyn_cast<IntegerType>(GVar->getValueType());
+ assert(IntTy);
+ // For patchable externals, emit "LD_imm64, ri, 0" if the external
+ // variable is 64bit width, emit "mov ri, 0" otherwise.
+ if (IntTy->getBitWidth() == 64)
+ OutMI.setOpcode(BPF::LD_imm64);
+ else
+ OutMI.setOpcode(BPF::MOV_ri);
+ OutMI.addOperand(MCOperand::createReg(MI->getOperand(0).getReg()));
+ OutMI.addOperand(MCOperand::createImm(0));
+ return true;
+ }
+ }
+ }
+ return false;
+}
+void BTFDebug::endModule() {
+ // Collect MapDef globals if not collected yet.
+ if (MapDefNotCollected) {
+ processGlobals(true);
+ MapDefNotCollected = false;
+ }
+
+ // Collect global types/variables except MapDef globals.
+ processGlobals(false);
for (auto &DataSec : DataSecEntries)
addType(std::move(DataSec.second));
-}
-void BTFDebug::endModule() {
- // Collect all global types/variables.
- processGlobals();
+ // Fixups
+ for (auto &Fixup : FixupDerivedTypes) {
+ StringRef TypeName = Fixup.first;
+ bool IsUnion = Fixup.second.first;
+
+ // Search through struct types
+ uint32_t StructTypeId = 0;
+ for (const auto &StructType : StructTypes) {
+ if (StructType->getName() == TypeName) {
+ StructTypeId = StructType->getId();
+ break;
+ }
+ }
+
+ if (StructTypeId == 0) {
+ auto FwdTypeEntry = llvm::make_unique<BTFTypeFwd>(TypeName, IsUnion);
+ StructTypeId = addType(std::move(FwdTypeEntry));
+ }
+
+ for (auto &DType : Fixup.second.second) {
+ DType->setPointeeType(StructTypeId);
+ }
+ }
// Complete BTF type cross refereences.
for (const auto &TypeEntry : TypeEntries)
diff --git a/llvm/lib/Target/BPF/BTFDebug.h b/llvm/lib/Target/BPF/BTFDebug.h
index 7d7a1d9b707..6c0cdde17d9 100644
--- a/llvm/lib/Target/BPF/BTFDebug.h
+++ b/llvm/lib/Target/BPF/BTFDebug.h
@@ -32,10 +32,12 @@ class MachineFunction;
class BTFTypeBase {
protected:
uint8_t Kind;
+ bool IsCompleted;
uint32_t Id;
struct BTF::CommonType BTFType;
public:
+ BTFTypeBase() : IsCompleted(false) {}
virtual ~BTFTypeBase() = default;
void setId(uint32_t Id) { this->Id = Id; }
uint32_t getId() { return Id; }
@@ -54,11 +56,13 @@ public:
/// volatile, typedef and restrict.
class BTFTypeDerived : public BTFTypeBase {
const DIDerivedType *DTy;
+ bool NeedsFixup;
public:
- BTFTypeDerived(const DIDerivedType *Ty, unsigned Tag);
+ BTFTypeDerived(const DIDerivedType *Ty, unsigned Tag, bool NeedsFixup);
void completeType(BTFDebug &BDebug);
void emitType(MCStreamer &OS);
+ void setPointeeType(uint32_t PointeeType);
};
/// Handle struct or union forward declaration.
@@ -100,13 +104,15 @@ public:
/// Handle array type.
class BTFTypeArray : public BTFTypeBase {
+ uint32_t ElemSize;
struct BTF::BTFArray ArrayInfo;
public:
- BTFTypeArray(uint32_t ElemTypeId, uint32_t NumElems);
+ BTFTypeArray(uint32_t ElemTypeId, uint32_t ElemSize, uint32_t NumElems);
uint32_t getSize() { return BTFTypeBase::getSize() + BTF::BTFArraySize; }
void completeType(BTFDebug &BDebug);
void emitType(MCStreamer &OS);
+ void getLocInfo(uint32_t Loc, uint32_t &LocOffset, uint32_t &ElementTypeId);
};
/// Handle struct/union type.
@@ -123,6 +129,9 @@ public:
}
void completeType(BTFDebug &BDebug);
void emitType(MCStreamer &OS);
+ std::string getName();
+ void getMemberInfo(uint32_t Loc, uint32_t &Offset, uint32_t &MemberType);
+ uint32_t getStructSize();
};
/// Handle function pointer.
@@ -218,6 +227,19 @@ struct BTFLineInfo {
uint32_t ColumnNum; ///< the column number
};
+/// Represent one offset relocation.
+struct BTFOffsetReloc {
+ const MCSymbol *Label; ///< MCSymbol identifying insn for the reloc
+ uint32_t TypeID; ///< Type ID
+ uint32_t OffsetNameOff; ///< The string to traverse types
+};
+
+/// Represent one extern relocation.
+struct BTFExternReloc {
+ const MCSymbol *Label; ///< MCSymbol identifying insn for the reloc
+ uint32_t ExternNameOff; ///< The extern variable name
+};
+
/// Collect and emit BTF information.
class BTFDebug : public DebugHandlerBase {
MCStreamer &OS;
@@ -225,14 +247,21 @@ class BTFDebug : public DebugHandlerBase {
bool LineInfoGenerated;
uint32_t SecNameOff;
uint32_t ArrayIndexTypeId;
+ bool MapDefNotCollected;
BTFStringTable StringTable;
std::vector<std::unique_ptr<BTFTypeBase>> TypeEntries;
std::unordered_map<const DIType *, uint32_t> DIToIdMap;
std::map<uint32_t, std::vector<BTFFuncInfo>> FuncInfoTable;
std::map<uint32_t, std::vector<BTFLineInfo>> LineInfoTable;
+ std::map<uint32_t, std::vector<BTFOffsetReloc>> OffsetRelocTable;
+ std::map<uint32_t, std::vector<BTFExternReloc>> ExternRelocTable;
StringMap<std::vector<std::string>> FileContent;
- std::map<std::string, std::unique_ptr<BTFKindDataSec>>
- DataSecEntries;
+ std::map<std::string, std::unique_ptr<BTFKindDataSec>> DataSecEntries;
+ std::vector<BTFTypeStruct *> StructTypes;
+ std::vector<BTFTypeArray *> ArrayTypes;
+ std::map<std::string, int64_t> AccessOffsets;
+ std::map<StringRef, std::pair<bool, std::vector<BTFTypeDerived *>>>
+ FixupDerivedTypes;
/// Add types to TypeEntries.
/// @{
@@ -245,7 +274,8 @@ class BTFDebug : public DebugHandlerBase {
/// IR type visiting functions.
/// @{
void visitTypeEntry(const DIType *Ty);
- void visitTypeEntry(const DIType *Ty, uint32_t &TypeId);
+ void visitTypeEntry(const DIType *Ty, uint32_t &TypeId, bool CheckPointer,
+ bool SeenPointer);
void visitBasicType(const DIBasicType *BTy, uint32_t &TypeId);
void visitSubroutineType(
const DISubroutineType *STy, bool ForSubprog,
@@ -258,7 +288,9 @@ class BTFDebug : public DebugHandlerBase {
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);
+ void visitDerivedType(const DIDerivedType *DTy, uint32_t &TypeId,
+ bool CheckPointer, bool SeenPointer);
+ void visitMapDefType(const DIType *Ty, uint32_t &TypeId);
/// @}
/// Get the file content for the subprogram. Certain lines of the file
@@ -270,7 +302,21 @@ class BTFDebug : public DebugHandlerBase {
uint32_t Column);
/// Generate types and variables for globals.
- void processGlobals(void);
+ void processGlobals(bool ProcessingMapDef);
+
+ /// Generate one offset relocation record.
+ void generateOffsetReloc(const MachineInstr *MI, const MCSymbol *ORSym,
+ DIType *RootTy, StringRef AccessPattern);
+
+ /// Set the to-be-traversed Struct/Array Type based on TypeId.
+ void setTypeFromId(uint32_t TypeId, BTFTypeStruct **PrevStructType,
+ BTFTypeArray **PrevArrayType);
+
+ /// Populating unprocessed struct type.
+ unsigned populateStructType(const DIType *Ty);
+
+ /// Process LD_imm64 instructions.
+ void processLDimm64(const MachineInstr *MI);
/// Emit common header of .BTF and .BTF.ext sections.
void emitCommonHeader();
@@ -291,6 +337,9 @@ protected:
public:
BTFDebug(AsmPrinter *AP);
+ ///
+ bool InstLower(const MachineInstr *MI, MCInst &OutMI);
+
/// Get the special array index type id.
uint32_t getArrayIndexTypeId() {
assert(ArrayIndexTypeId);
diff --git a/llvm/lib/Target/BPF/CMakeLists.txt b/llvm/lib/Target/BPF/CMakeLists.txt
index 37c03aa511e..42d7bf9ec8b 100644
--- a/llvm/lib/Target/BPF/CMakeLists.txt
+++ b/llvm/lib/Target/BPF/CMakeLists.txt
@@ -13,6 +13,7 @@ tablegen(LLVM BPFGenSubtargetInfo.inc -gen-subtarget)
add_public_tablegen_target(BPFCommonTableGen)
add_llvm_target(BPFCodeGen
+ BPFAbstrctMemberAccess.cpp
BPFAsmPrinter.cpp
BPFFrameLowering.cpp
BPFInstrInfo.cpp
@@ -25,6 +26,7 @@ add_llvm_target(BPFCodeGen
BPFTargetMachine.cpp
BPFMIPeephole.cpp
BPFMIChecking.cpp
+ BPFMISimplifyPatchable.cpp
BTFDebug.cpp
)
diff --git a/llvm/test/CodeGen/BPF/BTF/binary-format.ll b/llvm/test/CodeGen/BPF/BTF/binary-format.ll
index 39d699b2848..bc561560caa 100644
--- a/llvm/test/CodeGen/BPF/BTF/binary-format.ll
+++ b/llvm/test/CodeGen/BPF/BTF/binary-format.ll
@@ -15,31 +15,33 @@ entry:
; CHECK: '.BTF'
; CHECK-EL: 0x00000000 9feb0100 18000000 00000000 30000000
-; CHECK-EL: 0x00000010 30000000 33000000 2b000000 00000001
+; CHECK-EL: 0x00000010 30000000 33000000 01000000 00000001
; CHECK-EL: 0x00000020 04000000 20000001 00000000 0100000d
-; CHECK-EL: 0x00000030 01000000 2f000000 01000000 31000000
-; CHECK-EL: 0x00000040 0000000c 02000000 002e7465 7874002f
+; CHECK-EL: 0x00000030 01000000 05000000 01000000 07000000
+; CHECK-EL: 0x00000040 0000000c 02000000 00696e74 00610066
; CHECK-EB: 0x00000000 eb9f0100 00000018 00000000 00000030
-; CHECK-EB: 0x00000010 00000030 00000033 0000002b 01000000
+; CHECK-EB: 0x00000010 00000030 00000033 00000001 01000000
; CHECK-EB: 0x00000020 00000004 01000020 00000000 0d000001
-; CHECK-EB: 0x00000030 00000001 0000002f 00000001 00000031
-; CHECK-EB: 0x00000040 0c000000 00000002 002e7465 7874002f
-; CHECK: 0x00000050 746d702f 742e6300 696e7420 6628696e
-; CHECK: 0x00000060 74206129 207b2072 65747572 6e20613b
-; CHECK: 0x00000070 207d0069 6e740061 006600
+; CHECK-EB: 0x00000030 00000001 00000005 00000001 00000007
+; CHECK-EB: 0x00000040 0c000000 00000002 00696e74 00610066
+; CHECK: 0x00000050 002e7465 7874002f 746d702f 742e6300
+; CHECK: 0x00000060 696e7420 6628696e 74206129 207b2072
+; CHECK: 0x00000070 65747572 6e20613b 207d00
; CHECK: '.BTF.ext'
-; CHECK-EL: 0x00000000 9feb0100 18000000 00000000 14000000
-; CHECK-EL: 0x00000010 14000000 2c000000 08000000 01000000
-; CHECK-EL: 0x00000020 01000000 00000000 03000000 10000000
-; CHECK-EL: 0x00000030 01000000 02000000 00000000 07000000
-; CHECK-EL: 0x00000040 10000000 00040000 08000000 07000000
-; CHECK-EL: 0x00000050 10000000 10040000
-; CHECK-EB: 0x00000000 eb9f0100 00000018 00000000 00000014
-; CHECK-EB: 0x00000010 00000014 0000002c 00000008 00000001
-; CHECK-EB: 0x00000020 00000001 00000000 00000003 00000010
-; CHECK-EB: 0x00000030 00000001 00000002 00000000 00000007
-; CHECK-EB: 0x00000040 00000010 00000400 00000008 00000007
-; CHECK-EB: 0x00000050 00000010 00000410
+; CHECK-EL: 0x00000000 9feb0100 28000000 00000000 14000000
+; CHECK-EL: 0x00000010 14000000 2c000000 40000000 00000000
+; CHECK-EL: 0x00000020 40000000 00000000 08000000 09000000
+; CHECK-EL: 0x00000030 01000000 00000000 03000000 10000000
+; CHECK-EL: 0x00000040 09000000 02000000 00000000 0f000000
+; CHECK-EL: 0x00000050 18000000 00040000 08000000 0f000000
+; CHECK-EL: 0x00000060 18000000 10040000
+; CHECK-EB: 0x00000000 eb9f0100 00000028 00000000 00000014
+; CHECK-EB: 0x00000010 00000014 0000002c 00000040 00000000
+; CHECK-EB: 0x00000020 00000040 00000000 00000008 00000009
+; CHECK-EB: 0x00000030 00000001 00000000 00000003 00000010
+; CHECK-EB: 0x00000040 00000009 00000002 00000000 0000000f
+; CHECK-EB: 0x00000050 00000018 00000400 00000008 0000000f
+; CHECK-EB: 0x00000060 00000018 00000410
; Function Attrs: nounwind readnone speculatable
declare void @llvm.dbg.value(metadata, metadata, metadata) #1
diff --git a/llvm/test/CodeGen/BPF/BTF/extern-global-var.ll b/llvm/test/CodeGen/BPF/BTF/extern-global-var.ll
index ad81d28a657..235a0ed3f96 100644
--- a/llvm/test/CodeGen/BPF/BTF/extern-global-var.ll
+++ b/llvm/test/CodeGen/BPF/BTF/extern-global-var.ll
@@ -28,21 +28,21 @@ define dso_local i32 @foo() local_unnamed_addr #0 !dbg !7 {
; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1)
; CHECK-NEXT: .long 218103808 # 0xd000000
; CHECK-NEXT: .long 2
-; CHECK-NEXT: .long 44 # BTF_KIND_INT(id = 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 48 # BTF_KIND_FUNC(id = 3)
+; CHECK-NEXT: .long 5 # BTF_KIND_FUNC(id = 3)
; CHECK-NEXT: .long 201326592 # 0xc000000
; CHECK-NEXT: .long 1
; CHECK-NEXT: .byte 0 # string offset=0
-; CHECK-NEXT: .ascii ".text" # string offset=1
+; CHECK-NEXT: .ascii "int" # string offset=1
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=7
+; CHECK-NEXT: .ascii "foo" # string offset=5
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "int" # string offset=44
+; CHECK-NEXT: .ascii ".text" # string offset=9
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "foo" # string offset=48
+; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=15
; CHECK-NEXT: .byte 0
attributes #0 = { norecurse nounwind readonly "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "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" }
diff --git a/llvm/test/CodeGen/BPF/BTF/filename.ll b/llvm/test/CodeGen/BPF/BTF/filename.ll
index d0ada61e5a1..fd96720f041 100644
--- a/llvm/test/CodeGen/BPF/BTF/filename.ll
+++ b/llvm/test/CodeGen/BPF/BTF/filename.ll
@@ -23,41 +23,45 @@ define dso_local i32 @test() local_unnamed_addr #0 !dbg !7 {
; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1)
; CHECK-NEXT: .long 218103808 # 0xd000000
; CHECK-NEXT: .long 2
-; CHECK-NEXT: .long 26 # BTF_KIND_INT(id = 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 30 # BTF_KIND_FUNC(id = 3)
+; CHECK-NEXT: .long 5 # BTF_KIND_FUNC(id = 3)
; CHECK-NEXT: .long 201326592 # 0xc000000
; CHECK-NEXT: .long 1
; CHECK-NEXT: .byte 0 # string offset=0
-; CHECK-NEXT: .ascii ".text" # string offset=1
+; CHECK-NEXT: .ascii "int" # string offset=1
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "/home/yhs/ttmp/t.c" # string offset=7
+; CHECK-NEXT: .ascii "test" # string offset=5
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "int" # string offset=26
+; CHECK-NEXT: .ascii ".text" # string offset=10
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "test" # string offset=30
+; CHECK-NEXT: .ascii "/home/yhs/ttmp/t.c" # string offset=16
; CHECK-NEXT: .byte 0
; CHECK-NEXT: .section .BTF.ext,"",@progbits
; CHECK-NEXT: .short 60319 # 0xeb9f
; CHECK-NEXT: .byte 1
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .long 24
+; CHECK-NEXT: .long 40
; CHECK-NEXT: .long 0
; CHECK-NEXT: .long 20
; CHECK-NEXT: .long 20
; CHECK-NEXT: .long 28
+; CHECK-NEXT: .long 48
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 48
+; CHECK-NEXT: .long 0
; CHECK-NEXT: .long 8 # FuncInfo
-; CHECK-NEXT: .long 1 # FuncInfo section string offset=1
+; CHECK-NEXT: .long 10 # FuncInfo section string offset=10
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long .Lfunc_begin{{[0-9]+}}
; CHECK-NEXT: .long 3
; CHECK-NEXT: .long 16 # LineInfo
-; CHECK-NEXT: .long 1 # LineInfo section string offset=1
+; CHECK-NEXT: .long 10 # LineInfo section string offset=10
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
-; CHECK-NEXT: .long 7
+; CHECK-NEXT: .long 16
; CHECK-NEXT: .long 0
; CHECK-NEXT: .long 1038 # Line 1 Col 14
diff --git a/llvm/test/CodeGen/BPF/BTF/func-func-ptr.ll b/llvm/test/CodeGen/BPF/BTF/func-func-ptr.ll
index df564f5eb8a..e61459125b4 100644
--- a/llvm/test/CodeGen/BPF/BTF/func-func-ptr.ll
+++ b/llvm/test/CodeGen/BPF/BTF/func-func-ptr.ll
@@ -29,16 +29,16 @@ entry:
; CHECK-NEXT: .long 104
; CHECK-NEXT: .long 104
; CHECK-NEXT: .long 32
-; CHECK-NEXT: .long 16 # BTF_KIND_INT(id = 1)
+; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 1)
; CHECK-NEXT: .long 16777216 # 0x1000000
; CHECK-NEXT: .long 4
; CHECK-NEXT: .long 16777248 # 0x1000020
; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 2)
; CHECK-NEXT: .long 218103809 # 0xd000001
; CHECK-NEXT: .long 0
-; CHECK-NEXT: .long 20
+; CHECK-NEXT: .long 5
; CHECK-NEXT: .long 1
-; CHECK-NEXT: .long 23 # BTF_KIND_FUNC(id = 3)
+; CHECK-NEXT: .long 8 # BTF_KIND_FUNC(id = 3)
; CHECK-NEXT: .long 201326592 # 0xc000000
; CHECK-NEXT: .long 2
; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 4)
@@ -54,17 +54,17 @@ entry:
; CHECK-NEXT: .long 8
; CHECK-NEXT: .long 29
; CHECK-NEXT: .long 4
-; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 0 # 0x0
; CHECK-NEXT: .byte 0 # string offset=0
-; CHECK-NEXT: .ascii ".text" # string offset=1
+; CHECK-NEXT: .ascii "int" # string offset=1
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "/tmp/t.c" # string offset=7
+; CHECK-NEXT: .ascii "p2" # string offset=5
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "int" # string offset=16
+; CHECK-NEXT: .ascii "f1" # string offset=8
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "p2" # string offset=20
+; CHECK-NEXT: .ascii ".text" # string offset=11
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "f1" # string offset=23
+; CHECK-NEXT: .ascii "/tmp/t.c" # string offset=17
; CHECK-NEXT: .byte 0
; CHECK-NEXT: .ascii "t1" # string offset=26
; CHECK-NEXT: .byte 0
@@ -74,21 +74,25 @@ entry:
; CHECK-NEXT: .short 60319 # 0xeb9f
; CHECK-NEXT: .byte 1
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .long 24
+; CHECK-NEXT: .long 40
; CHECK-NEXT: .long 0
; CHECK-NEXT: .long 20
; CHECK-NEXT: .long 20
; CHECK-NEXT: .long 28
+; CHECK-NEXT: .long 48
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 48
+; CHECK-NEXT: .long 0
; CHECK-NEXT: .long 8 # FuncInfo
-; CHECK-NEXT: .long 1 # FuncInfo section string offset=1
+; CHECK-NEXT: .long 11 # FuncInfo section string offset=11
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long .Lfunc_begin0
; CHECK-NEXT: .long 3
; CHECK-NEXT: .long 16 # LineInfo
-; CHECK-NEXT: .long 1 # LineInfo section string offset=1
+; CHECK-NEXT: .long 11 # LineInfo section string offset=11
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
-; CHECK-NEXT: .long 7
+; CHECK-NEXT: .long 17
; CHECK-NEXT: .long 0
; CHECK-NEXT: .long 3091 # Line 3 Col 19
diff --git a/llvm/test/CodeGen/BPF/BTF/func-non-void.ll b/llvm/test/CodeGen/BPF/BTF/func-non-void.ll
index e5361b98e7d..5593ea888dd 100644
--- a/llvm/test/CodeGen/BPF/BTF/func-non-void.ll
+++ b/llvm/test/CodeGen/BPF/BTF/func-non-void.ll
@@ -21,52 +21,56 @@ define dso_local i32 @f1(i32 returned) local_unnamed_addr #0 !dbg !7 {
; CHECK-NEXT: .long 48
; CHECK-NEXT: .long 48
; CHECK-NEXT: .long 26
-; CHECK-NEXT: .long 16 # BTF_KIND_INT(id = 1)
+; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 1)
; CHECK-NEXT: .long 16777216 # 0x1000000
; CHECK-NEXT: .long 4
; CHECK-NEXT: .long 16777248 # 0x1000020
; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 2)
; CHECK-NEXT: .long 218103809 # 0xd000001
; CHECK-NEXT: .long 1
-; CHECK-NEXT: .long 20
+; CHECK-NEXT: .long 5
; CHECK-NEXT: .long 1
-; CHECK-NEXT: .long 23 # BTF_KIND_FUNC(id = 3)
+; CHECK-NEXT: .long 8 # BTF_KIND_FUNC(id = 3)
; CHECK-NEXT: .long 201326592 # 0xc000000
; CHECK-NEXT: .long 2
; CHECK-NEXT: .byte 0 # string offset=0
-; CHECK-NEXT: .ascii ".text" # string offset=1
+; CHECK-NEXT: .ascii "int" # string offset=1
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "/tmp/t.c" # string offset=7
+; CHECK-NEXT: .ascii "a1" # string offset=5
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "int" # string offset=16
+; CHECK-NEXT: .ascii "f1" # string offset=8
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "a1" # string offset=20
+; CHECK-NEXT: .ascii ".text" # string offset=11
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "f1" # string offset=23
+; CHECK-NEXT: .ascii "/tmp/t.c" # string offset=17
; CHECK-NEXT: .byte 0
; CHECK-NEXT: .section .BTF.ext,"",@progbits
; CHECK-NEXT: .short 60319 # 0xeb9f
; CHECK-NEXT: .byte 1
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .long 24
+; CHECK-NEXT: .long 40
; CHECK-NEXT: .long 0
; CHECK-NEXT: .long 20
; CHECK-NEXT: .long 20
; CHECK-NEXT: .long 44
+; CHECK-NEXT: .long 64
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 64
+; CHECK-NEXT: .long 0
; CHECK-NEXT: .long 8 # FuncInfo
-; CHECK-NEXT: .long 1 # FuncInfo section string offset=1
+; CHECK-NEXT: .long 11 # FuncInfo section string offset=11
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long .Lfunc_begin0
; CHECK-NEXT: .long 3
; CHECK-NEXT: .long 16 # LineInfo
-; CHECK-NEXT: .long 1 # LineInfo section string offset=1
+; CHECK-NEXT: .long 11 # LineInfo section string offset=11
; CHECK-NEXT: .long 2
; CHECK-NEXT: .long .Lfunc_begin0
-; CHECK-NEXT: .long 7
+; CHECK-NEXT: .long 17
; CHECK-NEXT: .long 0
; CHECK-NEXT: .long 1024 # Line 1 Col 0
; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
-; CHECK-NEXT: .long 7
+; CHECK-NEXT: .long 17
; CHECK-NEXT: .long 0
; CHECK-NEXT: .long 1042 # Line 1 Col 18
diff --git a/llvm/test/CodeGen/BPF/BTF/func-source.ll b/llvm/test/CodeGen/BPF/BTF/func-source.ll
index 6e1bed332d7..0d6e098b358 100644
--- a/llvm/test/CodeGen/BPF/BTF/func-source.ll
+++ b/llvm/test/CodeGen/BPF/BTF/func-source.ll
@@ -27,38 +27,42 @@ entry:
; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1)
; CHECK-NEXT: .long 218103808 # 0xd000000
; CHECK-NEXT: .long 0
-; CHECK-NEXT: .long 33 # BTF_KIND_FUNC(id = 2)
+; CHECK-NEXT: .long 1 # BTF_KIND_FUNC(id = 2)
; CHECK-NEXT: .long 201326592 # 0xc000000
; CHECK-NEXT: .long 1
; CHECK-NEXT: .byte 0 # string offset=0
-; CHECK-NEXT: .ascii ".text" # string offset=1
+; CHECK-NEXT: .byte 102 # string offset=1
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "/tmp/t.c" # string offset=7
+; CHECK-NEXT: .ascii ".text" # string offset=3
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "void f(void) { }" # string offset=16
+; CHECK-NEXT: .ascii "/tmp/t.c" # string offset=9
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .byte 102 # string offset=33
+; CHECK-NEXT: .ascii "void f(void) { }" # string offset=18
; CHECK-NEXT: .byte 0
; CHECK-NEXT: .section .BTF.ext,"",@progbits
; CHECK-NEXT: .short 60319 # 0xeb9f
; CHECK-NEXT: .byte 1
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .long 24
+; CHECK-NEXT: .long 40
; CHECK-NEXT: .long 0
; CHECK-NEXT: .long 20
; CHECK-NEXT: .long 20
; CHECK-NEXT: .long 28
+; CHECK-NEXT: .long 48
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 48
+; CHECK-NEXT: .long 0
; CHECK-NEXT: .long 8 # FuncInfo
-; CHECK-NEXT: .long 1 # FuncInfo section string offset=1
+; CHECK-NEXT: .long 3 # FuncInfo section string offset=3
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long .Lfunc_begin0
; CHECK-NEXT: .long 2
; CHECK-NEXT: .long 16 # LineInfo
-; CHECK-NEXT: .long 1 # LineInfo section string offset=1
+; CHECK-NEXT: .long 3 # LineInfo section string offset=3
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
-; CHECK-NEXT: .long 7
-; CHECK-NEXT: .long 16
+; CHECK-NEXT: .long 9
+; CHECK-NEXT: .long 18
; CHECK-NEXT: .long 1040 # Line 1 Col 16
attributes #0 = { norecurse nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "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" }
diff --git a/llvm/test/CodeGen/BPF/BTF/func-typedef.ll b/llvm/test/CodeGen/BPF/BTF/func-typedef.ll
index 8deac0f9441..48fcb336296 100644
--- a/llvm/test/CodeGen/BPF/BTF/func-typedef.ll
+++ b/llvm/test/CodeGen/BPF/BTF/func-typedef.ll
@@ -24,65 +24,70 @@ entry:
; CHECK-NEXT: .long 72
; CHECK-NEXT: .long 72
; CHECK-NEXT: .long 35
-; CHECK-NEXT: .long 16 # BTF_KIND_TYPEDEF(id = 1)
+; CHECK-NEXT: .long 1 # BTF_KIND_TYPEDEF(id = 1)
; CHECK-NEXT: .long 134217728 # 0x8000000
; CHECK-NEXT: .long 2
-; CHECK-NEXT: .long 22 # BTF_KIND_TYPEDEF(id = 2)
+; CHECK-NEXT: .long 7 # BTF_KIND_TYPEDEF(id = 2)
; CHECK-NEXT: .long 134217728 # 0x8000000
; CHECK-NEXT: .long 3
-; CHECK-NEXT: .long 27 # BTF_KIND_INT(id = 3)
+; CHECK-NEXT: .long 12 # BTF_KIND_INT(id = 3)
; CHECK-NEXT: .long 16777216 # 0x1000000
; CHECK-NEXT: .long 4
; CHECK-NEXT: .long 16777248 # 0x1000020
; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 4)
; CHECK-NEXT: .long 218103809 # 0xd000001
; CHECK-NEXT: .long 1
-; CHECK-NEXT: .long 31
+; CHECK-NEXT: .long 16
; CHECK-NEXT: .long 1
-; CHECK-NEXT: .long 33 # BTF_KIND_FUNC(id = 5)
+; CHECK-NEXT: .long 18 # BTF_KIND_FUNC(id = 5)
; CHECK-NEXT: .long 201326592 # 0xc000000
; CHECK-NEXT: .long 4
; CHECK-NEXT: .byte 0 # string offset=0
-; CHECK-NEXT: .ascii ".text" # string offset=1
+; CHECK-NEXT: .ascii "__int" # string offset=1
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "/tmp/t.c" # string offset=7
+; CHECK-NEXT: .ascii "_int" # string offset=7
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "__int" # string offset=16
+; CHECK-NEXT: .ascii "int" # string offset=12
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "_int" # string offset=22
+; CHECK-NEXT: .byte 97 # string offset=16
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "int" # string offset=27
+; CHECK-NEXT: .byte 102 # string offset=18
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .byte 97 # string offset=31
+; CHECK-NEXT: .ascii ".text" # string offset=20
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .byte 102 # string offset=33
+; CHECK-NEXT: .ascii "/tmp/t.c" # string offset=26
; CHECK-NEXT: .byte 0
; CHECK-NEXT: .section .BTF.ext,"",@progbits
; CHECK-NEXT: .short 60319 # 0xeb9f
; CHECK-NEXT: .byte 1
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .long 24
+; CHECK-NEXT: .long 40
; CHECK-NEXT: .long 0
; CHECK-NEXT: .long 20
; CHECK-NEXT: .long 20
; CHECK-NEXT: .long 44
+; CHECK-NEXT: .long 64
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 64
+; CHECK-NEXT: .long 0
; CHECK-NEXT: .long 8 # FuncInfo
-; CHECK-NEXT: .long 1 # FuncInfo section string offset=1
+; CHECK-NEXT: .long 20 # FuncInfo section string offset=20
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long .Lfunc_begin0
; CHECK-NEXT: .long 5
; CHECK-NEXT: .long 16 # LineInfo
-; CHECK-NEXT: .long 1 # LineInfo section string offset=1
+; CHECK-NEXT: .long 20 # LineInfo section string offset=20
; CHECK-NEXT: .long 2
; CHECK-NEXT: .long .Lfunc_begin0
-; CHECK-NEXT: .long 7
+; CHECK-NEXT: .long 26
; CHECK-NEXT: .long 0
; CHECK-NEXT: .long 3072 # Line 3 Col 0
; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
-; CHECK-NEXT: .long 7
+; CHECK-NEXT: .long 26
; CHECK-NEXT: .long 0
; CHECK-NEXT: .long 3092 # Line 3 Col 20
+
; Function Attrs: nounwind readnone speculatable
declare void @llvm.dbg.value(metadata, metadata, metadata) #1
diff --git a/llvm/test/CodeGen/BPF/BTF/func-unused-arg.ll b/llvm/test/CodeGen/BPF/BTF/func-unused-arg.ll
index 62e9d40db9a..ea94fb74638 100644
--- a/llvm/test/CodeGen/BPF/BTF/func-unused-arg.ll
+++ b/llvm/test/CodeGen/BPF/BTF/func-unused-arg.ll
@@ -21,48 +21,52 @@ define dso_local i32 @f1(i32) local_unnamed_addr #0 !dbg !7 {
; CHECK-NEXT: .long 48
; CHECK-NEXT: .long 48
; CHECK-NEXT: .long 26
-; CHECK-NEXT: .long 16 # BTF_KIND_INT(id = 1)
+; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 1)
; CHECK-NEXT: .long 16777216 # 0x1000000
; CHECK-NEXT: .long 4
; CHECK-NEXT: .long 16777248 # 0x1000020
; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 2)
; CHECK-NEXT: .long 218103809 # 0xd000001
; CHECK-NEXT: .long 1
-; CHECK-NEXT: .long 20
+; CHECK-NEXT: .long 5
; CHECK-NEXT: .long 1
-; CHECK-NEXT: .long 23 # BTF_KIND_FUNC(id = 3)
+; CHECK-NEXT: .long 8 # BTF_KIND_FUNC(id = 3)
; CHECK-NEXT: .long 201326592 # 0xc000000
; CHECK-NEXT: .long 2
; CHECK-NEXT: .byte 0 # string offset=0
-; CHECK-NEXT: .ascii ".text" # string offset=1
+; CHECK-NEXT: .ascii "int" # string offset=1
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "/tmp/t.c" # string offset=7
+; CHECK-NEXT: .ascii "a1" # string offset=5
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "int" # string offset=16
+; CHECK-NEXT: .ascii "f1" # string offset=8
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "a1" # string offset=20
+; CHECK-NEXT: .ascii ".text" # string offset=11
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "f1" # string offset=23
+; CHECK-NEXT: .ascii "/tmp/t.c" # string offset=17
; CHECK-NEXT: .byte 0
; CHECK-NEXT: .section .BTF.ext,"",@progbits
; CHECK-NEXT: .short 60319 # 0xeb9f
; CHECK-NEXT: .byte 1
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .long 24
+; CHECK-NEXT: .long 40
; CHECK-NEXT: .long 0
; CHECK-NEXT: .long 20
; CHECK-NEXT: .long 20
; CHECK-NEXT: .long 28
+; CHECK-NEXT: .long 48
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 48
+; CHECK-NEXT: .long 0
; CHECK-NEXT: .long 8 # FuncInfo
-; CHECK-NEXT: .long 1 # FuncInfo section string offset=1
+; CHECK-NEXT: .long 11 # FuncInfo section string offset=11
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long .Lfunc_begin0
; CHECK-NEXT: .long 3
; CHECK-NEXT: .long 16 # LineInfo
-; CHECK-NEXT: .long 1 # LineInfo section string offset=1
+; CHECK-NEXT: .long 11 # LineInfo section string offset=11
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
-; CHECK-NEXT: .long 7
+; CHECK-NEXT: .long 17
; CHECK-NEXT: .long 0
; CHECK-NEXT: .long 1042 # Line 1 Col 18
diff --git a/llvm/test/CodeGen/BPF/BTF/func-void.ll b/llvm/test/CodeGen/BPF/BTF/func-void.ll
index f86643b3de4..42a24d1884d 100644
--- a/llvm/test/CodeGen/BPF/BTF/func-void.ll
+++ b/llvm/test/CodeGen/BPF/BTF/func-void.ll
@@ -23,35 +23,39 @@ define dso_local void @f1() local_unnamed_addr #0 !dbg !7 {
; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1)
; CHECK-NEXT: .long 218103808 # 0xd000000
; CHECK-NEXT: .long 0
-; CHECK-NEXT: .long 16 # BTF_KIND_FUNC(id = 2)
+; CHECK-NEXT: .long 1 # BTF_KIND_FUNC(id = 2)
; CHECK-NEXT: .long 201326592 # 0xc000000
; CHECK-NEXT: .long 1
; CHECK-NEXT: .byte 0 # string offset=0
-; CHECK-NEXT: .ascii ".text" # string offset=1
+; CHECK-NEXT: .ascii "f1" # string offset=1
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "/tmp/t.c" # string offset=7
+; CHECK-NEXT: .ascii ".text" # string offset=4
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "f1" # string offset=16
+; CHECK-NEXT: .ascii "/tmp/t.c" # string offset=10
; CHECK-NEXT: .byte 0
; CHECK-NEXT: .section .BTF.ext,"",@progbits
; CHECK-NEXT: .short 60319 # 0xeb9f
; CHECK-NEXT: .byte 1
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .long 24
+; CHECK-NEXT: .long 40
; CHECK-NEXT: .long 0
; CHECK-NEXT: .long 20
; CHECK-NEXT: .long 20
; CHECK-NEXT: .long 28
+; CHECK-NEXT: .long 48
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 48
+; CHECK-NEXT: .long 0
; CHECK-NEXT: .long 8 # FuncInfo
-; CHECK-NEXT: .long 1 # FuncInfo section string offset=1
+; CHECK-NEXT: .long 4 # FuncInfo section string offset=4
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long .Lfunc_begin0
; CHECK-NEXT: .long 2
; CHECK-NEXT: .long 16 # LineInfo
-; CHECK-NEXT: .long 1 # LineInfo section string offset=1
+; CHECK-NEXT: .long 4 # LineInfo section string offset=4
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
-; CHECK-NEXT: .long 7
+; CHECK-NEXT: .long 10
; CHECK-NEXT: .long 0
; CHECK-NEXT: .long 1040 # Line 1 Col 16
diff --git a/llvm/test/CodeGen/BPF/BTF/local-var.ll b/llvm/test/CodeGen/BPF/BTF/local-var.ll
index 4eb498afcbd..fa7f09f3fb2 100644
--- a/llvm/test/CodeGen/BPF/BTF/local-var.ll
+++ b/llvm/test/CodeGen/BPF/BTF/local-var.ll
@@ -29,34 +29,34 @@ define dso_local i32 @foo(i8 signext) local_unnamed_addr #0 !dbg !7 {
; CHECK-NEXT: .long 64
; CHECK-NEXT: .long 64
; CHECK-NEXT: .long 59
-; CHECK-NEXT: .long 44 # BTF_KIND_INT(id = 1)
+; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 1)
; CHECK-NEXT: .long 16777216 # 0x1000000
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long 16777224 # 0x1000008
; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 2)
; CHECK-NEXT: .long 218103809 # 0xd000001
; CHECK-NEXT: .long 3
-; CHECK-NEXT: .long 49
+; CHECK-NEXT: .long 6
; CHECK-NEXT: .long 1
-; CHECK-NEXT: .long 51 # BTF_KIND_INT(id = 3)
+; CHECK-NEXT: .long 8 # BTF_KIND_INT(id = 3)
; CHECK-NEXT: .long 16777216 # 0x1000000
; CHECK-NEXT: .long 4
; CHECK-NEXT: .long 16777248 # 0x1000020
-; CHECK-NEXT: .long 55 # BTF_KIND_FUNC(id = 4)
+; CHECK-NEXT: .long 12 # BTF_KIND_FUNC(id = 4)
; CHECK-NEXT: .long 201326592 # 0xc000000
; CHECK-NEXT: .long 2
; CHECK-NEXT: .byte 0 # string offset=0
-; CHECK-NEXT: .ascii ".text" # string offset=1
+; CHECK-NEXT: .ascii "char" # string offset=1
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=7
+; CHECK-NEXT: .byte 97 # string offset=6
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "char" # string offset=44
+; CHECK-NEXT: .ascii "int" # string offset=8
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .byte 97 # string offset=49
+; CHECK-NEXT: .ascii "foo" # string offset=12
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "int" # string offset=51
+; CHECK-NEXT: .ascii ".text" # string offset=16
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "foo" # string offset=55
+; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=22
; CHECK-NEXT: .byte 0
; Function Attrs: nounwind readnone speculatable
diff --git a/llvm/test/CodeGen/BPF/BTF/map-def.ll b/llvm/test/CodeGen/BPF/BTF/map-def.ll
new file mode 100644
index 00000000000..cf777880efa
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/BTF/map-def.ll
@@ -0,0 +1,120 @@
+; 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:
+; struct key_type {
+; int a;
+; int b;
+; };
+; struct map_type {
+; struct key_type *key;
+; unsigned *value;
+; };
+; struct map_type __attribute__((section(".maps"))) hash_map;
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm t.c
+
+%struct.map_type = type { %struct.key_type*, i32* }
+%struct.key_type = type { i32, i32 }
+
+@hash_map = dso_local local_unnamed_addr global %struct.map_type zeroinitializer, section ".maps", align 8, !dbg !0
+
+; 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 168
+; CHECK-NEXT: .long 168
+; CHECK-NEXT: .long 65
+; CHECK-NEXT: .long 1 # BTF_KIND_STRUCT(id = 1)
+; CHECK-NEXT: .long 67108866 # 0x4000002
+; CHECK-NEXT: .long 16
+; CHECK-NEXT: .long 10
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 0 # 0x0
+; CHECK-NEXT: .long 14
+; CHECK-NEXT: .long 5
+; CHECK-NEXT: .long 64 # 0x40
+; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 2)
+; CHECK-NEXT: .long 33554432 # 0x2000000
+; CHECK-NEXT: .long 3
+; CHECK-NEXT: .long 20 # BTF_KIND_STRUCT(id = 3)
+; CHECK-NEXT: .long 67108866 # 0x4000002
+; CHECK-NEXT: .long 8
+; CHECK-NEXT: .long 29
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long 0 # 0x0
+; CHECK-NEXT: .long 31
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long 32 # 0x20
+; CHECK-NEXT: .long 33 # BTF_KIND_INT(id = 4)
+; CHECK-NEXT: .long 16777216 # 0x1000000
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long 16777248 # 0x1000020
+; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 5)
+; CHECK-NEXT: .long 33554432 # 0x2000000
+; CHECK-NEXT: .long 6
+; CHECK-NEXT: .long 37 # BTF_KIND_INT(id = 6)
+; CHECK-NEXT: .long 16777216 # 0x1000000
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long 32 # 0x20
+; CHECK-NEXT: .long 50 # BTF_KIND_VAR(id = 7)
+; CHECK-NEXT: .long 234881024 # 0xe000000
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long 59 # BTF_KIND_DATASEC(id = 8)
+; CHECK-NEXT: .long 251658241 # 0xf000001
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 7
+; CHECK-NEXT: .long hash_map
+; CHECK-NEXT: .long 16
+; CHECK-NEXT: .byte 0 # string offset=0
+; CHECK-NEXT: .ascii "map_type" # string offset=1
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "key" # string offset=10
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "value" # string offset=14
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "key_type" # string offset=20
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 97 # string offset=29
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 98 # string offset=31
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "int" # string offset=33
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "unsigned int" # string offset=37
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "hash_map" # string offset=50
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii ".maps" # string offset=59
+; CHECK-NEXT: .byte 0
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!18, !19, !20}
+!llvm.ident = !{!21}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "hash_map", scope: !2, file: !3, line: 9, type: !6, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (trunk 364157) (llvm/trunk 364156)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None)
+!3 = !DIFile(filename: "t.c", directory: "/tmp/home/yhs/work/tests/llvm")
+!4 = !{}
+!5 = !{!0}
+!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "map_type", file: !3, line: 5, size: 128, elements: !7)
+!7 = !{!8, !15}
+!8 = !DIDerivedType(tag: DW_TAG_member, name: "key", scope: !6, file: !3, line: 6, baseType: !9, size: 64)
+!9 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !10, size: 64)
+!10 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "key_type", file: !3, line: 1, size: 64, elements: !11)
+!11 = !{!12, !14}
+!12 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !10, file: !3, line: 2, baseType: !13, size: 32)
+!13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!14 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !10, file: !3, line: 3, baseType: !13, size: 32, offset: 32)
+!15 = !DIDerivedType(tag: DW_TAG_member, name: "value", scope: !6, file: !3, line: 7, baseType: !16, size: 64, offset: 64)
+!16 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !17, size: 64)
+!17 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
+!18 = !{i32 2, !"Dwarf Version", i32 4}
+!19 = !{i32 2, !"Debug Info Version", i32 3}
+!20 = !{i32 1, !"wchar_size", i32 4}
+!21 = !{!"clang version 9.0.0 (trunk 364157) (llvm/trunk 364156)"}
diff --git a/llvm/test/CodeGen/BPF/BTF/ptr-prune-type.ll b/llvm/test/CodeGen/BPF/BTF/ptr-prune-type.ll
new file mode 100644
index 00000000000..597e41394c9
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/BTF/ptr-prune-type.ll
@@ -0,0 +1,84 @@
+; 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:
+; struct t {
+; int a;
+; };
+; struct t2 {
+; struct t *f1;
+; };
+; struct t2 __attribute__((section("prune_types"))) g;
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm t.c
+
+%struct.t2 = type { %struct.t* }
+%struct.t = type { i32 }
+
+@g = dso_local local_unnamed_addr global %struct.t2 zeroinitializer, section "prune_types", align 8, !dbg !0
+
+; 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 88
+; CHECK-NEXT: .long 88
+; CHECK-NEXT: .long 23
+; CHECK-NEXT: .long 1 # BTF_KIND_STRUCT(id = 1)
+; CHECK-NEXT: .long 67108865 # 0x4000001
+; CHECK-NEXT: .long 8
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 0 # 0x0
+; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 2)
+; CHECK-NEXT: .long 33554432 # 0x2000000
+; CHECK-NEXT: .long 5
+; CHECK-NEXT: .long 7 # BTF_KIND_VAR(id = 3)
+; CHECK-NEXT: .long 234881024 # 0xe000000
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long 9 # BTF_KIND_DATASEC(id = 4)
+; CHECK-NEXT: .long 251658241 # 0xf000001
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 3
+; CHECK-NEXT: .long g
+; CHECK-NEXT: .long 8
+; CHECK-NEXT: .long 21 # BTF_KIND_FWD(id = 5)
+; CHECK-NEXT: .long 117440512 # 0x7000000
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .byte 0 # string offset=0
+; CHECK-NEXT: .ascii "t2" # string offset=1
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "f1" # string offset=4
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 103 # string offset=7
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "prune_types" # string offset=9
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 116 # string offset=21
+; CHECK-NEXT: .byte 0
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!14, !15, !16}
+!llvm.ident = !{!17}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "g", scope: !2, file: !3, line: 7, type: !6, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (trunk 364157) (llvm/trunk 364156)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None)
+!3 = !DIFile(filename: "t.c", directory: "/tmp/home/yhs/work/tests/llvm")
+!4 = !{}
+!5 = !{!0}
+!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t2", file: !3, line: 4, size: 64, elements: !7)
+!7 = !{!8}
+!8 = !DIDerivedType(tag: DW_TAG_member, name: "f1", scope: !6, file: !3, line: 5, baseType: !9, size: 64)
+!9 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !10, size: 64)
+!10 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t", file: !3, line: 1, size: 32, elements: !11)
+!11 = !{!12}
+!12 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !10, file: !3, line: 2, baseType: !13, size: 32)
+!13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!14 = !{i32 2, !"Dwarf Version", i32 4}
+!15 = !{i32 2, !"Debug Info Version", i32 3}
+!16 = !{i32 1, !"wchar_size", i32 4}
+!17 = !{!"clang version 9.0.0 (trunk 364157) (llvm/trunk 364156)"}
diff --git a/llvm/test/CodeGen/BPF/BTF/static-var-derived-type.ll b/llvm/test/CodeGen/BPF/BTF/static-var-derived-type.ll
index 1e87b5a020c..680bcd636d0 100644
--- a/llvm/test/CodeGen/BPF/BTF/static-var-derived-type.ll
+++ b/llvm/test/CodeGen/BPF/BTF/static-var-derived-type.ll
@@ -46,11 +46,11 @@ define dso_local i64 @foo() local_unnamed_addr #0 !dbg !27 {
; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1)
; CHECK-NEXT: .long 218103808 # 0xd000000
; CHECK-NEXT: .long 2
-; CHECK-NEXT: .long 45 # BTF_KIND_INT(id = 2)
+; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 2)
; CHECK-NEXT: .long 16777216 # 0x1000000
; CHECK-NEXT: .long 8
; CHECK-NEXT: .long 16777280 # 0x1000040
-; CHECK-NEXT: .long 54 # BTF_KIND_FUNC(id = 3)
+; CHECK-NEXT: .long 10 # BTF_KIND_FUNC(id = 3)
; CHECK-NEXT: .long 201326592 # 0xc000000
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long 0 # BTF_KIND_VOLATILE(id = 4)
@@ -116,13 +116,13 @@ define dso_local i64 @foo() local_unnamed_addr #0 !dbg !27 {
; CHECK-NEXT: .long v4
; CHECK-NEXT: .long 8
; CHECK-NEXT: .byte 0 # string offset=0
-; CHECK-NEXT: .ascii ".text" # string offset=1
+; CHECK-NEXT: .ascii "long int" # string offset=1
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bugs/test.c" # string offset=7
+; CHECK-NEXT: .ascii "foo" # string offset=10
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "long int" # string offset=45
+; CHECK-NEXT: .ascii ".text" # string offset=14
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "foo" # string offset=54
+; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bugs/test.c" # string offset=20
; CHECK-NEXT: .byte 0
; CHECK-NEXT: .ascii "int" # string offset=58
; CHECK-NEXT: .byte 0
diff --git a/llvm/test/CodeGen/BPF/BTF/static-var-inited-sec.ll b/llvm/test/CodeGen/BPF/BTF/static-var-inited-sec.ll
index beeffa0d5e8..4533742b519 100644
--- a/llvm/test/CodeGen/BPF/BTF/static-var-inited-sec.ll
+++ b/llvm/test/CodeGen/BPF/BTF/static-var-inited-sec.ll
@@ -35,11 +35,11 @@ define dso_local i32 @foo() local_unnamed_addr #0 !dbg !2 {
; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1)
; CHECK-NEXT: .long 218103808 # 0xd000000
; CHECK-NEXT: .long 2
-; CHECK-NEXT: .long 44 # BTF_KIND_INT(id = 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 48 # BTF_KIND_FUNC(id = 3)
+; CHECK-NEXT: .long 5 # BTF_KIND_FUNC(id = 3)
; CHECK-NEXT: .long 201326592 # 0xc000000
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long 0 # BTF_KIND_VOLATILE(id = 4)
@@ -74,13 +74,13 @@ define dso_local i32 @foo() local_unnamed_addr #0 !dbg !2 {
; CHECK-NEXT: .long a
; CHECK-NEXT: .long 1
; CHECK-NEXT: .byte 0 # string offset=0
-; CHECK-NEXT: .ascii ".text" # string offset=1
+; CHECK-NEXT: .ascii "int" # string offset=1
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=7
+; CHECK-NEXT: .ascii "foo" # string offset=5
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "int" # string offset=44
+; CHECK-NEXT: .ascii ".text" # string offset=9
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "foo" # string offset=48
+; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=15
; CHECK-NEXT: .byte 0
; CHECK-NEXT: .ascii "short" # string offset=52
; CHECK-NEXT: .byte 0
diff --git a/llvm/test/CodeGen/BPF/BTF/static-var-inited.ll b/llvm/test/CodeGen/BPF/BTF/static-var-inited.ll
index b3b3576fb6b..ed6e9eaf3eb 100644
--- a/llvm/test/CodeGen/BPF/BTF/static-var-inited.ll
+++ b/llvm/test/CodeGen/BPF/BTF/static-var-inited.ll
@@ -35,11 +35,11 @@ define dso_local i32 @foo() local_unnamed_addr #0 !dbg !2 {
; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1)
; CHECK-NEXT: .long 218103808 # 0xd000000
; CHECK-NEXT: .long 2
-; CHECK-NEXT: .long 44 # BTF_KIND_INT(id = 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 48 # BTF_KIND_FUNC(id = 3)
+; CHECK-NEXT: .long 5 # BTF_KIND_FUNC(id = 3)
; CHECK-NEXT: .long 201326592 # 0xc000000
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long 0 # BTF_KIND_VOLATILE(id = 4)
@@ -74,13 +74,13 @@ define dso_local i32 @foo() local_unnamed_addr #0 !dbg !2 {
; CHECK-NEXT: .long a
; CHECK-NEXT: .long 1
; CHECK-NEXT: .byte 0 # string offset=0
-; CHECK-NEXT: .ascii ".text" # string offset=1
+; CHECK-NEXT: .ascii "int" # string offset=1
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=7
+; CHECK-NEXT: .ascii "foo" # string offset=5
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "int" # string offset=44
+; CHECK-NEXT: .ascii ".text" # string offset=9
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "foo" # string offset=48
+; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=15
; CHECK-NEXT: .byte 0
; CHECK-NEXT: .ascii "short" # string offset=52
; CHECK-NEXT: .byte 0
diff --git a/llvm/test/CodeGen/BPF/BTF/static-var-readonly-sec.ll b/llvm/test/CodeGen/BPF/BTF/static-var-readonly-sec.ll
index 546f2bcbc0d..5901bbb384e 100644
--- a/llvm/test/CodeGen/BPF/BTF/static-var-readonly-sec.ll
+++ b/llvm/test/CodeGen/BPF/BTF/static-var-readonly-sec.ll
@@ -35,11 +35,11 @@ define dso_local i32 @foo() local_unnamed_addr #0 !dbg !2 {
; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1)
; CHECK-NEXT: .long 218103808 # 0xd000000
; CHECK-NEXT: .long 2
-; CHECK-NEXT: .long 44 # BTF_KIND_INT(id = 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 48 # BTF_KIND_FUNC(id = 3)
+; CHECK-NEXT: .long 5 # BTF_KIND_FUNC(id = 3)
; CHECK-NEXT: .long 201326592 # 0xc000000
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long 0 # BTF_KIND_CONST(id = 4)
@@ -80,13 +80,13 @@ define dso_local i32 @foo() local_unnamed_addr #0 !dbg !2 {
; CHECK-NEXT: .long a
; CHECK-NEXT: .long 1
; CHECK-NEXT: .byte 0 # string offset=0
-; CHECK-NEXT: .ascii ".text" # string offset=1
+; CHECK-NEXT: .ascii "int" # string offset=1
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=7
+; CHECK-NEXT: .ascii "foo" # string offset=5
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "int" # string offset=44
+; CHECK-NEXT: .ascii ".text" # string offset=9
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "foo" # string offset=48
+; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=15
; CHECK-NEXT: .byte 0
; CHECK-NEXT: .ascii "short" # string offset=52
; CHECK-NEXT: .byte 0
diff --git a/llvm/test/CodeGen/BPF/BTF/static-var-readonly.ll b/llvm/test/CodeGen/BPF/BTF/static-var-readonly.ll
index e39e737865d..04a3fbc5cbe 100644
--- a/llvm/test/CodeGen/BPF/BTF/static-var-readonly.ll
+++ b/llvm/test/CodeGen/BPF/BTF/static-var-readonly.ll
@@ -35,11 +35,11 @@ define dso_local i32 @foo() local_unnamed_addr #0 !dbg !2 {
; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1)
; CHECK-NEXT: .long 218103808 # 0xd000000
; CHECK-NEXT: .long 2
-; CHECK-NEXT: .long 44 # BTF_KIND_INT(id = 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 48 # BTF_KIND_FUNC(id = 3)
+; CHECK-NEXT: .long 5 # BTF_KIND_FUNC(id = 3)
; CHECK-NEXT: .long 201326592 # 0xc000000
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long 0 # BTF_KIND_CONST(id = 4)
@@ -80,13 +80,13 @@ define dso_local i32 @foo() local_unnamed_addr #0 !dbg !2 {
; CHECK-NEXT: .long a
; CHECK-NEXT: .long 1
; CHECK-NEXT: .byte 0 # string offset=0
-; CHECK-NEXT: .ascii ".text" # string offset=1
+; CHECK-NEXT: .ascii "int" # string offset=1
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=7
+; CHECK-NEXT: .ascii "foo" # string offset=5
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "int" # string offset=44
+; CHECK-NEXT: .ascii ".text" # string offset=9
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "foo" # string offset=48
+; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=15
; CHECK-NEXT: .byte 0
; CHECK-NEXT: .ascii "short" # string offset=52
; CHECK-NEXT: .byte 0
diff --git a/llvm/test/CodeGen/BPF/BTF/static-var-sec.ll b/llvm/test/CodeGen/BPF/BTF/static-var-sec.ll
index 36ce07d8968..6dcd4fefe93 100644
--- a/llvm/test/CodeGen/BPF/BTF/static-var-sec.ll
+++ b/llvm/test/CodeGen/BPF/BTF/static-var-sec.ll
@@ -35,11 +35,11 @@ define dso_local i32 @foo() local_unnamed_addr #0 !dbg !2 {
; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1)
; CHECK-NEXT: .long 218103808 # 0xd000000
; CHECK-NEXT: .long 2
-; CHECK-NEXT: .long 44 # BTF_KIND_INT(id = 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 48 # BTF_KIND_FUNC(id = 3)
+; CHECK-NEXT: .long 5 # BTF_KIND_FUNC(id = 3)
; CHECK-NEXT: .long 201326592 # 0xc000000
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long 0 # BTF_KIND_VOLATILE(id = 4)
@@ -74,13 +74,13 @@ define dso_local i32 @foo() local_unnamed_addr #0 !dbg !2 {
; CHECK-NEXT: .long a
; CHECK-NEXT: .long 1
; CHECK-NEXT: .byte 0 # string offset=0
-; CHECK-NEXT: .ascii ".text" # string offset=1
+; CHECK-NEXT: .ascii "int" # string offset=1
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=7
+; CHECK-NEXT: .ascii "foo" # string offset=5
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "int" # string offset=44
+; CHECK-NEXT: .ascii ".text" # string offset=9
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "foo" # string offset=48
+; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=15
; CHECK-NEXT: .byte 0
; CHECK-NEXT: .ascii "short" # string offset=52
; CHECK-NEXT: .byte 0
diff --git a/llvm/test/CodeGen/BPF/BTF/static-var-zerolen-array.ll b/llvm/test/CodeGen/BPF/BTF/static-var-zerolen-array.ll
index 51ff020bb72..93f5da342aa 100644
--- a/llvm/test/CodeGen/BPF/BTF/static-var-zerolen-array.ll
+++ b/llvm/test/CodeGen/BPF/BTF/static-var-zerolen-array.ll
@@ -32,11 +32,11 @@ define dso_local i32 @test() local_unnamed_addr #0 !dbg !21 {
; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1)
; CHECK-NEXT: .long 218103808 # 0xd000000
; CHECK-NEXT: .long 2
-; CHECK-NEXT: .long 44 # BTF_KIND_INT(id = 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 48 # BTF_KIND_FUNC(id = 3)
+; CHECK-NEXT: .long 5 # BTF_KIND_FUNC(id = 3)
; CHECK-NEXT: .long 201326592 # 0xc000000
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long 0 # BTF_KIND_VOLATILE(id = 4)
@@ -79,13 +79,13 @@ define dso_local i32 @test() local_unnamed_addr #0 !dbg !21 {
; CHECK-NEXT: .long sv
; CHECK-NEXT: .long 20
; CHECK-NEXT: .byte 0 # string offset=0
-; CHECK-NEXT: .ascii ".text" # string offset=1
+; CHECK-NEXT: .ascii "int" # string offset=1
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=7
+; CHECK-NEXT: .ascii "test" # string offset=5
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "int" # string offset=44
+; CHECK-NEXT: .ascii ".text" # string offset=10
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "test" # string offset=48
+; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=16
; CHECK-NEXT: .byte 0
; CHECK-NEXT: .byte 116 # string offset=53
; CHECK-NEXT: .byte 0
diff --git a/llvm/test/CodeGen/BPF/BTF/static-var.ll b/llvm/test/CodeGen/BPF/BTF/static-var.ll
index 5d09b19b520..0eb05652df6 100644
--- a/llvm/test/CodeGen/BPF/BTF/static-var.ll
+++ b/llvm/test/CodeGen/BPF/BTF/static-var.ll
@@ -35,11 +35,11 @@ define dso_local i32 @foo() local_unnamed_addr #0 !dbg !2 {
; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1)
; CHECK-NEXT: .long 218103808 # 0xd000000
; CHECK-NEXT: .long 2
-; CHECK-NEXT: .long 44 # BTF_KIND_INT(id = 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 48 # BTF_KIND_FUNC(id = 3)
+; CHECK-NEXT: .long 5 # BTF_KIND_FUNC(id = 3)
; CHECK-NEXT: .long 201326592 # 0xc000000
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long 0 # BTF_KIND_VOLATILE(id = 4)
@@ -74,13 +74,13 @@ define dso_local i32 @foo() local_unnamed_addr #0 !dbg !2 {
; CHECK-NEXT: .long a
; CHECK-NEXT: .long 1
; CHECK-NEXT: .byte 0 # string offset=0
-; CHECK-NEXT: .ascii ".text" # string offset=1
+; CHECK-NEXT: .ascii "int" # string offset=1
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=7
+; CHECK-NEXT: .ascii "foo" # string offset=5
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "int" # string offset=44
+; CHECK-NEXT: .ascii ".text" # string offset=9
; CHECK-NEXT: .byte 0
-; CHECK-NEXT: .ascii "foo" # string offset=48
+; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=15
; CHECK-NEXT: .byte 0
; CHECK-NEXT: .ascii "short" # string offset=52
; CHECK-NEXT: .byte 0
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-basic.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-basic.ll
new file mode 100644
index 00000000000..a6fb3a34dde
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-basic.ll
@@ -0,0 +1,186 @@
+; 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:
+; struct sk_buff {
+; int i;
+; struct net_device *dev;
+; };
+; #define _(x) (__builtin_preserve_access_index(x))
+; static int (*bpf_probe_read)(void *dst, int size, void *unsafe_ptr)
+; = (void *) 4;
+;
+; int bpf_prog(struct sk_buff *ctx) {
+; struct net_device *dev = 0;
+; bpf_probe_read(&dev, sizeof(dev), _(&ctx->dev));
+; return dev != 0;
+; }
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%struct.sk_buff = type { i32, %struct.net_device* }
+%struct.net_device = type opaque
+
+; Function Attrs: nounwind
+define dso_local i32 @bpf_prog(%struct.sk_buff*) local_unnamed_addr #0 !dbg !15 {
+ %2 = alloca %struct.net_device*, align 8
+ call void @llvm.dbg.value(metadata %struct.sk_buff* %0, metadata !26, metadata !DIExpression()), !dbg !28
+ %3 = bitcast %struct.net_device** %2 to i8*, !dbg !29
+ call void @llvm.lifetime.start.p0i8(i64 8, i8* nonnull %3) #4, !dbg !29
+ call void @llvm.dbg.value(metadata %struct.net_device* null, metadata !27, metadata !DIExpression()), !dbg !28
+ store %struct.net_device* null, %struct.net_device** %2, align 8, !dbg !30, !tbaa !31
+ %4 = tail call %struct.net_device** @llvm.preserve.struct.access.index.p0p0s_struct.net_devices.p0s_struct.sk_buffs(%struct.sk_buff* %0, i32 1, i32 1), !dbg !35, !llvm.preserve.access.index !19
+ %5 = bitcast %struct.net_device** %4 to i8*, !dbg !35
+ %6 = call i32 inttoptr (i64 4 to i32 (i8*, i32, i8*)*)(i8* nonnull %3, i32 8, i8* %5) #4, !dbg !36
+ %7 = load %struct.net_device*, %struct.net_device** %2, align 8, !dbg !37, !tbaa !31
+ call void @llvm.dbg.value(metadata %struct.net_device* %7, metadata !27, metadata !DIExpression()), !dbg !28
+ %8 = icmp ne %struct.net_device* %7, null, !dbg !38
+ %9 = zext i1 %8 to i32, !dbg !38
+ call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %3) #4, !dbg !39
+ ret i32 %9, !dbg !40
+}
+
+; 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 120
+; CHECK-NEXT: .long 120
+; CHECK-NEXT: .long 90
+; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 1)
+; CHECK-NEXT: .long 33554432 # 0x2000000
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 1 # BTF_KIND_STRUCT(id = 2)
+; CHECK-NEXT: .long 67108866 # 0x4000002
+; CHECK-NEXT: .long 16
+; CHECK-NEXT: .long 9
+; CHECK-NEXT: .long 3
+; CHECK-NEXT: .long 0 # 0x0
+; CHECK-NEXT: .long 11
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long 64 # 0x40
+; CHECK-NEXT: .long 15 # BTF_KIND_INT(id = 3)
+; CHECK-NEXT: .long 16777216 # 0x1000000
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long 16777248 # 0x1000020
+; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 4)
+; CHECK-NEXT: .long 33554432 # 0x2000000
+; CHECK-NEXT: .long 5
+; CHECK-NEXT: .long 19 # BTF_KIND_FWD(id = 5)
+; CHECK-NEXT: .long 117440512 # 0x7000000
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 6)
+; CHECK-NEXT: .long 218103809 # 0xd000001
+; CHECK-NEXT: .long 3
+; CHECK-NEXT: .long 30
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long 34 # BTF_KIND_FUNC(id = 7)
+; CHECK-NEXT: .long 201326592 # 0xc000000
+; CHECK-NEXT: .long 6
+; CHECK-NEXT: .byte 0 # string offset=0
+; CHECK-NEXT: .ascii "sk_buff" # string offset=1
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 105 # string offset=9
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "dev" # string offset=11
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "int" # string offset=15
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "net_device" # string offset=19
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "ctx" # string offset=30
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "bpf_prog" # string offset=34
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii ".text" # string offset=43
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "/tmp/home/yhs/work/tests/llvm/test.c" # string offset=49
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "0:1" # string offset=86
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .section .BTF.ext,"",@progbits
+; CHECK-NEXT: .short 60319 # 0xeb9f
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .long 40
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 20
+; CHECK-NEXT: .long 20
+; CHECK-NEXT: .long 124
+; CHECK-NEXT: .long 144
+; CHECK-NEXT: .long 24
+; CHECK-NEXT: .long 168
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 8 # FuncInfo
+
+; CHECK: .long 12 # OffsetReloc
+; CHECK-NEXT: .long 43 # Offset reloc section string offset=43
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long .Ltmp2
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 86
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1
+
+; Function Attrs: nounwind readnone
+declare %struct.net_device** @llvm.preserve.struct.access.index.p0p0s_struct.net_devices.p0s_struct.sk_buffs(%struct.sk_buff*, i32 immarg, i32 immarg) #2
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #1
+
+; Function Attrs: nounwind readnone speculatable
+declare void @llvm.dbg.value(metadata, metadata, metadata) #3
+
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "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 = { argmemonly nounwind }
+attributes #2 = { nounwind readnone }
+attributes #3 = { nounwind readnone speculatable }
+attributes #4 = { nounwind }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!11, !12, !13}
+!llvm.ident = !{!14}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (trunk 360739) (llvm/trunk 360747)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm")
+!2 = !{}
+!3 = !{!4}
+!4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression())
+!5 = distinct !DIGlobalVariable(name: "bpf_probe_read", scope: !0, file: !1, line: 6, type: !6, isLocal: true, isDefinition: true)
+!6 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64)
+!7 = !DISubroutineType(types: !8)
+!8 = !{!9, !10, !9, !10}
+!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!10 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64)
+!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 9.0.0 (trunk 360739) (llvm/trunk 360747)"}
+!15 = distinct !DISubprogram(name: "bpf_prog", scope: !1, file: !1, line: 9, type: !16, scopeLine: 9, flags: DIFlagPrototyped, isLocal: false, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !25)
+!16 = !DISubroutineType(types: !17)
+!17 = !{!9, !18}
+!18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !19, size: 64)
+!19 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "sk_buff", file: !1, line: 1, size: 128, elements: !20)
+!20 = !{!21, !22}
+!21 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !19, file: !1, line: 2, baseType: !9, size: 32)
+!22 = !DIDerivedType(tag: DW_TAG_member, name: "dev", scope: !19, file: !1, line: 3, baseType: !23, size: 64, offset: 64)
+!23 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !24, size: 64)
+!24 = !DICompositeType(tag: DW_TAG_structure_type, name: "net_device", file: !1, line: 3, flags: DIFlagFwdDecl)
+!25 = !{!26, !27}
+!26 = !DILocalVariable(name: "ctx", arg: 1, scope: !15, file: !1, line: 9, type: !18)
+!27 = !DILocalVariable(name: "dev", scope: !15, file: !1, line: 10, type: !23)
+!28 = !DILocation(line: 0, scope: !15)
+!29 = !DILocation(line: 10, column: 3, scope: !15)
+!30 = !DILocation(line: 10, column: 22, scope: !15)
+!31 = !{!32, !32, i64 0}
+!32 = !{!"any pointer", !33, i64 0}
+!33 = !{!"omnipotent char", !34, i64 0}
+!34 = !{!"Simple C/C++ TBAA"}
+!35 = !DILocation(line: 11, column: 37, scope: !15)
+!36 = !DILocation(line: 11, column: 3, scope: !15)
+!37 = !DILocation(line: 12, column: 10, scope: !15)
+!38 = !DILocation(line: 12, column: 14, scope: !15)
+!39 = !DILocation(line: 13, column: 1, scope: !15)
+!40 = !DILocation(line: 12, column: 3, scope: !15)
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-multilevel.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-multilevel.ll
new file mode 100644
index 00000000000..779b395299d
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-multilevel.ll
@@ -0,0 +1,197 @@
+; 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:
+; struct net_device {
+; int dev_id;
+; int others;
+; };
+; struct sk_buff {
+; int i;
+; struct net_device dev;
+; };
+; #define _(x) (__builtin_preserve_access_index(x))
+; static int (*bpf_probe_read)(void *dst, int size, void *unsafe_ptr)
+; = (void *) 4;
+;
+; int bpf_prog(struct sk_buff *ctx) {
+; int dev_id;
+; bpf_probe_read(&dev_id, sizeof(int), _(&ctx->dev.dev_id));
+; return dev_id;
+; }
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%struct.sk_buff = type { i32, %struct.net_device }
+%struct.net_device = type { i32, i32 }
+
+; Function Attrs: nounwind
+define dso_local i32 @bpf_prog(%struct.sk_buff*) local_unnamed_addr #0 !dbg !15 {
+ %2 = alloca i32, align 4
+ call void @llvm.dbg.value(metadata %struct.sk_buff* %0, metadata !28, metadata !DIExpression()), !dbg !30
+ %3 = bitcast i32* %2 to i8*, !dbg !31
+ call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %3) #4, !dbg !31
+ %4 = tail call %struct.net_device* @llvm.preserve.struct.access.index.p0s_struct.net_devices.p0s_struct.sk_buffs(%struct.sk_buff* %0, i32 1, i32 1), !dbg !32, !llvm.preserve.access.index !19
+ %5 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.net_devices(%struct.net_device* %4, i32 0, i32 0), !dbg !32, !llvm.preserve.access.index !23
+ %6 = bitcast i32* %5 to i8*, !dbg !32
+ %7 = call i32 inttoptr (i64 4 to i32 (i8*, i32, i8*)*)(i8* nonnull %3, i32 4, i8* %6) #4, !dbg !33
+ %8 = load i32, i32* %2, align 4, !dbg !34, !tbaa !35
+ call void @llvm.dbg.value(metadata i32 %8, metadata !29, metadata !DIExpression()), !dbg !30
+ call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %3) #4, !dbg !39
+ ret i32 %8, !dbg !40
+}
+
+; 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 132
+; CHECK-NEXT: .long 132
+; CHECK-NEXT: .long 106
+; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 1)
+; CHECK-NEXT: .long 33554432 # 0x2000000
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 1 # BTF_KIND_STRUCT(id = 2)
+; CHECK-NEXT: .long 67108866 # 0x4000002
+; CHECK-NEXT: .long 12
+; CHECK-NEXT: .long 9
+; CHECK-NEXT: .long 3
+; CHECK-NEXT: .long 0 # 0x0
+; CHECK-NEXT: .long 11
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long 32 # 0x20
+; CHECK-NEXT: .long 15 # BTF_KIND_INT(id = 3)
+; CHECK-NEXT: .long 16777216 # 0x1000000
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long 16777248 # 0x1000020
+; CHECK-NEXT: .long 19 # BTF_KIND_STRUCT(id = 4)
+; CHECK-NEXT: .long 67108866 # 0x4000002
+; CHECK-NEXT: .long 8
+; CHECK-NEXT: .long 30
+; CHECK-NEXT: .long 3
+; CHECK-NEXT: .long 0 # 0x0
+; CHECK-NEXT: .long 37
+; CHECK-NEXT: .long 3
+; CHECK-NEXT: .long 32 # 0x20
+; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 5)
+; CHECK-NEXT: .long 218103809 # 0xd000001
+; CHECK-NEXT: .long 3
+; CHECK-NEXT: .long 44
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long 48 # BTF_KIND_FUNC(id = 6)
+; CHECK-NEXT: .long 201326592 # 0xc000000
+; CHECK-NEXT: .long 5
+; CHECK-NEXT: .byte 0 # string offset=0
+; CHECK-NEXT: .ascii "sk_buff" # string offset=1
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 105 # string offset=9
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "dev" # string offset=11
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "int" # string offset=15
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "net_device" # string offset=19
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "dev_id" # string offset=30
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "others" # string offset=37
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "ctx" # string offset=44
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "bpf_prog" # string offset=48
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii ".text" # string offset=57
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "/tmp/home/yhs/work/tests/llvm/test.c" # string offset=63
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "0:1:0" # string offset=100
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .section .BTF.ext,"",@progbits
+; CHECK-NEXT: .short 60319 # 0xeb9f
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .long 40
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 20
+; CHECK-NEXT: .long 20
+; CHECK-NEXT: .long 76
+; CHECK-NEXT: .long 96
+; CHECK-NEXT: .long 24
+; CHECK-NEXT: .long 120
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 8 # FuncInfo
+
+; CHECK: .long 12 # OffsetReloc
+; CHECK-NEXT: .long 57 # Offset reloc section string offset=57
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long .Ltmp2
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 100
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1
+
+; Function Attrs: nounwind readnone
+declare %struct.net_device* @llvm.preserve.struct.access.index.p0s_struct.net_devices.p0s_struct.sk_buffs(%struct.sk_buff*, i32 immarg, i32 immarg) #2
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.net_devices(%struct.net_device*, i32 immarg, i32 immarg) #2
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #1
+
+; Function Attrs: nounwind readnone speculatable
+declare void @llvm.dbg.value(metadata, metadata, metadata) #3
+
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "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 = { argmemonly nounwind }
+attributes #2 = { nounwind readnone }
+attributes #3 = { nounwind readnone speculatable }
+attributes #4 = { nounwind }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!11, !12, !13}
+!llvm.ident = !{!14}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (trunk 360739) (llvm/trunk 360747)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm")
+!2 = !{}
+!3 = !{!4}
+!4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression())
+!5 = distinct !DIGlobalVariable(name: "bpf_probe_read", scope: !0, file: !1, line: 10, type: !6, isLocal: true, isDefinition: true)
+!6 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64)
+!7 = !DISubroutineType(types: !8)
+!8 = !{!9, !10, !9, !10}
+!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!10 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64)
+!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 9.0.0 (trunk 360739) (llvm/trunk 360747)"}
+!15 = distinct !DISubprogram(name: "bpf_prog", scope: !1, file: !1, line: 13, type: !16, scopeLine: 13, flags: DIFlagPrototyped, isLocal: false, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !27)
+!16 = !DISubroutineType(types: !17)
+!17 = !{!9, !18}
+!18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !19, size: 64)
+!19 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "sk_buff", file: !1, line: 5, size: 96, elements: !20)
+!20 = !{!21, !22}
+!21 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !19, file: !1, line: 6, baseType: !9, size: 32)
+!22 = !DIDerivedType(tag: DW_TAG_member, name: "dev", scope: !19, file: !1, line: 7, baseType: !23, size: 64, offset: 32)
+!23 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "net_device", file: !1, line: 1, size: 64, elements: !24)
+!24 = !{!25, !26}
+!25 = !DIDerivedType(tag: DW_TAG_member, name: "dev_id", scope: !23, file: !1, line: 2, baseType: !9, size: 32)
+!26 = !DIDerivedType(tag: DW_TAG_member, name: "others", scope: !23, file: !1, line: 3, baseType: !9, size: 32, offset: 32)
+!27 = !{!28, !29}
+!28 = !DILocalVariable(name: "ctx", arg: 1, scope: !15, file: !1, line: 13, type: !18)
+!29 = !DILocalVariable(name: "dev_id", scope: !15, file: !1, line: 14, type: !9)
+!30 = !DILocation(line: 0, scope: !15)
+!31 = !DILocation(line: 14, column: 3, scope: !15)
+!32 = !DILocation(line: 15, column: 40, scope: !15)
+!33 = !DILocation(line: 15, column: 3, scope: !15)
+!34 = !DILocation(line: 16, column: 10, scope: !15)
+!35 = !{!36, !36, i64 0}
+!36 = !{!"int", !37, i64 0}
+!37 = !{!"omnipotent char", !38, i64 0}
+!38 = !{!"Simple C/C++ TBAA"}
+!39 = !DILocation(line: 17, column: 1, scope: !15)
+!40 = !DILocation(line: 16, column: 3, scope: !15)
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-anonymous.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-anonymous.ll
new file mode 100644
index 00000000000..732187c019e
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-anonymous.ll
@@ -0,0 +1,213 @@
+; 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:
+; struct sk_buff {
+; int i;
+; struct {
+; int dev_id;
+; int others;
+; } dev[10];
+; };
+; #define _(x) (__builtin_preserve_access_index(x))
+; static int (*bpf_probe_read)(void *dst, int size, void *unsafe_ptr)
+; = (void *) 4;
+;
+; int bpf_prog(struct sk_buff *ctx) {
+; int dev_id;
+; bpf_probe_read(&dev_id, sizeof(int), _(&ctx->dev[5].dev_id));
+; return dev_id;
+; }
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%struct.sk_buff = type { i32, [10 x %struct.anon] }
+%struct.anon = type { i32, i32 }
+
+; Function Attrs: nounwind
+define dso_local i32 @bpf_prog(%struct.sk_buff*) local_unnamed_addr #0 !dbg !15 {
+ %2 = alloca i32, align 4
+ call void @llvm.dbg.value(metadata %struct.sk_buff* %0, metadata !31, metadata !DIExpression()), !dbg !33
+ %3 = bitcast i32* %2 to i8*, !dbg !34
+ call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %3) #4, !dbg !34
+ %4 = tail call [10 x %struct.anon]* @llvm.preserve.struct.access.index.p0a10s_struct.anons.p0s_struct.sk_buffs(%struct.sk_buff* %0, i32 1, i32 1), !dbg !35, !llvm.preserve.access.index !19
+ %5 = tail call %struct.anon* @llvm.preserve.array.access.index.p0s_struct.anons.p0a10s_struct.anons([10 x %struct.anon]* %4, i32 1, i32 5), !dbg !35
+ %6 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.anons(%struct.anon* %5, i32 0, i32 0), !dbg !35, !llvm.preserve.access.index !24
+ %7 = bitcast i32* %6 to i8*, !dbg !35
+ %8 = call i32 inttoptr (i64 4 to i32 (i8*, i32, i8*)*)(i8* nonnull %3, i32 4, i8* %7) #4, !dbg !36
+ %9 = load i32, i32* %2, align 4, !dbg !37, !tbaa !38
+ call void @llvm.dbg.value(metadata i32 %9, metadata !32, metadata !DIExpression()), !dbg !33
+ call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %3) #4, !dbg !42
+ ret i32 %9, !dbg !43
+}
+
+; 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 172
+; CHECK-NEXT: .long 172
+; CHECK-NEXT: .long 117
+; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 1)
+; CHECK-NEXT: .long 33554432 # 0x2000000
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 1 # BTF_KIND_STRUCT(id = 2)
+; CHECK-NEXT: .long 67108866 # 0x4000002
+; CHECK-NEXT: .long 84
+; CHECK-NEXT: .long 9
+; CHECK-NEXT: .long 3
+; CHECK-NEXT: .long 0 # 0x0
+; CHECK-NEXT: .long 11
+; CHECK-NEXT: .long 5
+; CHECK-NEXT: .long 32 # 0x20
+; CHECK-NEXT: .long 15 # BTF_KIND_INT(id = 3)
+; CHECK-NEXT: .long 16777216 # 0x1000000
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long 16777248 # 0x1000020
+; CHECK-NEXT: .long 0 # BTF_KIND_STRUCT(id = 4)
+; CHECK-NEXT: .long 67108866 # 0x4000002
+; CHECK-NEXT: .long 8
+; CHECK-NEXT: .long 19
+; CHECK-NEXT: .long 3
+; CHECK-NEXT: .long 0 # 0x0
+; CHECK-NEXT: .long 26
+; CHECK-NEXT: .long 3
+; CHECK-NEXT: .long 32 # 0x20
+; CHECK-NEXT: .long 0 # BTF_KIND_ARRAY(id = 5)
+; CHECK-NEXT: .long 50331648 # 0x3000000
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long 6
+; CHECK-NEXT: .long 10
+; CHECK-NEXT: .long 33 # BTF_KIND_INT(id = 6)
+; CHECK-NEXT: .long 16777216 # 0x1000000
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long 32 # 0x20
+; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 7)
+; CHECK-NEXT: .long 218103809 # 0xd000001
+; CHECK-NEXT: .long 3
+; CHECK-NEXT: .long 53
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long 57 # BTF_KIND_FUNC(id = 8)
+; CHECK-NEXT: .long 201326592 # 0xc000000
+; CHECK-NEXT: .long 7
+; CHECK-NEXT: .byte 0 # string offset=0
+; CHECK-NEXT: .ascii "sk_buff" # string offset=1
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 105 # string offset=9
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "dev" # string offset=11
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "int" # string offset=15
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "dev_id" # string offset=19
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "others" # string offset=26
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "__ARRAY_SIZE_TYPE__" # string offset=33
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "ctx" # string offset=53
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "bpf_prog" # string offset=57
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii ".text" # string offset=66
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "/tmp/home/yhs/work/tests/llvm/test.c" # string offset=72
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "0:1:5:0" # string offset=109
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .section .BTF.ext,"",@progbits
+; CHECK-NEXT: .short 60319 # 0xeb9f
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .long 40
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 20
+; CHECK-NEXT: .long 20
+; CHECK-NEXT: .long 76
+; CHECK-NEXT: .long 96
+; CHECK-NEXT: .long 24
+; CHECK-NEXT: .long 120
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 8 # FuncInfo
+
+; CHECK: .long 12 # OffsetReloc
+; CHECK-NEXT: .long 66 # Offset reloc section string offset=66
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long .Ltmp2
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 109
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1
+
+; Function Attrs: nounwind readnone
+declare [10 x %struct.anon]* @llvm.preserve.struct.access.index.p0a10s_struct.anons.p0s_struct.sk_buffs(%struct.sk_buff*, i32 immarg, i32 immarg) #2
+
+; Function Attrs: nounwind readnone
+declare %struct.anon* @llvm.preserve.array.access.index.p0s_struct.anons.p0a10s_struct.anons([10 x %struct.anon]*, i32 immarg, i32 immarg) #2
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.anons(%struct.anon*, i32 immarg, i32 immarg) #2
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #1
+
+; Function Attrs: nounwind readnone speculatable
+declare void @llvm.dbg.value(metadata, metadata, metadata) #3
+
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "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 = { argmemonly nounwind }
+attributes #2 = { nounwind readnone }
+attributes #3 = { nounwind readnone speculatable }
+attributes #4 = { nounwind }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!11, !12, !13}
+!llvm.ident = !{!14}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (trunk 360739) (llvm/trunk 360747)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm")
+!2 = !{}
+!3 = !{!4}
+!4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression())
+!5 = distinct !DIGlobalVariable(name: "bpf_probe_read", scope: !0, file: !1, line: 9, type: !6, isLocal: true, isDefinition: true)
+!6 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64)
+!7 = !DISubroutineType(types: !8)
+!8 = !{!9, !10, !9, !10}
+!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!10 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64)
+!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 9.0.0 (trunk 360739) (llvm/trunk 360747)"}
+!15 = distinct !DISubprogram(name: "bpf_prog", scope: !1, file: !1, line: 12, type: !16, scopeLine: 12, flags: DIFlagPrototyped, isLocal: false, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !30)
+!16 = !DISubroutineType(types: !17)
+!17 = !{!9, !18}
+!18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !19, size: 64)
+!19 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "sk_buff", file: !1, line: 1, size: 672, elements: !20)
+!20 = !{!21, !22}
+!21 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !19, file: !1, line: 2, baseType: !9, size: 32)
+!22 = !DIDerivedType(tag: DW_TAG_member, name: "dev", scope: !19, file: !1, line: 6, baseType: !23, size: 640, offset: 32)
+!23 = !DICompositeType(tag: DW_TAG_array_type, baseType: !24, size: 640, elements: !28)
+!24 = distinct !DICompositeType(tag: DW_TAG_structure_type, scope: !19, file: !1, line: 3, size: 64, elements: !25)
+!25 = !{!26, !27}
+!26 = !DIDerivedType(tag: DW_TAG_member, name: "dev_id", scope: !24, file: !1, line: 4, baseType: !9, size: 32)
+!27 = !DIDerivedType(tag: DW_TAG_member, name: "others", scope: !24, file: !1, line: 5, baseType: !9, size: 32, offset: 32)
+!28 = !{!29}
+!29 = !DISubrange(count: 10)
+!30 = !{!31, !32}
+!31 = !DILocalVariable(name: "ctx", arg: 1, scope: !15, file: !1, line: 12, type: !18)
+!32 = !DILocalVariable(name: "dev_id", scope: !15, file: !1, line: 13, type: !9)
+!33 = !DILocation(line: 0, scope: !15)
+!34 = !DILocation(line: 13, column: 3, scope: !15)
+!35 = !DILocation(line: 14, column: 40, scope: !15)
+!36 = !DILocation(line: 14, column: 3, scope: !15)
+!37 = !DILocation(line: 15, column: 10, scope: !15)
+!38 = !{!39, !39, i64 0}
+!39 = !{!"int", !40, i64 0}
+!40 = !{!"omnipotent char", !41, i64 0}
+!41 = !{!"Simple C/C++ TBAA"}
+!42 = !DILocation(line: 16, column: 1, scope: !15)
+!43 = !DILocation(line: 15, column: 3, scope: !15)
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-array.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-array.ll
new file mode 100644
index 00000000000..77d23753d4b
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-array.ll
@@ -0,0 +1,216 @@
+; 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:
+; struct net_device {
+; int dev_id;
+; int others;
+; };
+; struct sk_buff {
+; int i;
+; struct net_device dev[10];
+; };
+; #define _(x) (__builtin_preserve_access_index(x))
+; static int (*bpf_probe_read)(void *dst, int size, void *unsafe_ptr)
+; = (void *) 4;
+;
+; int bpf_prog(struct sk_buff *ctx) {
+; int dev_id;
+; bpf_probe_read(&dev_id, sizeof(int), _(&ctx->dev[5].dev_id));
+; return dev_id;
+; }
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%struct.sk_buff = type { i32, [10 x %struct.net_device] }
+%struct.net_device = type { i32, i32 }
+
+; Function Attrs: nounwind
+define dso_local i32 @bpf_prog(%struct.sk_buff*) local_unnamed_addr #0 !dbg !15 {
+ %2 = alloca i32, align 4
+ call void @llvm.dbg.value(metadata %struct.sk_buff* %0, metadata !31, metadata !DIExpression()), !dbg !33
+ %3 = bitcast i32* %2 to i8*, !dbg !34
+ call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %3) #4, !dbg !34
+ %4 = tail call [10 x %struct.net_device]* @llvm.preserve.struct.access.index.p0a10s_struct.net_devices.p0s_struct.sk_buffs(%struct.sk_buff* %0, i32 1, i32 1), !dbg !35, !llvm.preserve.access.index !19
+ %5 = tail call %struct.net_device* @llvm.preserve.array.access.index.p0s_struct.net_devices.p0a10s_struct.net_devices([10 x %struct.net_device]* %4, i32 1, i32 5), !dbg !35
+ %6 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.net_devices(%struct.net_device* %5, i32 0, i32 0), !dbg !35, !llvm.preserve.access.index !24
+ %7 = bitcast i32* %6 to i8*, !dbg !35
+ %8 = call i32 inttoptr (i64 4 to i32 (i8*, i32, i8*)*)(i8* nonnull %3, i32 4, i8* %7) #4, !dbg !36
+ %9 = load i32, i32* %2, align 4, !dbg !37, !tbaa !38
+ call void @llvm.dbg.value(metadata i32 %9, metadata !32, metadata !DIExpression()), !dbg !33
+ call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %3) #4, !dbg !42
+ ret i32 %9, !dbg !43
+}
+
+; 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 172
+; CHECK-NEXT: .long 172
+; CHECK-NEXT: .long 128
+; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 1)
+; CHECK-NEXT: .long 33554432 # 0x2000000
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 1 # BTF_KIND_STRUCT(id = 2)
+; CHECK-NEXT: .long 67108866 # 0x4000002
+; CHECK-NEXT: .long 84
+; CHECK-NEXT: .long 9
+; CHECK-NEXT: .long 3
+; CHECK-NEXT: .long 0 # 0x0
+; CHECK-NEXT: .long 11
+; CHECK-NEXT: .long 5
+; CHECK-NEXT: .long 32 # 0x20
+; CHECK-NEXT: .long 15 # BTF_KIND_INT(id = 3)
+; CHECK-NEXT: .long 16777216 # 0x1000000
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long 16777248 # 0x1000020
+; CHECK-NEXT: .long 19 # BTF_KIND_STRUCT(id = 4)
+; CHECK-NEXT: .long 67108866 # 0x4000002
+; CHECK-NEXT: .long 8
+; CHECK-NEXT: .long 30
+; CHECK-NEXT: .long 3
+; CHECK-NEXT: .long 0 # 0x0
+; CHECK-NEXT: .long 37
+; CHECK-NEXT: .long 3
+; CHECK-NEXT: .long 32 # 0x20
+; CHECK-NEXT: .long 0 # BTF_KIND_ARRAY(id = 5)
+; CHECK-NEXT: .long 50331648 # 0x3000000
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long 6
+; CHECK-NEXT: .long 10
+; CHECK-NEXT: .long 44 # BTF_KIND_INT(id = 6)
+; CHECK-NEXT: .long 16777216 # 0x1000000
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long 32 # 0x20
+; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 7)
+; CHECK-NEXT: .long 218103809 # 0xd000001
+; CHECK-NEXT: .long 3
+; CHECK-NEXT: .long 64
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long 68 # BTF_KIND_FUNC(id = 8)
+; CHECK-NEXT: .long 201326592 # 0xc000000
+; CHECK-NEXT: .long 7
+; CHECK-NEXT: .byte 0 # string offset=0
+; CHECK-NEXT: .ascii "sk_buff" # string offset=1
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 105 # string offset=9
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "dev" # string offset=11
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "int" # string offset=15
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "net_device" # string offset=19
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "dev_id" # string offset=30
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "others" # string offset=37
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "__ARRAY_SIZE_TYPE__" # string offset=44
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "ctx" # string offset=64
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "bpf_prog" # string offset=68
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii ".text" # string offset=77
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "/tmp/home/yhs/work/tests/llvm/test.c" # string offset=83
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "0:1:5:0" # string offset=120
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .section .BTF.ext,"",@progbits
+; CHECK-NEXT: .short 60319 # 0xeb9f
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .long 40
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 20
+; CHECK-NEXT: .long 20
+; CHECK-NEXT: .long 76
+; CHECK-NEXT: .long 96
+; CHECK-NEXT: .long 24
+; CHECK-NEXT: .long 120
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 8 # FuncInfo
+
+; CHECK: .long 12 # OffsetReloc
+; CHECK-NEXT: .long 77 # Offset reloc section string offset=77
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long .Ltmp2
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 120
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1
+
+; Function Attrs: nounwind readnone
+declare [10 x %struct.net_device]* @llvm.preserve.struct.access.index.p0a10s_struct.net_devices.p0s_struct.sk_buffs(%struct.sk_buff*, i32 immarg, i32 immarg) #2
+
+; Function Attrs: nounwind readnone
+declare %struct.net_device* @llvm.preserve.array.access.index.p0s_struct.net_devices.p0a10s_struct.net_devices([10 x %struct.net_device]*, i32 immarg, i32 immarg) #2
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.net_devices(%struct.net_device*, i32 immarg, i32 immarg) #2
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #1
+
+; Function Attrs: nounwind readnone speculatable
+declare void @llvm.dbg.value(metadata, metadata, metadata) #3
+
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "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 = { argmemonly nounwind }
+attributes #2 = { nounwind readnone }
+attributes #3 = { nounwind readnone speculatable }
+attributes #4 = { nounwind }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!11, !12, !13}
+!llvm.ident = !{!14}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (trunk 360739) (llvm/trunk 360747)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm")
+!2 = !{}
+!3 = !{!4}
+!4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression())
+!5 = distinct !DIGlobalVariable(name: "bpf_probe_read", scope: !0, file: !1, line: 10, type: !6, isLocal: true, isDefinition: true)
+!6 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64)
+!7 = !DISubroutineType(types: !8)
+!8 = !{!9, !10, !9, !10}
+!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!10 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64)
+!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 9.0.0 (trunk 360739) (llvm/trunk 360747)"}
+!15 = distinct !DISubprogram(name: "bpf_prog", scope: !1, file: !1, line: 13, type: !16, scopeLine: 13, flags: DIFlagPrototyped, isLocal: false, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !30)
+!16 = !DISubroutineType(types: !17)
+!17 = !{!9, !18}
+!18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !19, size: 64)
+!19 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "sk_buff", file: !1, line: 5, size: 672, elements: !20)
+!20 = !{!21, !22}
+!21 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !19, file: !1, line: 6, baseType: !9, size: 32)
+!22 = !DIDerivedType(tag: DW_TAG_member, name: "dev", scope: !19, file: !1, line: 7, baseType: !23, size: 640, offset: 32)
+!23 = !DICompositeType(tag: DW_TAG_array_type, baseType: !24, size: 640, elements: !28)
+!24 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "net_device", file: !1, line: 1, size: 64, elements: !25)
+!25 = !{!26, !27}
+!26 = !DIDerivedType(tag: DW_TAG_member, name: "dev_id", scope: !24, file: !1, line: 2, baseType: !9, size: 32)
+!27 = !DIDerivedType(tag: DW_TAG_member, name: "others", scope: !24, file: !1, line: 3, baseType: !9, size: 32, offset: 32)
+!28 = !{!29}
+!29 = !DISubrange(count: 10)
+!30 = !{!31, !32}
+!31 = !DILocalVariable(name: "ctx", arg: 1, scope: !15, file: !1, line: 13, type: !18)
+!32 = !DILocalVariable(name: "dev_id", scope: !15, file: !1, line: 14, type: !9)
+!33 = !DILocation(line: 0, scope: !15)
+!34 = !DILocation(line: 14, column: 3, scope: !15)
+!35 = !DILocation(line: 15, column: 40, scope: !15)
+!36 = !DILocation(line: 15, column: 3, scope: !15)
+!37 = !DILocation(line: 16, column: 10, scope: !15)
+!38 = !{!39, !39, i64 0}
+!39 = !{!"int", !40, i64 0}
+!40 = !{!"omnipotent char", !41, i64 0}
+!41 = !{!"Simple C/C++ TBAA"}
+!42 = !DILocation(line: 17, column: 1, scope: !15)
+!43 = !DILocation(line: 16, column: 3, scope: !15)
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-union.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-union.ll
new file mode 100644
index 00000000000..eefa1ebda73
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-union.ll
@@ -0,0 +1,220 @@
+; 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:
+; union sk_buff {
+; int i;
+; struct {
+; int netid;
+; union {
+; int dev_id;
+; int others;
+; } dev;
+; } u;
+; };
+; #define _(x) (__builtin_preserve_access_index(x))
+; static int (*bpf_probe_read)(void *dst, int size, void *unsafe_ptr)
+; = (void *) 4;
+;
+; int bpf_prog(union sk_buff *ctx) {
+; int dev_id;
+; bpf_probe_read(&dev_id, sizeof(int), _(&ctx->u.dev.dev_id));
+; return dev_id;
+; }
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%union.sk_buff = type { %struct.anon }
+%struct.anon = type { i32, %union.anon }
+%union.anon = type { i32 }
+
+; Function Attrs: nounwind
+define dso_local i32 @bpf_prog(%union.sk_buff*) local_unnamed_addr #0 !dbg !15 {
+ %2 = alloca i32, align 4
+ call void @llvm.dbg.value(metadata %union.sk_buff* %0, metadata !32, metadata !DIExpression()), !dbg !34
+ %3 = bitcast i32* %2 to i8*, !dbg !35
+ call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %3) #4, !dbg !35
+ %4 = tail call %union.sk_buff* @llvm.preserve.union.access.index.p0s_union.sk_buffs.p0s_union.sk_buffs(%union.sk_buff* %0, i32 1), !dbg !36, !llvm.preserve.access.index !19
+ %5 = getelementptr inbounds %union.sk_buff, %union.sk_buff* %4, i64 0, i32 0, !dbg !36
+ %6 = tail call %union.anon* @llvm.preserve.struct.access.index.p0s_union.anons.p0s_struct.anons(%struct.anon* %5, i32 1, i32 1), !dbg !36, !llvm.preserve.access.index !23
+ %7 = tail call %union.anon* @llvm.preserve.union.access.index.p0s_union.anons.p0s_union.anons(%union.anon* %6, i32 0), !dbg !36, !llvm.preserve.access.index !27
+ %8 = bitcast %union.anon* %7 to i8*, !dbg !36
+ %9 = call i32 inttoptr (i64 4 to i32 (i8*, i32, i8*)*)(i8* nonnull %3, i32 4, i8* %8) #4, !dbg !37
+ %10 = load i32, i32* %2, align 4, !dbg !38, !tbaa !39
+ call void @llvm.dbg.value(metadata i32 %10, metadata !33, metadata !DIExpression()), !dbg !34
+ call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %3) #4, !dbg !43
+ ret i32 %10, !dbg !44
+}
+
+; 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 168
+; CHECK-NEXT: .long 168
+; CHECK-NEXT: .long 105
+; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 1)
+; CHECK-NEXT: .long 33554432 # 0x2000000
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 1 # BTF_KIND_UNION(id = 2)
+; CHECK-NEXT: .long 83886082 # 0x5000002
+; CHECK-NEXT: .long 8
+; CHECK-NEXT: .long 9
+; CHECK-NEXT: .long 3
+; CHECK-NEXT: .long 0 # 0x0
+; CHECK-NEXT: .long 11
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long 0 # 0x0
+; CHECK-NEXT: .long 13 # BTF_KIND_INT(id = 3)
+; CHECK-NEXT: .long 16777216 # 0x1000000
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long 16777248 # 0x1000020
+; CHECK-NEXT: .long 0 # BTF_KIND_STRUCT(id = 4)
+; CHECK-NEXT: .long 67108866 # 0x4000002
+; CHECK-NEXT: .long 8
+; CHECK-NEXT: .long 17
+; CHECK-NEXT: .long 3
+; CHECK-NEXT: .long 0 # 0x0
+; CHECK-NEXT: .long 23
+; CHECK-NEXT: .long 5
+; CHECK-NEXT: .long 32 # 0x20
+; CHECK-NEXT: .long 0 # BTF_KIND_UNION(id = 5)
+; CHECK-NEXT: .long 83886082 # 0x5000002
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long 27
+; CHECK-NEXT: .long 3
+; CHECK-NEXT: .long 0 # 0x0
+; CHECK-NEXT: .long 34
+; CHECK-NEXT: .long 3
+; CHECK-NEXT: .long 0 # 0x0
+; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 6)
+; CHECK-NEXT: .long 218103809 # 0xd000001
+; CHECK-NEXT: .long 3
+; CHECK-NEXT: .long 41
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long 45 # BTF_KIND_FUNC(id = 7)
+; CHECK-NEXT: .long 201326592 # 0xc000000
+; CHECK-NEXT: .long 6
+; CHECK-NEXT: .byte 0 # string offset=0
+; CHECK-NEXT: .ascii "sk_buff" # string offset=1
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 105 # string offset=9
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 117 # string offset=11
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "int" # string offset=13
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "netid" # string offset=17
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "dev" # string offset=23
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "dev_id" # string offset=27
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "others" # string offset=34
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "ctx" # string offset=41
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "bpf_prog" # string offset=45
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii ".text" # string offset=54
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "/tmp/home/yhs/work/tests/llvm/test.c" # string offset=60
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "0:1:1:0" # string offset=97
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .section .BTF.ext,"",@progbits
+; CHECK-NEXT: .short 60319 # 0xeb9f
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .long 40
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 20
+; CHECK-NEXT: .long 20
+; CHECK-NEXT: .long 76
+; CHECK-NEXT: .long 96
+; CHECK-NEXT: .long 24
+; CHECK-NEXT: .long 120
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 8 # FuncInfo
+
+; CHECK: .long 12 # OffsetReloc
+; CHECK-NEXT: .long 54 # Offset reloc section string offset=54
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long .Ltmp2
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 97
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1
+
+; Function Attrs: nounwind readnone
+declare %union.sk_buff* @llvm.preserve.union.access.index.p0s_union.sk_buffs.p0s_union.sk_buffs(%union.sk_buff*, i32 immarg) #2
+
+; Function Attrs: nounwind readnone
+declare %union.anon* @llvm.preserve.struct.access.index.p0s_union.anons.p0s_struct.anons(%struct.anon*, i32 immarg, i32 immarg) #2
+
+; Function Attrs: nounwind readnone
+declare %union.anon* @llvm.preserve.union.access.index.p0s_union.anons.p0s_union.anons(%union.anon*, i32 immarg) #2
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #1
+
+; Function Attrs: nounwind readnone speculatable
+declare void @llvm.dbg.value(metadata, metadata, metadata) #3
+
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "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 = { argmemonly nounwind }
+attributes #2 = { nounwind readnone }
+attributes #3 = { nounwind readnone speculatable }
+attributes #4 = { nounwind }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!11, !12, !13}
+!llvm.ident = !{!14}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (trunk 360739) (llvm/trunk 360747)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm")
+!2 = !{}
+!3 = !{!4}
+!4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression())
+!5 = distinct !DIGlobalVariable(name: "bpf_probe_read", scope: !0, file: !1, line: 12, type: !6, isLocal: true, isDefinition: true)
+!6 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64)
+!7 = !DISubroutineType(types: !8)
+!8 = !{!9, !10, !9, !10}
+!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!10 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64)
+!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 9.0.0 (trunk 360739) (llvm/trunk 360747)"}
+!15 = distinct !DISubprogram(name: "bpf_prog", scope: !1, file: !1, line: 15, type: !16, scopeLine: 15, flags: DIFlagPrototyped, isLocal: false, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !31)
+!16 = !DISubroutineType(types: !17)
+!17 = !{!9, !18}
+!18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !19, size: 64)
+!19 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "sk_buff", file: !1, line: 1, size: 64, elements: !20)
+!20 = !{!21, !22}
+!21 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !19, file: !1, line: 2, baseType: !9, size: 32)
+!22 = !DIDerivedType(tag: DW_TAG_member, name: "u", scope: !19, file: !1, line: 9, baseType: !23, size: 64)
+!23 = distinct !DICompositeType(tag: DW_TAG_structure_type, scope: !19, file: !1, line: 3, size: 64, elements: !24)
+!24 = !{!25, !26}
+!25 = !DIDerivedType(tag: DW_TAG_member, name: "netid", scope: !23, file: !1, line: 4, baseType: !9, size: 32)
+!26 = !DIDerivedType(tag: DW_TAG_member, name: "dev", scope: !23, file: !1, line: 8, baseType: !27, size: 32, offset: 32)
+!27 = distinct !DICompositeType(tag: DW_TAG_union_type, scope: !23, file: !1, line: 5, size: 32, elements: !28)
+!28 = !{!29, !30}
+!29 = !DIDerivedType(tag: DW_TAG_member, name: "dev_id", scope: !27, file: !1, line: 6, baseType: !9, size: 32)
+!30 = !DIDerivedType(tag: DW_TAG_member, name: "others", scope: !27, file: !1, line: 7, baseType: !9, size: 32)
+!31 = !{!32, !33}
+!32 = !DILocalVariable(name: "ctx", arg: 1, scope: !15, file: !1, line: 15, type: !18)
+!33 = !DILocalVariable(name: "dev_id", scope: !15, file: !1, line: 16, type: !9)
+!34 = !DILocation(line: 0, scope: !15)
+!35 = !DILocation(line: 16, column: 3, scope: !15)
+!36 = !DILocation(line: 17, column: 40, scope: !15)
+!37 = !DILocation(line: 17, column: 3, scope: !15)
+!38 = !DILocation(line: 18, column: 10, scope: !15)
+!39 = !{!40, !40, i64 0}
+!40 = !{!"int", !41, i64 0}
+!41 = !{!"omnipotent char", !42, i64 0}
+!42 = !{!"Simple C/C++ TBAA"}
+!43 = !DILocation(line: 19, column: 1, scope: !15)
+!44 = !DILocation(line: 18, column: 3, scope: !15)
diff --git a/llvm/test/CodeGen/BPF/CORE/patchable-extern-char.ll b/llvm/test/CodeGen/BPF/CORE/patchable-extern-char.ll
new file mode 100644
index 00000000000..fb30fd5a070
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/CORE/patchable-extern-char.ll
@@ -0,0 +1,107 @@
+; 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 __attribute__((section(".BPF.patchable_externs"))) char a;
+; int foo() { return a; }
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm test.c
+
+@a = external dso_local local_unnamed_addr global i8, section ".BPF.patchable_externs", align 1
+
+; Function Attrs: norecurse nounwind readonly
+define dso_local i32 @foo() local_unnamed_addr #0 !dbg !7 {
+ %1 = load i8, i8* @a, align 1, !dbg !11, !tbaa !12
+ %2 = sext i8 %1 to i32, !dbg !11
+; CHECK: r0 = 0
+; CHECK-NEXT: r0 <<= 56
+; CHECK-NEXT: r0 s>>= 56
+ ret i32 %2, !dbg !15
+}
+
+; 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 40
+; CHECK-NEXT: .long 40
+; CHECK-NEXT: .long 54
+; 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: .byte 0 # string offset=0
+; CHECK-NEXT: .ascii "int" # string offset=1
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "foo" # string offset=5
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii ".text" # string offset=9
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 97 # string offset=15
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "/tmp/home/yhs/work/tests/llvm/test.c" # string offset=17
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .section .BTF.ext,"",@progbits
+; CHECK-NEXT: .short 60319 # 0xeb9f
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .long 40
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 20
+; CHECK-NEXT: .long 20
+; CHECK-NEXT: .long 44
+; CHECK-NEXT: .long 64
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 64
+; CHECK-NEXT: .long 20
+; CHECK-NEXT: .long 8 # FuncInfo
+; CHECK-NEXT: .long 9 # FuncInfo section string offset=9
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long .Lfunc_begin0
+; CHECK-NEXT: .long 3
+; CHECK-NEXT: .long 16 # LineInfo
+; CHECK-NEXT: .long 9 # LineInfo section string offset=9
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 17
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 2068 # Line 2 Col 20
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 17
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 2061 # Line 2 Col 13
+; CHECK-NEXT: .long 8 # ExternReloc
+; CHECK-NEXT: .long 9 # Extern reloc section string offset=9
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 15
+
+attributes #0 = { norecurse nounwind readonly "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "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 = !{!0}
+!llvm.module.flags = !{!3, !4, !5}
+!llvm.ident = !{!6}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 8.0.20181009 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm")
+!2 = !{}
+!3 = !{i32 2, !"Dwarf Version", i32 4}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"wchar_size", i32 4}
+!6 = !{!"clang version 8.0.20181009 "}
+!7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 2, type: !8, isLocal: false, isDefinition: true, scopeLine: 2, isOptimized: true, unit: !0, retainedNodes: !2)
+!8 = !DISubroutineType(types: !9)
+!9 = !{!10}
+!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!11 = !DILocation(line: 2, column: 20, scope: !7)
+!12 = !{!13, !13, i64 0}
+!13 = !{!"omnipotent char", !14, i64 0}
+!14 = !{!"Simple C/C++ TBAA"}
+!15 = !DILocation(line: 2, column: 13, scope: !7)
diff --git a/llvm/test/CodeGen/BPF/CORE/patchable-extern-uint.ll b/llvm/test/CodeGen/BPF/CORE/patchable-extern-uint.ll
new file mode 100644
index 00000000000..ba3770b4736
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/CORE/patchable-extern-uint.ll
@@ -0,0 +1,102 @@
+; 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 __attribute__((section(".BPF.patchable_externs"))) unsigned a;
+; int foo() { return a; }
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm test.c
+
+@a = external dso_local local_unnamed_addr global i32, section ".BPF.patchable_externs", align 4
+
+; Function Attrs: norecurse nounwind readonly
+define dso_local i32 @foo() local_unnamed_addr #0 !dbg !7 {
+ %1 = load i32, i32* @a, align 4, !dbg !11, !tbaa !12
+; CHECK: r0 = 0
+; CHECK-NEXT: exit
+ ret i32 %1, !dbg !16
+}
+
+; 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 40
+; CHECK-NEXT: .long 40
+; CHECK-NEXT: .long 49
+; 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: .byte 0 # string offset=0
+; CHECK-NEXT: .ascii "int" # string offset=1
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "foo" # string offset=5
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii ".text" # string offset=9
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 97 # string offset=15
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "/tmp/yhs/work/tests/llvm/test.c" # string offset=17
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .section .BTF.ext,"",@progbits
+; CHECK-NEXT: .short 60319 # 0xeb9f
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .long 40
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 20
+; CHECK-NEXT: .long 20
+; CHECK-NEXT: .long 28
+; CHECK-NEXT: .long 48
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 48
+; CHECK-NEXT: .long 20
+; CHECK-NEXT: .long 8 # FuncInfo
+; CHECK-NEXT: .long 9 # FuncInfo section string offset=9
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long .Lfunc_begin0
+; CHECK-NEXT: .long 3
+; CHECK-NEXT: .long 16 # LineInfo
+; CHECK-NEXT: .long 9 # LineInfo section string offset=9
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 17
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 2061 # Line 2 Col 13
+; CHECK-NEXT: .long 8 # ExternReloc
+; CHECK-NEXT: .long 9 # Extern reloc section string offset=9
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 15
+
+attributes #0 = { norecurse nounwind readonly "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "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 = !{!0}
+!llvm.module.flags = !{!3, !4, !5}
+!llvm.ident = !{!6}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 8.0.20181009 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/yhs/work/tests/llvm")
+!2 = !{}
+!3 = !{i32 2, !"Dwarf Version", i32 4}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"wchar_size", i32 4}
+!6 = !{!"clang version 8.0.20181009 "}
+!7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 2, type: !8, isLocal: false, isDefinition: true, scopeLine: 2, isOptimized: true, unit: !0, retainedNodes: !2)
+!8 = !DISubroutineType(types: !9)
+!9 = !{!10}
+!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!11 = !DILocation(line: 2, column: 20, scope: !7)
+!12 = !{!13, !13, i64 0}
+!13 = !{!"int", !14, i64 0}
+!14 = !{!"omnipotent char", !15, i64 0}
+!15 = !{!"Simple C/C++ TBAA"}
+!16 = !DILocation(line: 2, column: 13, scope: !7)
diff --git a/llvm/test/CodeGen/BPF/CORE/patchable-extern-ulonglong.ll b/llvm/test/CodeGen/BPF/CORE/patchable-extern-ulonglong.ll
new file mode 100644
index 00000000000..c483cceadc8
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/CORE/patchable-extern-ulonglong.ll
@@ -0,0 +1,103 @@
+; 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 __attribute__((section(".BPF.patchable_externs"))) unsigned long long a;
+; int foo() { return a; }
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm test.c
+
+@a = external dso_local local_unnamed_addr global i64, section ".BPF.patchable_externs", align 8
+
+; Function Attrs: norecurse nounwind readonly
+define dso_local i32 @foo() local_unnamed_addr #0 !dbg !7 {
+ %1 = load i64, i64* @a, align 8, !dbg !11, !tbaa !12
+ %2 = trunc i64 %1 to i32, !dbg !11
+; CHECK: r0 = 0 ll
+; CHECK-NEXT: exit
+ ret i32 %2, !dbg !16
+}
+
+; 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 40
+; CHECK-NEXT: .long 40
+; CHECK-NEXT: .long 54
+; 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: .byte 0 # string offset=0
+; CHECK-NEXT: .ascii "int" # string offset=1
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "foo" # string offset=5
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii ".text" # string offset=9
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 97 # string offset=15
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "/tmp/home/yhs/work/tests/llvm/test.c" # string offset=17
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .section .BTF.ext,"",@progbits
+; CHECK-NEXT: .short 60319 # 0xeb9f
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .long 40
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 20
+; CHECK-NEXT: .long 20
+; CHECK-NEXT: .long 28
+; CHECK-NEXT: .long 48
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 48
+; CHECK-NEXT: .long 20
+; CHECK-NEXT: .long 8 # FuncInfo
+; CHECK-NEXT: .long 9 # FuncInfo section string offset=9
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long .Lfunc_begin0
+; CHECK-NEXT: .long 3
+; CHECK-NEXT: .long 16 # LineInfo
+; CHECK-NEXT: .long 9 # LineInfo section string offset=9
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 17
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 2061 # Line 2 Col 13
+; CHECK-NEXT: .long 8 # ExternReloc
+; CHECK-NEXT: .long 9 # Extern reloc section string offset=9
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long 15
+
+attributes #0 = { norecurse nounwind readonly "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "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 = !{!0}
+!llvm.module.flags = !{!3, !4, !5}
+!llvm.ident = !{!6}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 8.0.20181009 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm")
+!2 = !{}
+!3 = !{i32 2, !"Dwarf Version", i32 4}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"wchar_size", i32 4}
+!6 = !{!"clang version 8.0.20181009 "}
+!7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 2, type: !8, isLocal: false, isDefinition: true, scopeLine: 2, isOptimized: true, unit: !0, retainedNodes: !2)
+!8 = !DISubroutineType(types: !9)
+!9 = !{!10}
+!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!11 = !DILocation(line: 2, column: 20, scope: !7)
+!12 = !{!13, !13, i64 0}
+!13 = !{!"long long", !14, i64 0}
+!14 = !{!"omnipotent char", !15, i64 0}
+!15 = !{!"Simple C/C++ TBAA"}
+!16 = !DILocation(line: 2, column: 13, scope: !7)
diff --git a/llvm/test/CodeGen/BPF/reloc-btf-2.ll b/llvm/test/CodeGen/BPF/reloc-btf-2.ll
index feabb089153..2871daa38f8 100644
--- a/llvm/test/CodeGen/BPF/reloc-btf-2.ll
+++ b/llvm/test/CodeGen/BPF/reloc-btf-2.ll
@@ -47,7 +47,7 @@ attributes #0 = { norecurse nounwind "correctly-rounded-divide-sqrt-fp-math"="fa
!11 = !{i32 2, !"Debug Info Version", i32 3}
!12 = !{i32 1, !"wchar_size", i32 4}
!13 = !{!"clang version 9.0.0 (trunk 360739) (llvm/trunk 360747)"}
-!14 = distinct !DISubprogram(name: "test", scope: !3, file: !3, line: 3, type: !15, scopeLine: 3, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !4)
+!14 = distinct !DISubprogram(name: "test", scope: !3, file: !3, line: 3, type: !15, scopeLine: 3, isLocal: false, isDefinition: true, isOptimized: true, unit: !2, retainedNodes: !4)
!15 = !DISubroutineType(types: !16)
!16 = !{!9}
!17 = !DILocation(line: 4, column: 10, scope: !14)
OpenPOWER on IntegriCloud