Blame 0001-BPF-Handling-type-conversions-correctly-for-CO-RE.patch

1243758
From 20253836fbb1baf5c7cd6fb6558bd12dff682855 Mon Sep 17 00:00:00 2001
1243758
From: Yonghong Song <yhs@fb.com>
1243758
Date: Fri, 2 Aug 2019 23:16:44 +0000
1243758
Subject: [PATCH] [BPF] Handling type conversions correctly for CO-RE
1243758
1243758
With newly added debuginfo type
1243758
metadata for preserve_array_access_index() intrinsic,
1243758
this patch did the following two things:
1243758
 (1). checking validity before adding a new access index
1243758
      to the access chain.
1243758
 (2). calculating access byte offset in IR phase
1243758
      BPFAbstractMemberAccess instead of when BTF is emitted.
1243758
1243758
For (1), the metadata provided by all preserve_*_access_index()
1243758
intrinsics are used to check whether the to-be-added type
1243758
is a proper struct/union member or array element.
1243758
1243758
For (2), with all available metadata, calculating access byte
1243758
offset becomes easier in BPFAbstractMemberAccess IR phase.
1243758
This enables us to remove the unnecessary complexity in
1243758
BTFDebug.cpp.
1243758
1243758
New tests are added for
1243758
  . user explicit casting to array/structure/union
1243758
  . global variable (or its dereference) as the source of base
1243758
  . multi demensional arrays
1243758
  . array access given a base pointer
1243758
  . cases where we won't generate relocation if we cannot find
1243758
    type name.
1243758
1243758
Differential Revision: https://reviews.llvm.org/D65618
1243758
1243758
llvm-svn: 367735
1243758
(cherry picked from commit 37d24a696bf74f4830f2582d2f36256ca1b6bb30)
1243758
---
1243758
 llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp    | 332 +++++++++++++++++----
1243758
 llvm/lib/Target/BPF/BTFDebug.cpp                   | 110 +------
1243758
 llvm/lib/Target/BPF/BTFDebug.h                     |  15 +-
1243758
 .../CodeGen/BPF/CORE/offset-reloc-cast-array-1.ll  | 124 ++++++++
1243758
 .../CodeGen/BPF/CORE/offset-reloc-cast-array-2.ll  | 131 ++++++++
1243758
 .../CodeGen/BPF/CORE/offset-reloc-cast-struct-1.ll | 112 +++++++
1243758
 .../CodeGen/BPF/CORE/offset-reloc-cast-struct-2.ll | 117 ++++++++
1243758
 .../CodeGen/BPF/CORE/offset-reloc-cast-struct-3.ll | 116 +++++++
1243758
 .../CodeGen/BPF/CORE/offset-reloc-cast-union-1.ll  | 117 ++++++++
1243758
 .../CodeGen/BPF/CORE/offset-reloc-cast-union-2.ll  | 118 ++++++++
1243758
 .../test/CodeGen/BPF/CORE/offset-reloc-global-1.ll |  79 +++++
1243758
 .../test/CodeGen/BPF/CORE/offset-reloc-global-2.ll |  95 ++++++
1243758
 .../test/CodeGen/BPF/CORE/offset-reloc-global-3.ll |  84 ++++++
1243758
 llvm/test/CodeGen/BPF/CORE/offset-reloc-ignore.ll  |  62 ++++
1243758
 .../CodeGen/BPF/CORE/offset-reloc-multi-array-1.ll | 101 +++++++
1243758
 .../CodeGen/BPF/CORE/offset-reloc-multi-array-2.ll | 107 +++++++
1243758
 .../CodeGen/BPF/CORE/offset-reloc-pointer-1.ll     |  83 ++++++
1243758
 .../CodeGen/BPF/CORE/offset-reloc-pointer-2.ll     |  85 ++++++
1243758
 .../BPF/CORE/offset-reloc-struct-anonymous.ll      |   2 +-
1243758
 .../CodeGen/BPF/CORE/offset-reloc-struct-array.ll  |   2 +-
1243758
 .../CodeGen/BPF/CORE/offset-reloc-typedef-array.ll |   2 +-
1243758
 llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef.ll |   2 +-
1243758
 22 files changed, 1812 insertions(+), 184 deletions(-)
1243758
 create mode 100644 llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-array-1.ll
1243758
 create mode 100644 llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-array-2.ll
1243758
 create mode 100644 llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-1.ll
1243758
 create mode 100644 llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-2.ll
1243758
 create mode 100644 llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-3.ll
1243758
 create mode 100644 llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-union-1.ll
1243758
 create mode 100644 llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-union-2.ll
1243758
 create mode 100644 llvm/test/CodeGen/BPF/CORE/offset-reloc-global-1.ll
1243758
 create mode 100644 llvm/test/CodeGen/BPF/CORE/offset-reloc-global-2.ll
1243758
 create mode 100644 llvm/test/CodeGen/BPF/CORE/offset-reloc-global-3.ll
1243758
 create mode 100644 llvm/test/CodeGen/BPF/CORE/offset-reloc-ignore.ll
1243758
 create mode 100644 llvm/test/CodeGen/BPF/CORE/offset-reloc-multi-array-1.ll
1243758
 create mode 100644 llvm/test/CodeGen/BPF/CORE/offset-reloc-multi-array-2.ll
1243758
 create mode 100644 llvm/test/CodeGen/BPF/CORE/offset-reloc-pointer-1.ll
1243758
 create mode 100644 llvm/test/CodeGen/BPF/CORE/offset-reloc-pointer-2.ll
1243758
1243758
diff --git a/llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp b/llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp
1243758
index 509484b..f55f6f9 100644
1243758
--- a/llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp
1243758
+++ b/llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp
1243758
@@ -65,6 +65,7 @@
1243758
 #include "llvm/IR/Value.h"
1243758
 #include "llvm/Pass.h"
1243758
 #include "llvm/Transforms/Utils/BasicBlockUtils.h"
1243758
+#include <stack>
1243758
 
1243758
 #define DEBUG_TYPE "bpf-abstract-member-access"
1243758
 
1243758
@@ -106,18 +107,24 @@ private:
1243758
 
1243758
   bool doTransformation(Module &M);
1243758
 
1243758
-  void traceAICall(CallInst *Call, uint32_t Kind);
1243758
-  void traceBitCast(BitCastInst *BitCast, CallInst *Parent, uint32_t Kind);
1243758
-  void traceGEP(GetElementPtrInst *GEP, CallInst *Parent, uint32_t Kind);
1243758
+  void traceAICall(CallInst *Call, uint32_t Kind, const MDNode *ParentMeta,
1243758
+                   uint32_t ParentAI);
1243758
+  void traceBitCast(BitCastInst *BitCast, CallInst *Parent, uint32_t Kind,
1243758
+                    const MDNode *ParentMeta, uint32_t ParentAI);
1243758
+  void traceGEP(GetElementPtrInst *GEP, CallInst *Parent, uint32_t Kind,
1243758
+                const MDNode *ParentMeta, uint32_t ParentAI);
1243758
   void collectAICallChains(Module &M, Function &F);
1243758
 
1243758
-  bool IsPreserveDIAccessIndexCall(const CallInst *Call, uint32_t &Kind);
1243758
+  bool IsPreserveDIAccessIndexCall(const CallInst *Call, uint32_t &Kind,
1243758
+                                   const MDNode *&TypeMeta, uint32_t &AccessIndex);
1243758
+  bool IsValidAIChain(const MDNode *ParentMeta, uint32_t ParentAI,
1243758
+                      const MDNode *ChildMeta);
1243758
   bool removePreserveAccessIndexIntrinsic(Module &M);
1243758
   void replaceWithGEP(std::vector<CallInst *> &CallList,
1243758
                       uint32_t NumOfZerosIndex, uint32_t DIIndex);
1243758
 
1243758
   Value *computeBaseAndAccessKey(CallInst *Call, std::string &AccessKey,
1243758
-                                 uint32_t Kind, MDNode *&TypeMeta);
1243758
+                                 uint32_t Kind, MDNode *&BaseMeta);
1243758
   bool getAccessIndex(const Value *IndexValue, uint64_t &AccessIndex);
1243758
   bool transformGEPChain(Module &M, CallInst *Call, uint32_t Kind);
1243758
 };
1243758
@@ -141,9 +148,53 @@ bool BPFAbstractMemberAccess::runOnModule(Module &M) {
1243758
   return doTransformation(M);
1243758
 }
1243758
 
1243758
+static bool SkipDIDerivedTag(unsigned Tag) {
1243758
+  if (Tag != dwarf::DW_TAG_typedef && Tag != dwarf::DW_TAG_const_type &&
1243758
+      Tag != dwarf::DW_TAG_volatile_type &&
1243758
+      Tag != dwarf::DW_TAG_restrict_type &&
1243758
+      Tag != dwarf::DW_TAG_member)
1243758
+     return false;
1243758
+  return true;
1243758
+}
1243758
+
1243758
+static DIType * stripQualifiers(DIType *Ty) {
1243758
+  while (auto *DTy = dyn_cast<DIDerivedType>(Ty)) {
1243758
+    if (!SkipDIDerivedTag(DTy->getTag()))
1243758
+      break;
1243758
+    Ty = DTy->getBaseType();
1243758
+  }
1243758
+  return Ty;
1243758
+}
1243758
+
1243758
+static const DIType * stripQualifiers(const DIType *Ty) {
1243758
+  while (auto *DTy = dyn_cast<DIDerivedType>(Ty)) {
1243758
+    if (!SkipDIDerivedTag(DTy->getTag()))
1243758
+      break;
1243758
+    Ty = DTy->getBaseType();
1243758
+  }
1243758
+  return Ty;
1243758
+}
1243758
+
1243758
+static uint32_t calcArraySize(const DICompositeType *CTy, uint32_t StartDim) {
1243758
+  DINodeArray Elements = CTy->getElements();
1243758
+  uint32_t DimSize = 1;
1243758
+  for (uint32_t I = StartDim; I < Elements.size(); ++I) {
1243758
+    if (auto *Element = dyn_cast_or_null<DINode>(Elements[I]))
1243758
+      if (Element->getTag() == dwarf::DW_TAG_subrange_type) {
1243758
+        const DISubrange *SR = cast<DISubrange>(Element);
1243758
+        auto *CI = SR->getCount().dyn_cast<ConstantInt *>();
1243758
+        DimSize *= CI->getSExtValue();
1243758
+      }
1243758
+  }
1243758
+
1243758
+  return DimSize;
1243758
+}
1243758
+
1243758
 /// Check whether a call is a preserve_*_access_index intrinsic call or not.
1243758
 bool BPFAbstractMemberAccess::IsPreserveDIAccessIndexCall(const CallInst *Call,
1243758
-                                                          uint32_t &Kind) {
1243758
+                                                          uint32_t &Kind,
1243758
+                                                          const MDNode *&TypeMeta,
1243758
+                                                          uint32_t &AccessIndex) {
1243758
   if (!Call)
1243758
     return false;
1243758
 
1243758
@@ -152,14 +203,29 @@ bool BPFAbstractMemberAccess::IsPreserveDIAccessIndexCall(const CallInst *Call,
1243758
     return false;
1243758
   if (GV->getName().startswith("llvm.preserve.array.access.index")) {
1243758
     Kind = BPFPreserveArrayAI;
1243758
+    TypeMeta = Call->getMetadata(LLVMContext::MD_preserve_access_index);
1243758
+    if (!TypeMeta)
1243758
+      report_fatal_error("Missing metadata for llvm.preserve.array.access.index intrinsic");
1243758
+    AccessIndex = cast<ConstantInt>(Call->getArgOperand(2))
1243758
+                      ->getZExtValue();
1243758
     return true;
1243758
   }
1243758
   if (GV->getName().startswith("llvm.preserve.union.access.index")) {
1243758
     Kind = BPFPreserveUnionAI;
1243758
+    TypeMeta = Call->getMetadata(LLVMContext::MD_preserve_access_index);
1243758
+    if (!TypeMeta)
1243758
+      report_fatal_error("Missing metadata for llvm.preserve.union.access.index intrinsic");
1243758
+    AccessIndex = cast<ConstantInt>(Call->getArgOperand(1))
1243758
+                      ->getZExtValue();
1243758
     return true;
1243758
   }
1243758
   if (GV->getName().startswith("llvm.preserve.struct.access.index")) {
1243758
     Kind = BPFPreserveStructAI;
1243758
+    TypeMeta = Call->getMetadata(LLVMContext::MD_preserve_access_index);
1243758
+    if (!TypeMeta)
1243758
+      report_fatal_error("Missing metadata for llvm.preserve.struct.access.index intrinsic");
1243758
+    AccessIndex = cast<ConstantInt>(Call->getArgOperand(2))
1243758
+                      ->getZExtValue();
1243758
     return true;
1243758
   }
1243758
 
1243758
@@ -200,7 +266,9 @@ bool BPFAbstractMemberAccess::removePreserveAccessIndexIntrinsic(Module &M) {
1243758
       for (auto &I : BB) {
1243758
         auto *Call = dyn_cast<CallInst>(&I);
1243758
         uint32_t Kind;
1243758
-        if (!IsPreserveDIAccessIndexCall(Call, Kind))
1243758
+        const MDNode *TypeMeta;
1243758
+        uint32_t AccessIndex;
1243758
+        if (!IsPreserveDIAccessIndexCall(Call, Kind, TypeMeta, AccessIndex))
1243758
           continue;
1243758
 
1243758
         Found = true;
1243758
@@ -232,25 +300,79 @@ bool BPFAbstractMemberAccess::removePreserveAccessIndexIntrinsic(Module &M) {
1243758
   return Found;
1243758
 }
1243758
 
1243758
-void BPFAbstractMemberAccess::traceAICall(CallInst *Call, uint32_t Kind) {
1243758
+/// Check whether the access index chain is valid. We check
1243758
+/// here because there may be type casts between two
1243758
+/// access indexes. We want to ensure memory access still valid.
1243758
+bool BPFAbstractMemberAccess::IsValidAIChain(const MDNode *ParentType,
1243758
+                                             uint32_t ParentAI,
1243758
+                                             const MDNode *ChildType) {
1243758
+  const DIType *PType = stripQualifiers(cast<DIType>(ParentType));
1243758
+  const DIType *CType = stripQualifiers(cast<DIType>(ChildType));
1243758
+
1243758
+  // Child is a derived/pointer type, which is due to type casting.
1243758
+  // Pointer type cannot be in the middle of chain.
1243758
+  if (const auto *PtrTy = dyn_cast<DIDerivedType>(CType))
1243758
+    return false;
1243758
+
1243758
+  // Parent is a pointer type.
1243758
+  if (const auto *PtrTy = dyn_cast<DIDerivedType>(PType)) {
1243758
+    if (PtrTy->getTag() != dwarf::DW_TAG_pointer_type)
1243758
+      return false;
1243758
+    return stripQualifiers(PtrTy->getBaseType()) == CType;
1243758
+  }
1243758
+
1243758
+  // Otherwise, struct/union/array types
1243758
+  const auto *PTy = dyn_cast<DICompositeType>(PType);
1243758
+  const auto *CTy = dyn_cast<DICompositeType>(CType);
1243758
+  assert(PTy && CTy && "ParentType or ChildType is null or not composite");
1243758
+
1243758
+  uint32_t PTyTag = PTy->getTag();
1243758
+  assert(PTyTag == dwarf::DW_TAG_array_type ||
1243758
+         PTyTag == dwarf::DW_TAG_structure_type ||
1243758
+         PTyTag == dwarf::DW_TAG_union_type);
1243758
+
1243758
+  uint32_t CTyTag = CTy->getTag();
1243758
+  assert(CTyTag == dwarf::DW_TAG_array_type ||
1243758
+         CTyTag == dwarf::DW_TAG_structure_type ||
1243758
+         CTyTag == dwarf::DW_TAG_union_type);
1243758
+
1243758
+  // Multi dimensional arrays, base element should be the same
1243758
+  if (PTyTag == dwarf::DW_TAG_array_type && PTyTag == CTyTag)
1243758
+    return PTy->getBaseType() == CTy->getBaseType();
1243758
+
1243758
+  DIType *Ty;
1243758
+  if (PTyTag == dwarf::DW_TAG_array_type)
1243758
+    Ty = PTy->getBaseType();
1243758
+  else
1243758
+    Ty = dyn_cast<DIType>(PTy->getElements()[ParentAI]);
1243758
+
1243758
+  return dyn_cast<DICompositeType>(stripQualifiers(Ty)) == CTy;
1243758
+}
1243758
+
1243758
+void BPFAbstractMemberAccess::traceAICall(CallInst *Call, uint32_t Kind,
1243758
+                                          const MDNode *ParentMeta,
1243758
+                                          uint32_t ParentAI) {
1243758
   for (User *U : Call->users()) {
1243758
     Instruction *Inst = dyn_cast<Instruction>(U);
1243758
     if (!Inst)
1243758
       continue;
1243758
 
1243758
     if (auto *BI = dyn_cast<BitCastInst>(Inst)) {
1243758
-      traceBitCast(BI, Call, Kind);
1243758
+      traceBitCast(BI, Call, Kind, ParentMeta, ParentAI);
1243758
     } else if (auto *CI = dyn_cast<CallInst>(Inst)) {
1243758
       uint32_t CIKind;
1243758
-      if (IsPreserveDIAccessIndexCall(CI, CIKind)) {
1243758
+      const MDNode *ChildMeta;
1243758
+      uint32_t ChildAI;
1243758
+      if (IsPreserveDIAccessIndexCall(CI, CIKind, ChildMeta, ChildAI) &&
1243758
+          IsValidAIChain(ParentMeta, ParentAI, ChildMeta)) {
1243758
         AIChain[CI] = std::make_pair(Call, Kind);
1243758
-        traceAICall(CI, CIKind);
1243758
+        traceAICall(CI, CIKind, ChildMeta, ChildAI);
1243758
       } else {
1243758
         BaseAICalls[Call] = Kind;
1243758
       }
1243758
     } else if (auto *GI = dyn_cast<GetElementPtrInst>(Inst)) {
1243758
       if (GI->hasAllZeroIndices())
1243758
-        traceGEP(GI, Call, Kind);
1243758
+        traceGEP(GI, Call, Kind, ParentMeta, ParentAI);
1243758
       else
1243758
         BaseAICalls[Call] = Kind;
1243758
     }
1243758
@@ -258,25 +380,30 @@ void BPFAbstractMemberAccess::traceAICall(CallInst *Call, uint32_t Kind) {
1243758
 }
1243758
 
1243758
 void BPFAbstractMemberAccess::traceBitCast(BitCastInst *BitCast,
1243758
-                                           CallInst *Parent, uint32_t Kind) {
1243758
+                                           CallInst *Parent, uint32_t Kind,
1243758
+                                           const MDNode *ParentMeta,
1243758
+                                           uint32_t ParentAI) {
1243758
   for (User *U : BitCast->users()) {
1243758
     Instruction *Inst = dyn_cast<Instruction>(U);
1243758
     if (!Inst)
1243758
       continue;
1243758
 
1243758
     if (auto *BI = dyn_cast<BitCastInst>(Inst)) {
1243758
-      traceBitCast(BI, Parent, Kind);
1243758
+      traceBitCast(BI, Parent, Kind, ParentMeta, ParentAI);
1243758
     } else if (auto *CI = dyn_cast<CallInst>(Inst)) {
1243758
       uint32_t CIKind;
1243758
-      if (IsPreserveDIAccessIndexCall(CI, CIKind)) {
1243758
+      const MDNode *ChildMeta;
1243758
+      uint32_t ChildAI;
1243758
+      if (IsPreserveDIAccessIndexCall(CI, CIKind, ChildMeta, ChildAI) &&
1243758
+          IsValidAIChain(ParentMeta, ParentAI, ChildMeta)) {
1243758
         AIChain[CI] = std::make_pair(Parent, Kind);
1243758
-        traceAICall(CI, CIKind);
1243758
+        traceAICall(CI, CIKind, ChildMeta, ChildAI);
1243758
       } else {
1243758
         BaseAICalls[Parent] = Kind;
1243758
       }
1243758
     } else if (auto *GI = dyn_cast<GetElementPtrInst>(Inst)) {
1243758
       if (GI->hasAllZeroIndices())
1243758
-        traceGEP(GI, Parent, Kind);
1243758
+        traceGEP(GI, Parent, Kind, ParentMeta, ParentAI);
1243758
       else
1243758
         BaseAICalls[Parent] = Kind;
1243758
     }
1243758
@@ -284,25 +411,29 @@ void BPFAbstractMemberAccess::traceBitCast(BitCastInst *BitCast,
1243758
 }
1243758
 
1243758
 void BPFAbstractMemberAccess::traceGEP(GetElementPtrInst *GEP, CallInst *Parent,
1243758
-                                       uint32_t Kind) {
1243758
+                                       uint32_t Kind, const MDNode *ParentMeta,
1243758
+                                       uint32_t ParentAI) {
1243758
   for (User *U : GEP->users()) {
1243758
     Instruction *Inst = dyn_cast<Instruction>(U);
1243758
     if (!Inst)
1243758
       continue;
1243758
 
1243758
     if (auto *BI = dyn_cast<BitCastInst>(Inst)) {
1243758
-      traceBitCast(BI, Parent, Kind);
1243758
+      traceBitCast(BI, Parent, Kind, ParentMeta, ParentAI);
1243758
     } else if (auto *CI = dyn_cast<CallInst>(Inst)) {
1243758
       uint32_t CIKind;
1243758
-      if (IsPreserveDIAccessIndexCall(CI, CIKind)) {
1243758
+      const MDNode *ChildMeta;
1243758
+      uint32_t ChildAI;
1243758
+      if (IsPreserveDIAccessIndexCall(CI, CIKind, ChildMeta, ChildAI) &&
1243758
+          IsValidAIChain(ParentMeta, ParentAI, ChildMeta)) {
1243758
         AIChain[CI] = std::make_pair(Parent, Kind);
1243758
-        traceAICall(CI, CIKind);
1243758
+        traceAICall(CI, CIKind, ChildMeta, ChildAI);
1243758
       } else {
1243758
         BaseAICalls[Parent] = Kind;
1243758
       }
1243758
     } else if (auto *GI = dyn_cast<GetElementPtrInst>(Inst)) {
1243758
       if (GI->hasAllZeroIndices())
1243758
-        traceGEP(GI, Parent, Kind);
1243758
+        traceGEP(GI, Parent, Kind, ParentMeta, ParentAI);
1243758
       else
1243758
         BaseAICalls[Parent] = Kind;
1243758
     }
1243758
@@ -316,12 +447,14 @@ void BPFAbstractMemberAccess::collectAICallChains(Module &M, Function &F) {
1243758
   for (auto &BB : F)
1243758
     for (auto &I : BB) {
1243758
       uint32_t Kind;
1243758
+      const MDNode *TypeMeta;
1243758
+      uint32_t AccessIndex;
1243758
       auto *Call = dyn_cast<CallInst>(&I);
1243758
-      if (!IsPreserveDIAccessIndexCall(Call, Kind) ||
1243758
+      if (!IsPreserveDIAccessIndexCall(Call, Kind, TypeMeta, AccessIndex) ||
1243758
           AIChain.find(Call) != AIChain.end())
1243758
         continue;
1243758
 
1243758
-      traceAICall(Call, Kind);
1243758
+      traceAICall(Call, Kind, TypeMeta, AccessIndex);
1243758
     }
1243758
 }
1243758
 
1243758
@@ -344,62 +477,131 @@ Value *BPFAbstractMemberAccess::computeBaseAndAccessKey(CallInst *Call,
1243758
                                                         uint32_t Kind,
1243758
                                                         MDNode *&TypeMeta) {
1243758
   Value *Base = nullptr;
1243758
-  std::vector<uint64_t> AccessIndices;
1243758
-  uint64_t TypeNameIndex = 0;
1243758
-  std::string LastTypeName;
1243758
+  std::string TypeName;
1243758
+  std::stack<std::pair<CallInst *, uint32_t>> CallStack;
1243758
 
1243758
+  // Put the access chain into a stack with the top as the head of the chain.
1243758
   while (Call) {
1243758
-    // Base of original corresponding GEP
1243758
-    Base = Call->getArgOperand(0);
1243758
+    CallStack.push(std::make_pair(Call, Kind));
1243758
+    Kind = AIChain[Call].second;
1243758
+    Call = AIChain[Call].first;
1243758
+  }
1243758
 
1243758
-    // Type Name
1243758
-    std::string TypeName;
1243758
-    MDNode *MDN;
1243758
+  // The access offset from the base of the head of chain is also
1243758
+  // calculated here as all debuginfo types are available.
1243758
+
1243758
+  // Get type name and calculate the first index.
1243758
+  // We only want to get type name from structure or union.
1243758
+  // If user wants a relocation like
1243758
+  //    int *p; ... __builtin_preserve_access_index(&p[4]) ...
1243758
+  // or
1243758
+  //    int a[10][20]; ... __builtin_preserve_access_index(&a[2][3]) ...
1243758
+  // we will skip them.
1243758
+  uint32_t FirstIndex = 0;
1243758
+  uint32_t AccessOffset = 0;
1243758
+  while (CallStack.size()) {
1243758
+    auto StackElem = CallStack.top();
1243758
+    Call = StackElem.first;
1243758
+    Kind = StackElem.second;
1243758
+
1243758
+    if (!Base)
1243758
+      Base = Call->getArgOperand(0);
1243758
+
1243758
+    MDNode *MDN = Call->getMetadata(LLVMContext::MD_preserve_access_index);
1243758
+    DIType *Ty = stripQualifiers(cast<DIType>(MDN));
1243758
     if (Kind == BPFPreserveUnionAI || Kind == BPFPreserveStructAI) {
1243758
-      MDN = Call->getMetadata(LLVMContext::MD_preserve_access_index);
1243758
-      if (!MDN)
1243758
-        return nullptr;
1243758
+      // struct or union type
1243758
+      TypeName = Ty->getName();
1243758
+      TypeMeta = Ty;
1243758
+      AccessOffset += FirstIndex * Ty->getSizeInBits() >> 3;
1243758
+      break;
1243758
+    }
1243758
 
1243758
-      DIType *Ty = dyn_cast<DIType>(MDN);
1243758
-      if (!Ty)
1243758
+    // Array entries will always be consumed for accumulative initial index.
1243758
+    CallStack.pop();
1243758
+
1243758
+    // BPFPreserveArrayAI
1243758
+    uint64_t AccessIndex;
1243758
+    if (!getAccessIndex(Call->getArgOperand(2), AccessIndex))
1243758
+      return nullptr;
1243758
+
1243758
+    DIType *BaseTy = nullptr;
1243758
+    bool CheckElemType = false;
1243758
+    if (const auto *CTy = dyn_cast<DICompositeType>(Ty)) {
1243758
+      // array type
1243758
+      assert(CTy->getTag() == dwarf::DW_TAG_array_type);
1243758
+
1243758
+
1243758
+      FirstIndex += AccessIndex * calcArraySize(CTy, 1);
1243758
+      BaseTy = stripQualifiers(CTy->getBaseType());
1243758
+      CheckElemType = CTy->getElements().size() == 1;
1243758
+    } else {
1243758
+      // pointer type
1243758
+      auto *DTy = cast<DIDerivedType>(Ty);
1243758
+      assert(DTy->getTag() == dwarf::DW_TAG_pointer_type);
1243758
+
1243758
+      BaseTy = stripQualifiers(DTy->getBaseType());
1243758
+      CTy = dyn_cast<DICompositeType>(BaseTy);
1243758
+      if (!CTy) {
1243758
+        CheckElemType = true;
1243758
+      } else if (CTy->getTag() != dwarf::DW_TAG_array_type) {
1243758
+        FirstIndex += AccessIndex;
1243758
+        CheckElemType = true;
1243758
+      } else {
1243758
+        FirstIndex += AccessIndex * calcArraySize(CTy, 0);
1243758
+      }
1243758
+    }
1243758
+
1243758
+    if (CheckElemType) {
1243758
+      auto *CTy = dyn_cast<DICompositeType>(BaseTy);
1243758
+      if (!CTy)
1243758
         return nullptr;
1243758
 
1243758
-      TypeName = Ty->getName();
1243758
+      unsigned CTag = CTy->getTag();
1243758
+      if (CTag != dwarf::DW_TAG_structure_type && CTag != dwarf::DW_TAG_union_type)
1243758
+        return nullptr;
1243758
+      else
1243758
+        TypeName = CTy->getName();
1243758
+      TypeMeta = CTy;
1243758
+      AccessOffset += FirstIndex * CTy->getSizeInBits() >> 3;
1243758
+      break;
1243758
     }
1243758
+  }
1243758
+  assert(TypeName.size());
1243758
+  AccessKey += std::to_string(FirstIndex);
1243758
+
1243758
+  // Traverse the rest of access chain to complete offset calculation
1243758
+  // and access key construction.
1243758
+  while (CallStack.size()) {
1243758
+    auto StackElem = CallStack.top();
1243758
+    Call = StackElem.first;
1243758
+    Kind = StackElem.second;
1243758
+    CallStack.pop();
1243758
 
1243758
     // Access Index
1243758
     uint64_t AccessIndex;
1243758
     uint32_t ArgIndex = (Kind == BPFPreserveUnionAI) ? 1 : 2;
1243758
     if (!getAccessIndex(Call->getArgOperand(ArgIndex), AccessIndex))
1243758
       return nullptr;
1243758
-
1243758
-    AccessIndices.push_back(AccessIndex);
1243758
-    if (TypeName.size()) {
1243758
-      TypeNameIndex = AccessIndices.size() - 1;
1243758
-      LastTypeName = TypeName;
1243758
-      TypeMeta = MDN;
1243758
+    AccessKey += ":" + std::to_string(AccessIndex);
1243758
+
1243758
+    MDNode *MDN = Call->getMetadata(LLVMContext::MD_preserve_access_index);
1243758
+    // At this stage, it cannot be pointer type.
1243758
+    auto *CTy = cast<DICompositeType>(stripQualifiers(cast<DIType>(MDN)));
1243758
+    uint32_t Tag = CTy->getTag();
1243758
+    if (Tag == dwarf::DW_TAG_structure_type) {
1243758
+      auto *MemberTy = cast<DIDerivedType>(CTy->getElements()[AccessIndex]);
1243758
+      AccessOffset += MemberTy->getOffsetInBits() >> 3;
1243758
+    } else if (Tag == dwarf::DW_TAG_array_type) {
1243758
+      auto *EltTy = stripQualifiers(CTy->getBaseType());
1243758
+      AccessOffset += AccessIndex * calcArraySize(CTy, 1) *
1243758
+                      EltTy->getSizeInBits() >> 3;
1243758
     }
1243758
-
1243758
-    Kind = AIChain[Call].second;
1243758
-    Call = AIChain[Call].first;
1243758
   }
1243758
 
1243758
-  // The intial type name is required.
1243758
-  // FIXME: if the initial type access is an array index, e.g.,
1243758
-  // &a[3].b.c, only one dimentional array is supported.
1243758
-  if (!LastTypeName.size() || AccessIndices.size() > TypeNameIndex + 2)
1243758
-    return nullptr;
1243758
-
1243758
-  // Construct the type string AccessKey.
1243758
-  for (unsigned I = 0; I < AccessIndices.size(); ++I)
1243758
-    AccessKey = std::to_string(AccessIndices[I]) + ":" + AccessKey;
1243758
-
1243758
-  if (TypeNameIndex == AccessIndices.size() - 1)
1243758
-    AccessKey = "0:" + AccessKey;
1243758
-
1243758
   // Access key is the type name + access string, uniquely identifying
1243758
   // one kernel memory access.
1243758
-  AccessKey = LastTypeName + ":" + AccessKey;
1243758
+  AccessKey = TypeName + ":" + std::to_string(AccessOffset) + "$" + AccessKey;
1243758
 
1243758
   return Base;
1243758
 }
1243758
@@ -409,7 +611,7 @@ Value *BPFAbstractMemberAccess::computeBaseAndAccessKey(CallInst *Call,
1243758
 bool BPFAbstractMemberAccess::transformGEPChain(Module &M, CallInst *Call,
1243758
                                                 uint32_t Kind) {
1243758
   std::string AccessKey;
1243758
-  MDNode *TypeMeta = nullptr;
1243758
+  MDNode *TypeMeta;
1243758
   Value *Base =
1243758
       computeBaseAndAccessKey(Call, AccessKey, Kind, TypeMeta);
1243758
   if (!Base)
1243758
@@ -419,7 +621,7 @@ bool BPFAbstractMemberAccess::transformGEPChain(Module &M, CallInst *Call,
1243758
   // For any original GEP Call and Base %2 like
1243758
   //   %4 = bitcast %struct.net_device** %dev1 to i64*
1243758
   // it is transformed to:
1243758
-  //   %6 = load __BTF_0:sk_buff:0:0:2:0:
1243758
+  //   %6 = load sk_buff:50:$0:0:0:2:0
1243758
   //   %7 = bitcast %struct.sk_buff* %2 to i8*
1243758
   //   %8 = getelementptr i8, i8* %7, %6
1243758
   //   %9 = bitcast i8* %8 to i64*
1243758
@@ -432,9 +634,7 @@ bool BPFAbstractMemberAccess::transformGEPChain(Module &M, CallInst *Call,
1243758
     GV = new GlobalVariable(M, Type::getInt64Ty(BB->getContext()), false,
1243758
                             GlobalVariable::ExternalLinkage, NULL, AccessKey);
1243758
     GV->addAttribute(BPFCoreSharedInfo::AmaAttr);
1243758
-    // Set the metadata (debuginfo types) for the global.
1243758
-    if (TypeMeta)
1243758
-      GV->setMetadata(LLVMContext::MD_preserve_access_index, TypeMeta);
1243758
+    GV->setMetadata(LLVMContext::MD_preserve_access_index, TypeMeta);
1243758
     GEPGlobals[AccessKey] = GV;
1243758
   } else {
1243758
     GV = GEPGlobals[AccessKey];
1243758
diff --git a/llvm/lib/Target/BPF/BTFDebug.cpp b/llvm/lib/Target/BPF/BTFDebug.cpp
1243758
index 5c542e7..9b966eb 100644
1243758
--- a/llvm/lib/Target/BPF/BTFDebug.cpp
1243758
+++ b/llvm/lib/Target/BPF/BTFDebug.cpp
1243758
@@ -30,18 +30,6 @@ static const char *BTFKindStr[] = {
1243758
 #include "BTF.def"
1243758
 };
1243758
 
1243758
-static const DIType * stripQualifiers(const DIType *Ty) {
1243758
-  while (const auto *DTy = dyn_cast<DIDerivedType>(Ty)) {
1243758
-    unsigned Tag = DTy->getTag();
1243758
-    if (Tag != dwarf::DW_TAG_typedef && Tag != dwarf::DW_TAG_const_type &&
1243758
-        Tag != dwarf::DW_TAG_volatile_type && Tag != dwarf::DW_TAG_restrict_type)
1243758
-      break;
1243758
-    Ty = DTy->getBaseType();
1243758
-  }
1243758
-
1243758
-  return Ty;
1243758
-}
1243758
-
1243758
 /// Emit a BTF common type.
1243758
 void BTFTypeBase::emitType(MCStreamer &OS) {
1243758
   OS.AddComment(std::string(BTFKindStr[Kind]) + "(id = " + std::to_string(Id) +
1243758
@@ -196,9 +184,7 @@ void BTFTypeEnum::emitType(MCStreamer &OS) {
1243758
   }
1243758
 }
1243758
 
1243758
-BTFTypeArray::BTFTypeArray(const DIType *Ty, uint32_t ElemTypeId,
1243758
-                           uint32_t ElemSize, uint32_t NumElems)
1243758
-    : ElemTyNoQual(Ty), ElemSize(ElemSize) {
1243758
+BTFTypeArray::BTFTypeArray(uint32_t ElemTypeId, uint32_t NumElems) {
1243758
   Kind = BTF::BTF_KIND_ARRAY;
1243758
   BTFType.NameOff = 0;
1243758
   BTFType.Info = Kind << 24;
1243758
@@ -219,9 +205,6 @@ void BTFTypeArray::completeType(BTFDebug &BDebug) {
1243758
   // created during initial type traversal. Just
1243758
   // retrieve that type id.
1243758
   ArrayInfo.IndexType = BDebug.getArrayIndexTypeId();
1243758
-
1243758
-  ElemTypeNoQual = ElemTyNoQual ? BDebug.getTypeId(ElemTyNoQual)
1243758
-                                : ArrayInfo.ElemType;
1243758
 }
1243758
 
1243758
 void BTFTypeArray::emitType(MCStreamer &OS) {
1243758
@@ -231,12 +214,6 @@ void BTFTypeArray::emitType(MCStreamer &OS) {
1243758
   OS.EmitIntValue(ArrayInfo.Nelems, 4);
1243758
 }
1243758
 
1243758
-void BTFTypeArray::getLocInfo(uint32_t Loc, uint32_t &LocOffset,
1243758
-                              uint32_t &ElementTypeId) {
1243758
-  ElementTypeId = ElemTypeNoQual;
1243758
-  LocOffset = Loc * ElemSize;
1243758
-}
1243758
-
1243758
 /// Represent either a struct or a union.
1243758
 BTFTypeStruct::BTFTypeStruct(const DICompositeType *STy, bool IsStruct,
1243758
                              bool HasBitField, uint32_t Vlen)
1243758
@@ -268,7 +245,6 @@ void BTFTypeStruct::completeType(BTFDebug &BDebug) {
1243758
     }
1243758
     const auto *BaseTy = DDTy->getBaseType();
1243758
     BTFMember.Type = BDebug.getTypeId(BaseTy);
1243758
-    MemberTypeNoQual.push_back(BDebug.getTypeId(stripQualifiers(BaseTy)));
1243758
     Members.push_back(BTFMember);
1243758
   }
1243758
 }
1243758
@@ -285,15 +261,6 @@ void BTFTypeStruct::emitType(MCStreamer &OS) {
1243758
 
1243758
 std::string BTFTypeStruct::getName() { return STy->getName(); }
1243758
 
1243758
-void BTFTypeStruct::getMemberInfo(uint32_t Loc, uint32_t &MemberOffset,
1243758
-                                  uint32_t &MemberType) {
1243758
-  MemberType = MemberTypeNoQual[Loc];
1243758
-  MemberOffset =
1243758
-      HasBitField ? Members[Loc].Offset & 0xffffff : Members[Loc].Offset;
1243758
-}
1243758
-
1243758
-uint32_t BTFTypeStruct::getStructSize() { return STy->getSizeInBits() >> 3; }
1243758
-
1243758
 /// The Func kind represents both subprogram and pointee of function
1243758
 /// pointers. If the FuncName is empty, it represents a pointee of function
1243758
 /// pointer. Otherwise, it represents a subprogram. The func arg names
1243758
@@ -511,12 +478,10 @@ void BTFDebug::visitArrayType(const DICompositeType *CTy, uint32_t &TypeId) {
1243758
   visitTypeEntry(ElemType, ElemTypeId, false, false);
1243758
 
1243758
   // Strip qualifiers from element type to get accurate element size.
1243758
-  ElemType = stripQualifiers(ElemType);
1243758
   ElemSize = ElemType->getSizeInBits() >> 3;
1243758
 
1243758
   if (!CTy->getSizeInBits()) {
1243758
-    auto TypeEntry = llvm::make_unique<BTFTypeArray>(ElemType, ElemTypeId, 0, 0);
1243758
-    ArrayTypes.push_back(TypeEntry.get());
1243758
+    auto TypeEntry = llvm::make_unique<BTFTypeArray>(ElemTypeId, 0);
1243758
     ElemTypeId = addType(std::move(TypeEntry), CTy);
1243758
   } else {
1243758
     // Visit array dimensions.
1243758
@@ -527,12 +492,9 @@ void BTFDebug::visitArrayType(const DICompositeType *CTy, uint32_t &TypeId) {
1243758
           const DISubrange *SR = cast<DISubrange>(Element);
1243758
           auto *CI = SR->getCount().dyn_cast<ConstantInt *>();
1243758
           int64_t Count = CI->getSExtValue();
1243758
-          const DIType *ArrayElemTy = (I == 0) ? ElemType : nullptr;
1243758
 
1243758
           auto TypeEntry =
1243758
-              llvm::make_unique<BTFTypeArray>(ArrayElemTy, ElemTypeId,
1243758
-                                              ElemSize, Count);
1243758
-          ArrayTypes.push_back(TypeEntry.get());
1243758
+              llvm::make_unique<BTFTypeArray>(ElemTypeId, Count);
1243758
           if (I == 0)
1243758
             ElemTypeId = addType(std::move(TypeEntry), CTy);
1243758
           else
1243758
@@ -1002,74 +964,22 @@ unsigned BTFDebug::populateStructType(const DIType *Ty) {
1243758
   return Id;
1243758
 }
1243758
 
1243758
-// Find struct/array debuginfo types given a type id.
1243758
-void BTFDebug::setTypeFromId(uint32_t TypeId, BTFTypeStruct **PrevStructType,
1243758
-                             BTFTypeArray **PrevArrayType) {
1243758
-  for (const auto &StructType : StructTypes) {
1243758
-    if (StructType->getId() == TypeId) {
1243758
-      *PrevStructType = StructType;
1243758
-      return;
1243758
-    }
1243758
-  }
1243758
-  for (const auto &ArrayType : ArrayTypes) {
1243758
-    if (ArrayType->getId() == TypeId) {
1243758
-      *PrevArrayType = ArrayType;
1243758
-      return;
1243758
-    }
1243758
-  }
1243758
-}
1243758
-
1243758
 /// Generate a struct member offset relocation.
1243758
 void BTFDebug::generateOffsetReloc(const MachineInstr *MI,
1243758
                                    const MCSymbol *ORSym, DIType *RootTy,
1243758
                                    StringRef AccessPattern) {
1243758
-  BTFTypeStruct *PrevStructType = nullptr;
1243758
-  BTFTypeArray *PrevArrayType = nullptr;
1243758
   unsigned RootId = populateStructType(RootTy);
1243758
-  setTypeFromId(RootId, &PrevStructType, &PrevArrayType);
1243758
-  unsigned RootTySize = PrevStructType->getStructSize();
1243758
-  StringRef IndexPattern = AccessPattern.substr(AccessPattern.find_first_of(':') + 1);
1243758
+  size_t FirstDollar = AccessPattern.find_first_of('$');
1243758
+  size_t FirstColon = AccessPattern.find_first_of(':');
1243758
+  StringRef IndexPattern = AccessPattern.substr(FirstDollar + 1);
1243758
+  StringRef OffsetStr = AccessPattern.substr(FirstColon + 1,
1243758
+      FirstDollar - FirstColon);
1243758
 
1243758
   BTFOffsetReloc OffsetReloc;
1243758
   OffsetReloc.Label = ORSym;
1243758
-  OffsetReloc.OffsetNameOff = addString(IndexPattern.drop_back());
1243758
+  OffsetReloc.OffsetNameOff = addString(IndexPattern);
1243758
   OffsetReloc.TypeID = RootId;
1243758
-
1243758
-  uint32_t Start = 0, End = 0, Offset = 0;
1243758
-  bool FirstAccess = true;
1243758
-  for (auto C : IndexPattern) {
1243758
-    if (C != ':') {
1243758
-      End++;
1243758
-    } else {
1243758
-      std::string SubStr = IndexPattern.substr(Start, End - Start);
1243758
-      int Loc = std::stoi(SubStr);
1243758
-
1243758
-      if (FirstAccess) {
1243758
-        Offset = Loc * RootTySize;
1243758
-        FirstAccess = false;
1243758
-      } else if (PrevStructType) {
1243758
-        uint32_t MemberOffset, MemberTypeId;
1243758
-        PrevStructType->getMemberInfo(Loc, MemberOffset, MemberTypeId);
1243758
-
1243758
-        Offset += MemberOffset >> 3;
1243758
-        PrevStructType = nullptr;
1243758
-        setTypeFromId(MemberTypeId, &PrevStructType, &PrevArrayType);
1243758
-      } else if (PrevArrayType) {
1243758
-        uint32_t LocOffset, ElementTypeId;
1243758
-        PrevArrayType->getLocInfo(Loc, LocOffset, ElementTypeId);
1243758
-
1243758
-        Offset += LocOffset;
1243758
-        PrevArrayType = nullptr;
1243758
-        setTypeFromId(ElementTypeId, &PrevStructType, &PrevArrayType);
1243758
-      } else {
1243758
-        llvm_unreachable("Internal Error: BTF offset relocation type traversal error");
1243758
-      }
1243758
-
1243758
-      Start = End + 1;
1243758
-      End = Start;
1243758
-    }
1243758
-  }
1243758
-  AccessOffsets[AccessPattern.str()] = Offset;
1243758
+  AccessOffsets[AccessPattern.str()] = std::stoi(OffsetStr);
1243758
   OffsetRelocTable[SecNameOff].push_back(OffsetReloc);
1243758
 }
1243758
 
1243758
diff --git a/llvm/lib/Target/BPF/BTFDebug.h b/llvm/lib/Target/BPF/BTFDebug.h
1243758
index e210d18..a79527d 100644
1243758
--- a/llvm/lib/Target/BPF/BTFDebug.h
1243758
+++ b/llvm/lib/Target/BPF/BTFDebug.h
1243758
@@ -104,18 +104,13 @@ public:
1243758
 
1243758
 /// Handle array type.
1243758
 class BTFTypeArray : public BTFTypeBase {
1243758
-  const DIType *ElemTyNoQual;
1243758
-  uint32_t ElemSize;
1243758
   struct BTF::BTFArray ArrayInfo;
1243758
-  uint32_t ElemTypeNoQual;
1243758
 
1243758
 public:
1243758
-  BTFTypeArray(const DIType *Ty, uint32_t ElemTypeId,
1243758
-               uint32_t ElemSize, uint32_t NumElems);
1243758
+  BTFTypeArray(uint32_t ElemTypeId, uint32_t NumElems);
1243758
   uint32_t getSize() { return BTFTypeBase::getSize() + BTF::BTFArraySize; }
1243758
   void completeType(BTFDebug &BDebug);
1243758
   void emitType(MCStreamer &OS;;
1243758
-  void getLocInfo(uint32_t Loc, uint32_t &LocOffset, uint32_t &ElementTypeId);
1243758
 };
1243758
 
1243758
 /// Handle struct/union type.
1243758
@@ -123,7 +118,6 @@ class BTFTypeStruct : public BTFTypeBase {
1243758
   const DICompositeType *STy;
1243758
   bool HasBitField;
1243758
   std::vector<struct BTF::BTFMember> Members;
1243758
-  std::vector<uint32_t> MemberTypeNoQual;
1243758
 
1243758
 public:
1243758
   BTFTypeStruct(const DICompositeType *STy, bool IsStruct, bool HasBitField,
1243758
@@ -134,8 +128,6 @@ public:
1243758
   void completeType(BTFDebug &BDebug);
1243758
   void emitType(MCStreamer &OS;;
1243758
   std::string getName();
1243758
-  void getMemberInfo(uint32_t Loc, uint32_t &Offset, uint32_t &MemberType);
1243758
-  uint32_t getStructSize();
1243758
 };
1243758
 
1243758
 /// Handle function pointer.
1243758
@@ -262,7 +254,6 @@ class BTFDebug : public DebugHandlerBase {
1243758
   StringMap<std::vector<std::string>> FileContent;
1243758
   std::map<std::string, std::unique_ptr<BTFKindDataSec>> DataSecEntries;
1243758
   std::vector<BTFTypeStruct *> StructTypes;
1243758
-  std::vector<BTFTypeArray *> ArrayTypes;
1243758
   std::map<std::string, int64_t> AccessOffsets;
1243758
   std::map<StringRef, std::pair<bool, std::vector<BTFTypeDerived *>>>
1243758
       FixupDerivedTypes;
1243758
@@ -312,10 +303,6 @@ class BTFDebug : public DebugHandlerBase {
1243758
   void generateOffsetReloc(const MachineInstr *MI, const MCSymbol *ORSym,
1243758
                            DIType *RootTy, StringRef AccessPattern);
1243758
 
1243758
-  /// Set the to-be-traversed Struct/Array Type based on TypeId.
1243758
-  void setTypeFromId(uint32_t TypeId, BTFTypeStruct **PrevStructType,
1243758
-                     BTFTypeArray **PrevArrayType);
1243758
-
1243758
   /// Populating unprocessed struct type.
1243758
   unsigned populateStructType(const DIType *Ty);
1243758
 
1243758
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-array-1.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-array-1.ll
1243758
new file mode 100644
1243758
index 0000000..9e291cd
1243758
--- /dev/null
1243758
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-array-1.ll
1243758
@@ -0,0 +1,124 @@
1243758
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
1243758
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
1243758
+; Source code:
1243758
+;   struct v1 {int a; int b;};
1243758
+;   typedef struct v1 __v1;
1243758
+;   typedef __v1 arr[4];
1243758
+;   struct v3 { char c; int d[100]; };
1243758
+;   #define _(x) (__builtin_preserve_access_index(x))
1243758
+;   #define cast_to_arr(x) ((arr *)(x))
1243758
+;   int get_value(const int *arg);
1243758
+;   int test(struct v3 *arg) {
1243758
+;     return get_value(_(&cast_to_arr(&arg->d[0])[0][2].b));
1243758
+;   }
1243758
+; Compilation flag:
1243758
+;   clang -target bpf -O2 -g -S -emit-llvm test.c
1243758
+
1243758
+%struct.v3 = type { i8, [100 x i32] }
1243758
+%struct.v1 = type { i32, i32 }
1243758
+
1243758
+; Function Attrs: nounwind
1243758
+define dso_local i32 @test(%struct.v3* %arg) local_unnamed_addr #0 !dbg !22 {
1243758
+entry:
1243758
+  call void @llvm.dbg.value(metadata %struct.v3* %arg, metadata !32, metadata !DIExpression()), !dbg !33
1243758
+  %0 = tail call [100 x i32]* @llvm.preserve.struct.access.index.p0a100i32.p0s_struct.v3s(%struct.v3* %arg, i32 1, i32 1), !dbg !34, !llvm.preserve.access.index !26
1243758
+  %1 = tail call i32* @llvm.preserve.array.access.index.p0i32.p0a100i32([100 x i32]* %0, i32 1, i32 0), !dbg !34, !llvm.preserve.access.index !15
1243758
+  %2 = bitcast i32* %1 to [4 x %struct.v1]*, !dbg !34
1243758
+  %3 = tail call [4 x %struct.v1]* @llvm.preserve.array.access.index.p0a4s_struct.v1s.p0a4s_struct.v1s([4 x %struct.v1]* %2, i32 0, i32 0), !dbg !34, !llvm.preserve.access.index !4
1243758
+  %4 = tail call %struct.v1* @llvm.preserve.array.access.index.p0s_struct.v1s.p0a4s_struct.v1s([4 x %struct.v1]* %3, i32 1, i32 2), !dbg !34, !llvm.preserve.access.index !5
1243758
+  %5 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v1s(%struct.v1* %4, i32 1, i32 1), !dbg !34, !llvm.preserve.access.index !8
1243758
+  %call = tail call i32 @get_value(i32* %5) #4, !dbg !35
1243758
+  ret i32 %call, !dbg !36
1243758
+}
1243758
+
1243758
+; CHECK:              r2 = 4
1243758
+; CHECK:              r1 += r2
1243758
+; CHECK:              r2 = 20
1243758
+; CHECK:              r1 += r2
1243758
+; CHECK:              call get_value
1243758
+
1243758
+; CHECK:              .long   1                       # BTF_KIND_STRUCT(id = [[TID1:[0-9]+]])
1243758
+; CHECK:              .long   100                     # BTF_KIND_STRUCT(id = [[TID2:[0-9]+]])
1243758
+
1243758
+; CHECK:              .ascii  "v3"                    # string offset=1
1243758
+; CHECK:              .ascii  ".text"                 # string offset=46
1243758
+; CHECK:              .ascii  "0:1:0"                 # string offset=52
1243758
+; CHECK:              .ascii  "2:1"                   # string offset=107
1243758
+
1243758
+; CHECK:              .long   12                      # OffsetReloc
1243758
+; CHECK-NEXT:         .long   46                      # Offset reloc section string offset=46
1243758
+; CHECK-NEXT:         .long   2
1243758
+; CHECK-NEXT:         .long   .Ltmp{{[0-9]+}}
1243758
+; CHECK-NEXT:         .long   [[TID1]]
1243758
+; CHECK-NEXT:         .long   52
1243758
+; CHECK-NEXT:         .long   .Ltmp{{[0-9]+}}
1243758
+; CHECK-NEXT:         .long   [[TID2]]
1243758
+; CHECK-NEXT:         .long   107
1243758
+
1243758
+declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
1243758
+
1243758
+; Function Attrs: nounwind readnone
1243758
+declare [100 x i32]* @llvm.preserve.struct.access.index.p0a100i32.p0s_struct.v3s(%struct.v3*, i32, i32) #2
1243758
+
1243758
+; Function Attrs: nounwind readnone
1243758
+declare i32* @llvm.preserve.array.access.index.p0i32.p0a100i32([100 x i32]*, i32, i32) #2
1243758
+
1243758
+; Function Attrs: nounwind readnone
1243758
+declare [4 x %struct.v1]* @llvm.preserve.array.access.index.p0a4s_struct.v1s.p0a4s_struct.v1s([4 x %struct.v1]*, i32, i32) #2
1243758
+
1243758
+; Function Attrs: nounwind readnone
1243758
+declare %struct.v1* @llvm.preserve.array.access.index.p0s_struct.v1s.p0a4s_struct.v1s([4 x %struct.v1]*, i32, i32) #2
1243758
+
1243758
+; Function Attrs: nounwind readnone
1243758
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v1s(%struct.v1*, i32, i32) #2
1243758
+
1243758
+; Function Attrs: nounwind readnone speculatable willreturn
1243758
+declare void @llvm.dbg.value(metadata, metadata, metadata) #3
1243758
+
1243758
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
1243758
+attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
1243758
+attributes #2 = { nounwind readnone }
1243758
+attributes #3 = { nounwind readnone speculatable willreturn }
1243758
+attributes #4 = { nounwind }
1243758
+
1243758
+!llvm.dbg.cu = !{!0}
1243758
+!llvm.module.flags = !{!18, !19, !20}
1243758
+!llvm.ident = !{!21}
1243758
+
1243758
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None)
1243758
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
1243758
+!2 = !{}
1243758
+!3 = !{!4, !15, !5}
1243758
+!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64)
1243758
+!5 = !DIDerivedType(tag: DW_TAG_typedef, name: "arr", file: !1, line: 3, baseType: !6)
1243758
+!6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 256, elements: !13)
1243758
+!7 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v1", file: !1, line: 2, baseType: !8)
1243758
+!8 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v1", file: !1, line: 1, size: 64, elements: !9)
1243758
+!9 = !{!10, !12}
1243758
+!10 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !8, file: !1, line: 1, baseType: !11, size: 32)
1243758
+!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
1243758
+!12 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !8, file: !1, line: 1, baseType: !11, size: 32, offset: 32)
1243758
+!13 = !{!14}
1243758
+!14 = !DISubrange(count: 4)
1243758
+!15 = !DICompositeType(tag: DW_TAG_array_type, baseType: !11, size: 3200, elements: !16)
1243758
+!16 = !{!17}
1243758
+!17 = !DISubrange(count: 100)
1243758
+!18 = !{i32 2, !"Dwarf Version", i32 4}
1243758
+!19 = !{i32 2, !"Debug Info Version", i32 3}
1243758
+!20 = !{i32 1, !"wchar_size", i32 4}
1243758
+!21 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
1243758
+!22 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 8, type: !23, scopeLine: 8, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !31)
1243758
+!23 = !DISubroutineType(types: !24)
1243758
+!24 = !{!11, !25}
1243758
+!25 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !26, size: 64)
1243758
+!26 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !1, line: 4, size: 3232, elements: !27)
1243758
+!27 = !{!28, !30}
1243758
+!28 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !26, file: !1, line: 4, baseType: !29, size: 8)
1243758
+!29 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
1243758
+!30 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !26, file: !1, line: 4, baseType: !15, size: 3200, offset: 32)
1243758
+!31 = !{!32}
1243758
+!32 = !DILocalVariable(name: "arg", arg: 1, scope: !22, file: !1, line: 8, type: !25)
1243758
+!33 = !DILocation(line: 0, scope: !22)
1243758
+!34 = !DILocation(line: 9, column: 20, scope: !22)
1243758
+!35 = !DILocation(line: 9, column: 10, scope: !22)
1243758
+!36 = !DILocation(line: 9, column: 3, scope: !22)
1243758
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-array-2.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-array-2.ll
1243758
new file mode 100644
1243758
index 0000000..7903179
1243758
--- /dev/null
1243758
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-array-2.ll
1243758
@@ -0,0 +1,131 @@
1243758
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
1243758
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
1243758
+; Source code:
1243758
+;   struct v1 {int a; int b;};
1243758
+;   typedef struct v1 __v1;
1243758
+;   typedef __v1 arr[4][4];
1243758
+;   struct v3 { char c; int d[100]; };
1243758
+;   #define _(x) (__builtin_preserve_access_index(x))
1243758
+;   #define cast_to_arr(x) ((arr *)(x))
1243758
+;   int get_value(const int *arg);
1243758
+;   int test(struct v3 *arg) {
1243758
+;     return get_value(_(&cast_to_arr(&arg->d[0])[0][2][3].b));
1243758
+;   }
1243758
+; Compilation flag:
1243758
+;   clang -target bpf -O2 -g -S -emit-llvm test.c
1243758
+
1243758
+%struct.v3 = type { i8, [100 x i32] }
1243758
+%struct.v1 = type { i32, i32 }
1243758
+
1243758
+; Function Attrs: nounwind
1243758
+define dso_local i32 @test(%struct.v3* %arg) local_unnamed_addr #0 !dbg !24 {
1243758
+entry:
1243758
+  call void @llvm.dbg.value(metadata %struct.v3* %arg, metadata !34, metadata !DIExpression()), !dbg !35
1243758
+  %0 = tail call [100 x i32]* @llvm.preserve.struct.access.index.p0a100i32.p0s_struct.v3s(%struct.v3* %arg, i32 1, i32 1), !dbg !36, !llvm.preserve.access.index !28
1243758
+  %1 = tail call i32* @llvm.preserve.array.access.index.p0i32.p0a100i32([100 x i32]* %0, i32 1, i32 0), !dbg !36, !llvm.preserve.access.index !15
1243758
+  %2 = bitcast i32* %1 to [4 x [4 x %struct.v1]]*, !dbg !36
1243758
+  %3 = tail call [4 x [4 x %struct.v1]]* @llvm.preserve.array.access.index.p0a4a4s_struct.v1s.p0a4a4s_struct.v1s([4 x [4 x %struct.v1]]* %2, i32 0, i32 0), !dbg !36, !llvm.preserve.access.index !4
1243758
+  %4 = tail call [4 x %struct.v1]* @llvm.preserve.array.access.index.p0a4s_struct.v1s.p0a4a4s_struct.v1s([4 x [4 x %struct.v1]]* %3, i32 1, i32 2), !dbg !36, !llvm.preserve.access.index !5
1243758
+  %5 = tail call %struct.v1* @llvm.preserve.array.access.index.p0s_struct.v1s.p0a4s_struct.v1s([4 x %struct.v1]* %4, i32 1, i32 3), !dbg !36, !llvm.preserve.access.index !18
1243758
+  %6 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v1s(%struct.v1* %5, i32 1, i32 1), !dbg !36, !llvm.preserve.access.index !8
1243758
+  %call = tail call i32 @get_value(i32* %6) #4, !dbg !37
1243758
+  ret i32 %call, !dbg !38
1243758
+}
1243758
+
1243758
+; CHECK:              r2 = 4
1243758
+; CHECK:              r1 += r2
1243758
+; CHECK:              r2 = 92
1243758
+; CHECK:              r1 += r2
1243758
+; CHECK:              call get_value
1243758
+
1243758
+; CHECK:              .long   1                       # BTF_KIND_STRUCT(id = [[TID1:[0-9]+]])
1243758
+; CHECK:              .long   100                     # BTF_KIND_STRUCT(id = [[TID2:[0-9]+]])
1243758
+
1243758
+; CHECK:              .ascii  "v3"                    # string offset=1
1243758
+; CHECK:              .ascii  ".text"                 # string offset=46
1243758
+; CHECK:              .ascii  "0:1:0"                 # string offset=52
1243758
+; CHECK:              .ascii  "v1"                    # string offset=100
1243758
+; CHECK:              .ascii  "11:1"                  # string offset=107
1243758
+
1243758
+; CHECK:              .long   12                      # OffsetReloc
1243758
+; CHECK-NEXT:         .long   46                      # Offset reloc section string offset=46
1243758
+; CHECK-NEXT:         .long   2
1243758
+; CHECK-NEXT:         .long   .Ltmp{{[0-9]+}}
1243758
+; CHECK-NEXT:         .long   [[TID1]]
1243758
+; CHECK-NEXT:         .long   52
1243758
+; CHECK-NEXT:         .long   .Ltmp{{[0-9]+}}
1243758
+; CHECK-NEXT:         .long   [[TID2]]
1243758
+; CHECK-NEXT:         .long   107
1243758
+
1243758
+declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
1243758
+
1243758
+; Function Attrs: nounwind readnone
1243758
+declare [100 x i32]* @llvm.preserve.struct.access.index.p0a100i32.p0s_struct.v3s(%struct.v3*, i32, i32) #2
1243758
+
1243758
+; Function Attrs: nounwind readnone
1243758
+declare i32* @llvm.preserve.array.access.index.p0i32.p0a100i32([100 x i32]*, i32, i32) #2
1243758
+
1243758
+; Function Attrs: nounwind readnone
1243758
+declare [4 x [4 x %struct.v1]]* @llvm.preserve.array.access.index.p0a4a4s_struct.v1s.p0a4a4s_struct.v1s([4 x [4 x %struct.v1]]*, i32, i32) #2
1243758
+
1243758
+; Function Attrs: nounwind readnone
1243758
+declare [4 x %struct.v1]* @llvm.preserve.array.access.index.p0a4s_struct.v1s.p0a4a4s_struct.v1s([4 x [4 x %struct.v1]]*, i32, i32) #2
1243758
+
1243758
+; Function Attrs: nounwind readnone
1243758
+declare %struct.v1* @llvm.preserve.array.access.index.p0s_struct.v1s.p0a4s_struct.v1s([4 x %struct.v1]*, i32, i32) #2
1243758
+
1243758
+; Function Attrs: nounwind readnone
1243758
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v1s(%struct.v1*, i32, i32) #2
1243758
+
1243758
+; Function Attrs: nounwind readnone speculatable willreturn
1243758
+declare void @llvm.dbg.value(metadata, metadata, metadata) #3
1243758
+
1243758
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
1243758
+attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
1243758
+attributes #2 = { nounwind readnone }
1243758
+attributes #3 = { nounwind readnone speculatable willreturn }
1243758
+attributes #4 = { nounwind }
1243758
+
1243758
+!llvm.dbg.cu = !{!0}
1243758
+!llvm.module.flags = !{!20, !21, !22}
1243758
+!llvm.ident = !{!23}
1243758
+
1243758
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None)
1243758
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
1243758
+!2 = !{}
1243758
+!3 = !{!4, !15, !5, !18}
1243758
+!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64)
1243758
+!5 = !DIDerivedType(tag: DW_TAG_typedef, name: "arr", file: !1, line: 3, baseType: !6)
1243758
+!6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 1024, elements: !13)
1243758
+!7 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v1", file: !1, line: 2, baseType: !8)
1243758
+!8 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v1", file: !1, line: 1, size: 64, elements: !9)
1243758
+!9 = !{!10, !12}
1243758
+!10 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !8, file: !1, line: 1, baseType: !11, size: 32)
1243758
+!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
1243758
+!12 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !8, file: !1, line: 1, baseType: !11, size: 32, offset: 32)
1243758
+!13 = !{!14, !14}
1243758
+!14 = !DISubrange(count: 4)
1243758
+!15 = !DICompositeType(tag: DW_TAG_array_type, baseType: !11, size: 3200, elements: !16)
1243758
+!16 = !{!17}
1243758
+!17 = !DISubrange(count: 100)
1243758
+!18 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 256, elements: !19)
1243758
+!19 = !{!14}
1243758
+!20 = !{i32 2, !"Dwarf Version", i32 4}
1243758
+!21 = !{i32 2, !"Debug Info Version", i32 3}
1243758
+!22 = !{i32 1, !"wchar_size", i32 4}
1243758
+!23 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
1243758
+!24 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 8, type: !25, scopeLine: 8, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !33)
1243758
+!25 = !DISubroutineType(types: !26)
1243758
+!26 = !{!11, !27}
1243758
+!27 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !28, size: 64)
1243758
+!28 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !1, line: 4, size: 3232, elements: !29)
1243758
+!29 = !{!30, !32}
1243758
+!30 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !28, file: !1, line: 4, baseType: !31, size: 8)
1243758
+!31 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
1243758
+!32 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !28, file: !1, line: 4, baseType: !15, size: 3200, offset: 32)
1243758
+!33 = !{!34}
1243758
+!34 = !DILocalVariable(name: "arg", arg: 1, scope: !24, file: !1, line: 8, type: !27)
1243758
+!35 = !DILocation(line: 0, scope: !24)
1243758
+!36 = !DILocation(line: 9, column: 20, scope: !24)
1243758
+!37 = !DILocation(line: 9, column: 10, scope: !24)
1243758
+!38 = !DILocation(line: 9, column: 3, scope: !24)
1243758
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-1.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-1.ll
1243758
new file mode 100644
1243758
index 0000000..a97c6a0
1243758
--- /dev/null
1243758
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-1.ll
1243758
@@ -0,0 +1,112 @@
1243758
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
1243758
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
1243758
+; Source code:
1243758
+;   struct v1 { int a; int b; };
1243758
+;   struct v2 { int c; int d; };
1243758
+;   struct v3 { char c; struct v2 d; };
1243758
+;   #define _(x) (__builtin_preserve_access_index(x))
1243758
+;   #define cast_to_v1(x) ((struct v1 *)(x))
1243758
+;   int get_value(const int *arg);
1243758
+;   int test(struct v3 *arg) {
1243758
+;     return get_value(_(&cast_to_v1(&arg->d)->b));
1243758
+;   }
1243758
+; Compilation flag:
1243758
+;   clang -target bpf -O2 -g -S -emit-llvm test.c
1243758
+
1243758
+%struct.v3 = type { i8, %struct.v2 }
1243758
+%struct.v2 = type { i32, i32 }
1243758
+%struct.v1 = type { i32, i32 }
1243758
+
1243758
+; Function Attrs: nounwind
1243758
+define dso_local i32 @test(%struct.v3* %arg) local_unnamed_addr #0 !dbg !14 {
1243758
+entry:
1243758
+  call void @llvm.dbg.value(metadata %struct.v3* %arg, metadata !28, metadata !DIExpression()), !dbg !29
1243758
+  %0 = tail call %struct.v2* @llvm.preserve.struct.access.index.p0s_struct.v2s.p0s_struct.v3s(%struct.v3* %arg, i32 1, i32 1), !dbg !30, !llvm.preserve.access.index !18
1243758
+  %1 = bitcast %struct.v2* %0 to %struct.v1*, !dbg !30
1243758
+  %2 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v1s(%struct.v1* %1, i32 1, i32 1), !dbg !30, !llvm.preserve.access.index !5
1243758
+  %call = tail call i32 @get_value(i32* %2) #4, !dbg !31
1243758
+  ret i32 %call, !dbg !32
1243758
+}
1243758
+
1243758
+; CHECK:              r2 = 4
1243758
+; CHECK:              r1 += r2
1243758
+; CHECK:              r2 = 4
1243758
+; CHECK:              r1 += r2
1243758
+; CHECK:              call get_value
1243758
+
1243758
+; CHECK:             .long   1                       # BTF_KIND_STRUCT(id = [[V3_TID:[0-9]+]])
1243758
+; CHECK:             .long   81                      # BTF_KIND_STRUCT(id = [[V1_TID:[0-9]+]])
1243758
+
1243758
+; CHECK:             .ascii  "v3"                    # string offset=1
1243758
+; CHECK-NEXT:        .byte   0
1243758
+; CHECK:             .ascii  ".text"                 # string offset=[[SEC_STR:[0-9]+]]
1243758
+; CHECK-NEXT:        .byte   0
1243758
+; CHECK:             .ascii  "0:1"                   # string offset=[[ACCESS_STR:[0-9]+]]
1243758
+; CHECK-NEXT:        .byte   0
1243758
+; CHECK:             .ascii  "v1"                    # string offset=81
1243758
+; CHECK-NEXT:        .byte   0
1243758
+
1243758
+; CHECK:             .long   12                      # OffsetReloc
1243758
+; CHECK-NEXT:        .long   [[SEC_STR]]             # Offset reloc section string offset=[[SEC_STR]]
1243758
+; CHECK-NEXT:        .long   2
1243758
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
1243758
+; CHECK-NEXT:        .long   [[V3_TID]]
1243758
+; CHECK-NEXT:        .long   [[ACCESS_STR]]
1243758
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
1243758
+; CHECK-NEXT:        .long   [[V1_TID]]
1243758
+; CHECK-NEXT:        .long   [[ACCESS_STR]]
1243758
+
1243758
+declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
1243758
+
1243758
+; Function Attrs: nounwind readnone
1243758
+declare %struct.v2* @llvm.preserve.struct.access.index.p0s_struct.v2s.p0s_struct.v3s(%struct.v3*, i32, i32) #2
1243758
+
1243758
+; Function Attrs: nounwind readnone
1243758
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v1s(%struct.v1*, i32, i32) #2
1243758
+
1243758
+; Function Attrs: nounwind readnone speculatable willreturn
1243758
+declare void @llvm.dbg.value(metadata, metadata, metadata) #3
1243758
+
1243758
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
1243758
+attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
1243758
+attributes #2 = { nounwind readnone }
1243758
+attributes #3 = { nounwind readnone speculatable willreturn }
1243758
+attributes #4 = { nounwind }
1243758
+
1243758
+!llvm.dbg.cu = !{!0}
1243758
+!llvm.module.flags = !{!10, !11, !12}
1243758
+!llvm.ident = !{!13}
1243758
+
1243758
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None)
1243758
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
1243758
+!2 = !{}
1243758
+!3 = !{!4}
1243758
+!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64)
1243758
+!5 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v1", file: !1, line: 1, size: 64, elements: !6)
1243758
+!6 = !{!7, !9}
1243758
+!7 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !5, file: !1, line: 1, baseType: !8, size: 32)
1243758
+!8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
1243758
+!9 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !5, file: !1, line: 1, baseType: !8, size: 32, offset: 32)
1243758
+!10 = !{i32 2, !"Dwarf Version", i32 4}
1243758
+!11 = !{i32 2, !"Debug Info Version", i32 3}
1243758
+!12 = !{i32 1, !"wchar_size", i32 4}
1243758
+!13 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
1243758
+!14 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 7, type: !15, scopeLine: 7, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !27)
1243758
+!15 = !DISubroutineType(types: !16)
1243758
+!16 = !{!8, !17}
1243758
+!17 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !18, size: 64)
1243758
+!18 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !1, line: 3, size: 96, elements: !19)
1243758
+!19 = !{!20, !22}
1243758
+!20 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !18, file: !1, line: 3, baseType: !21, size: 8)
1243758
+!21 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
1243758
+!22 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !18, file: !1, line: 3, baseType: !23, size: 64, offset: 32)
1243758
+!23 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v2", file: !1, line: 2, size: 64, elements: !24)
1243758
+!24 = !{!25, !26}
1243758
+!25 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !23, file: !1, line: 2, baseType: !8, size: 32)
1243758
+!26 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !23, file: !1, line: 2, baseType: !8, size: 32, offset: 32)
1243758
+!27 = !{!28}
1243758
+!28 = !DILocalVariable(name: "arg", arg: 1, scope: !14, file: !1, line: 7, type: !17)
1243758
+!29 = !DILocation(line: 0, scope: !14)
1243758
+!30 = !DILocation(line: 8, column: 20, scope: !14)
1243758
+!31 = !DILocation(line: 8, column: 10, scope: !14)
1243758
+!32 = !DILocation(line: 8, column: 3, scope: !14)
1243758
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-2.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-2.ll
1243758
new file mode 100644
1243758
index 0000000..f65b3f3
1243758
--- /dev/null
1243758
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-2.ll
1243758
@@ -0,0 +1,117 @@
1243758
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
1243758
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
1243758
+; Source code:
1243758
+;   struct v1 { int a; int b; };
1243758
+;   typedef struct v1 __v1;
1243758
+;   struct v2 { int c; int d; };
1243758
+;   typedef struct v2 __v2;
1243758
+;   struct v3 { char c; volatile const __v2 d; };
1243758
+;   typedef struct v3 __v3;
1243758
+;   #define _(x) (__builtin_preserve_access_index(x))
1243758
+;   #define cast_to_v1(x) ((__v1 *)(x))
1243758
+;   int get_value(const int *arg);
1243758
+;   int test(__v3 *arg) {
1243758
+;     return get_value(_(&cast_to_v1(&arg->d)->b));
1243758
+;   }
1243758
+; Compilation flag:
1243758
+;   clang -target bpf -O2 -g -S -emit-llvm test.c
1243758
+
1243758
+%struct.v3 = type { i8, %struct.v2 }
1243758
+%struct.v2 = type { i32, i32 }
1243758
+%struct.v1 = type { i32, i32 }
1243758
+
1243758
+; Function Attrs: nounwind
1243758
+define dso_local i32 @test(%struct.v3* %arg) local_unnamed_addr #0 !dbg !15 {
1243758
+entry:
1243758
+  call void @llvm.dbg.value(metadata %struct.v3* %arg, metadata !33, metadata !DIExpression()), !dbg !34
1243758
+  %0 = tail call %struct.v2* @llvm.preserve.struct.access.index.p0s_struct.v2s.p0s_struct.v3s(%struct.v3* %arg, i32 1, i32 1), !dbg !35, !llvm.preserve.access.index !20
1243758
+  %1 = bitcast %struct.v2* %0 to %struct.v1*, !dbg !35
1243758
+  %2 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v1s(%struct.v1* %1, i32 1, i32 1), !dbg !35, !llvm.preserve.access.index !6
1243758
+  %call = tail call i32 @get_value(i32* %2) #4, !dbg !36
1243758
+  ret i32 %call, !dbg !37
1243758
+}
1243758
+
1243758
+; CHECK:             r2 = 4
1243758
+; CHECK:             r1 += r2
1243758
+; CHECK:             r2 = 4
1243758
+; CHECK:             r1 += r2
1243758
+; CHECK:             call get_value
1243758
+
1243758
+; CHECK:             .long   6                       # BTF_KIND_STRUCT(id = [[TID1:[0-9]+]])
1243758
+; CHECK:             .long   91                      # BTF_KIND_STRUCT(id = [[TID2:[0-9]+]])
1243758
+
1243758
+; CHECK:             .ascii  "v3"                    # string offset=6
1243758
+; CHECK:             .ascii  ".text"                 # string offset=39
1243758
+; CHECK:             .ascii  "0:1"                   # string offset=45
1243758
+; CHECK:             .ascii  "v1"                    # string offset=91
1243758
+
1243758
+
1243758
+; CHECK:             .long   12                      # OffsetReloc
1243758
+; CHECK-NEXT:        .long   39                      # Offset reloc section string offset=39
1243758
+; CHECK-NEXT:        .long   2
1243758
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
1243758
+; CHECK-NEXT:        .long   [[TID1]]
1243758
+; CHECK-NEXT:        .long   45
1243758
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
1243758
+; CHECK-NEXT:        .long   [[TID2]]
1243758
+; CHECK-NEXT:        .long   45
1243758
+
1243758
+declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
1243758
+
1243758
+; Function Attrs: nounwind readnone
1243758
+declare %struct.v2* @llvm.preserve.struct.access.index.p0s_struct.v2s.p0s_struct.v3s(%struct.v3*, i32, i32) #2
1243758
+
1243758
+; Function Attrs: nounwind readnone
1243758
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v1s(%struct.v1*, i32, i32) #2
1243758
+
1243758
+; Function Attrs: nounwind readnone speculatable willreturn
1243758
+declare void @llvm.dbg.value(metadata, metadata, metadata) #3
1243758
+
1243758
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
1243758
+attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
1243758
+attributes #2 = { nounwind readnone }
1243758
+attributes #3 = { nounwind readnone speculatable willreturn }
1243758
+attributes #4 = { nounwind }
1243758
+
1243758
+!llvm.dbg.cu = !{!0}
1243758
+!llvm.module.flags = !{!11, !12, !13}
1243758
+!llvm.ident = !{!14}
1243758
+
1243758
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None)
1243758
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
1243758
+!2 = !{}
1243758
+!3 = !{!4}
1243758
+!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64)
1243758
+!5 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v1", file: !1, line: 2, baseType: !6)
1243758
+!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v1", file: !1, line: 1, size: 64, elements: !7)
1243758
+!7 = !{!8, !10}
1243758
+!8 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !6, file: !1, line: 1, baseType: !9, size: 32)
1243758
+!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
1243758
+!10 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !6, file: !1, line: 1, baseType: !9, size: 32, offset: 32)
1243758
+!11 = !{i32 2, !"Dwarf Version", i32 4}
1243758
+!12 = !{i32 2, !"Debug Info Version", i32 3}
1243758
+!13 = !{i32 1, !"wchar_size", i32 4}
1243758
+!14 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
1243758
+!15 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 10, type: !16, scopeLine: 10, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !32)
1243758
+!16 = !DISubroutineType(types: !17)
1243758
+!17 = !{!9, !18}
1243758
+!18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !19, size: 64)
1243758
+!19 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v3", file: !1, line: 6, baseType: !20)
1243758
+!20 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !1, line: 5, size: 96, elements: !21)
1243758
+!21 = !{!22, !24}
1243758
+!22 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !20, file: !1, line: 5, baseType: !23, size: 8)
1243758
+!23 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
1243758
+!24 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !20, file: !1, line: 5, baseType: !25, size: 64, offset: 32)
1243758
+!25 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !26)
1243758
+!26 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !27)
1243758
+!27 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v2", file: !1, line: 4, baseType: !28)
1243758
+!28 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v2", file: !1, line: 3, size: 64, elements: !29)
1243758
+!29 = !{!30, !31}
1243758
+!30 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !28, file: !1, line: 3, baseType: !9, size: 32)
1243758
+!31 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !28, file: !1, line: 3, baseType: !9, size: 32, offset: 32)
1243758
+!32 = !{!33}
1243758
+!33 = !DILocalVariable(name: "arg", arg: 1, scope: !15, file: !1, line: 10, type: !18)
1243758
+!34 = !DILocation(line: 0, scope: !15)
1243758
+!35 = !DILocation(line: 11, column: 20, scope: !15)
1243758
+!36 = !DILocation(line: 11, column: 10, scope: !15)
1243758
+!37 = !DILocation(line: 11, column: 3, scope: !15)
1243758
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-3.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-3.ll
1243758
new file mode 100644
1243758
index 0000000..ed78b84
1243758
--- /dev/null
1243758
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-3.ll
1243758
@@ -0,0 +1,116 @@
1243758
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
1243758
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
1243758
+; Source code:
1243758
+;   struct v1 { int a; int b; };
1243758
+;   typedef struct v1 __v1;
1243758
+;   typedef int __int;
1243758
+;   struct v3 { char c; __int d[40]; };
1243758
+;   typedef struct v3 __v3;
1243758
+;   #define _(x) (__builtin_preserve_access_index(x))
1243758
+;   #define cast_to_v1(x) ((__v1 *)(x))
1243758
+;   int get_value(const int *arg);
1243758
+;   int test(__v3 *arg) {
1243758
+;     return get_value(_(&cast_to_v1(&arg->d[4])->b));
1243758
+;   }
1243758
+; Compilation flag:
1243758
+;   clang -target bpf -O2 -g -S -emit-llvm test.c
1243758
+
1243758
+%struct.v3 = type { i8, [40 x i32] }
1243758
+%struct.v1 = type { i32, i32 }
1243758
+
1243758
+; Function Attrs: nounwind
1243758
+define dso_local i32 @test(%struct.v3* %arg) local_unnamed_addr #0 !dbg !19 {
1243758
+entry:
1243758
+  call void @llvm.dbg.value(metadata %struct.v3* %arg, metadata !30, metadata !DIExpression()), !dbg !31
1243758
+  %0 = tail call [40 x i32]* @llvm.preserve.struct.access.index.p0a40i32.p0s_struct.v3s(%struct.v3* %arg, i32 1, i32 1), !dbg !32, !llvm.preserve.access.index !24
1243758
+  %1 = tail call i32* @llvm.preserve.array.access.index.p0i32.p0a40i32([40 x i32]* %0, i32 1, i32 4), !dbg !32, !llvm.preserve.access.index !11
1243758
+  %2 = bitcast i32* %1 to %struct.v1*, !dbg !32
1243758
+  %3 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v1s(%struct.v1* %2, i32 1, i32 1), !dbg !32, !llvm.preserve.access.index !6
1243758
+  %call = tail call i32 @get_value(i32* %3) #4, !dbg !33
1243758
+  ret i32 %call, !dbg !34
1243758
+}
1243758
+
1243758
+; CHECK:             r2 = 20
1243758
+; CHECK:             r1 += r2
1243758
+; CHECK:             r2 = 4
1243758
+; CHECK:             r1 += r2
1243758
+; CHECK:             call get_value
1243758
+
1243758
+; CHECK:             .long   6                       # BTF_KIND_STRUCT(id = [[TID1:[0-9]+]])
1243758
+; CHECK:             .long   111                     # BTF_KIND_STRUCT(id = [[TID2:[0-9]+]])
1243758
+
1243758
+; CHECK:             .ascii  "v3"                    # string offset=6
1243758
+; CHECK:             .ascii  ".text"                 # string offset=57
1243758
+; CHECK:             .ascii  "0:1:4"                 # string offset=63
1243758
+; CHECK:             .ascii  "v1"                    # string offset=111
1243758
+; CHECK:             .ascii  "0:1"                   # string offset=118
1243758
+
1243758
+; CHECK:             .long   12                      # OffsetReloc
1243758
+; CHECK-NEXT:        .long   57                      # Offset reloc section string offset=57
1243758
+; CHECK-NEXT:        .long   2
1243758
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
1243758
+; CHECK-NEXT:        .long   [[TID1]]
1243758
+; CHECK-NEXT:        .long   63
1243758
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
1243758
+; CHECK-NEXT:        .long   [[TID2]]
1243758
+; CHECK-NEXT:        .long   118
1243758
+
1243758
+declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
1243758
+
1243758
+; Function Attrs: nounwind readnone
1243758
+declare [40 x i32]* @llvm.preserve.struct.access.index.p0a40i32.p0s_struct.v3s(%struct.v3*, i32, i32) #2
1243758
+
1243758
+; Function Attrs: nounwind readnone
1243758
+declare i32* @llvm.preserve.array.access.index.p0i32.p0a40i32([40 x i32]*, i32, i32) #2
1243758
+
1243758
+; Function Attrs: nounwind readnone
1243758
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v1s(%struct.v1*, i32, i32) #2
1243758
+
1243758
+; Function Attrs: nounwind readnone speculatable willreturn
1243758
+declare void @llvm.dbg.value(metadata, metadata, metadata) #3
1243758
+
1243758
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
1243758
+attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
1243758
+attributes #2 = { nounwind readnone }
1243758
+attributes #3 = { nounwind readnone speculatable willreturn }
1243758
+attributes #4 = { nounwind }
1243758
+
1243758
+!llvm.dbg.cu = !{!0}
1243758
+!llvm.module.flags = !{!15, !16, !17}
1243758
+!llvm.ident = !{!18}
1243758
+
1243758
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None)
1243758
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
1243758
+!2 = !{}
1243758
+!3 = !{!4, !11}
1243758
+!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64)
1243758
+!5 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v1", file: !1, line: 2, baseType: !6)
1243758
+!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v1", file: !1, line: 1, size: 64, elements: !7)
1243758
+!7 = !{!8, !10}
1243758
+!8 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !6, file: !1, line: 1, baseType: !9, size: 32)
1243758
+!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
1243758
+!10 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !6, file: !1, line: 1, baseType: !9, size: 32, offset: 32)
1243758
+!11 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 1280, elements: !13)
1243758
+!12 = !DIDerivedType(tag: DW_TAG_typedef, name: "__int", file: !1, line: 3, baseType: !9)
1243758
+!13 = !{!14}
1243758
+!14 = !DISubrange(count: 40)
1243758
+!15 = !{i32 2, !"Dwarf Version", i32 4}
1243758
+!16 = !{i32 2, !"Debug Info Version", i32 3}
1243758
+!17 = !{i32 1, !"wchar_size", i32 4}
1243758
+!18 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
1243758
+!19 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 9, type: !20, scopeLine: 9, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !29)
1243758
+!20 = !DISubroutineType(types: !21)
1243758
+!21 = !{!9, !22}
1243758
+!22 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !23, size: 64)
1243758
+!23 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v3", file: !1, line: 5, baseType: !24)
1243758
+!24 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !1, line: 4, size: 1312, elements: !25)
1243758
+!25 = !{!26, !28}
1243758
+!26 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !24, file: !1, line: 4, baseType: !27, size: 8)
1243758
+!27 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
1243758
+!28 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !24, file: !1, line: 4, baseType: !11, size: 1280, offset: 32)
1243758
+!29 = !{!30}
1243758
+!30 = !DILocalVariable(name: "arg", arg: 1, scope: !19, file: !1, line: 9, type: !22)
1243758
+!31 = !DILocation(line: 0, scope: !19)
1243758
+!32 = !DILocation(line: 10, column: 20, scope: !19)
1243758
+!33 = !DILocation(line: 10, column: 10, scope: !19)
1243758
+!34 = !DILocation(line: 10, column: 3, scope: !19)
1243758
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-union-1.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-union-1.ll
1243758
new file mode 100644
1243758
index 0000000..1e8f99c
1243758
--- /dev/null
1243758
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-union-1.ll
1243758
@@ -0,0 +1,117 @@
1243758
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
1243758
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
1243758
+; Source code:
1243758
+;   union v1 { int a; int b; };
1243758
+;   typedef union v1 __v1;
1243758
+;   union v2 { int c; int d; };
1243758
+;   typedef union v2 __v2;
1243758
+;   union v3 { char c; volatile const __v2 d; };
1243758
+;   typedef union v3 __v3;
1243758
+;   #define _(x) (__builtin_preserve_access_index(x))
1243758
+;   #define cast_to_v1(x) ((__v1 *)(x))
1243758
+;   int get_value(const int *arg);
1243758
+;   int test(__v3 *arg) {
1243758
+;     return get_value(_(&cast_to_v1(&arg->d)->b));
1243758
+;   }
1243758
+; Compilation flag:
1243758
+;   clang -target bpf -O2 -g -S -emit-llvm test.c
1243758
+
1243758
+%union.v3 = type { %union.v2 }
1243758
+%union.v2 = type { i32 }
1243758
+%union.v1 = type { i32 }
1243758
+
1243758
+; Function Attrs: nounwind
1243758
+define dso_local i32 @test(%union.v3* %arg) local_unnamed_addr #0 !dbg !15 {
1243758
+entry:
1243758
+  call void @llvm.dbg.value(metadata %union.v3* %arg, metadata !33, metadata !DIExpression()), !dbg !34
1243758
+  %0 = tail call %union.v3* @llvm.preserve.union.access.index.p0s_union.v3s.p0s_union.v3s(%union.v3* %arg, i32 1), !dbg !35, !llvm.preserve.access.index !20
1243758
+  %1 = bitcast %union.v3* %0 to %union.v1*, !dbg !35
1243758
+  %2 = tail call %union.v1* @llvm.preserve.union.access.index.p0s_union.v1s.p0s_union.v1s(%union.v1* %1, i32 1), !dbg !35, !llvm.preserve.access.index !6
1243758
+  %b = getelementptr inbounds %union.v1, %union.v1* %2, i64 0, i32 0, !dbg !35
1243758
+  %call = tail call i32 @get_value(i32* %b) #4, !dbg !36
1243758
+  ret i32 %call, !dbg !37
1243758
+}
1243758
+
1243758
+; CHECK:             r2 = 0
1243758
+; CHECK:             r1 += r2
1243758
+; CHECK:             r2 = 0
1243758
+; CHECK:             r1 += r2
1243758
+; CHECK:             call get_value
1243758
+
1243758
+; CHECK:             .long   6                       # BTF_KIND_UNION(id = [[TID1:[0-9]+]])
1243758
+; CHECK:             .long   91                      # BTF_KIND_UNION(id = [[TID2:[0-9]+]])
1243758
+
1243758
+; CHECK:             .ascii  "v3"                    # string offset=6
1243758
+; CHECK:             .ascii  ".text"                 # string offset=39
1243758
+; CHECK:             .ascii  "0:1"                   # string offset=45
1243758
+; CHECK:             .ascii  "v1"                    # string offset=91
1243758
+
1243758
+; CHECK:             .long   12                      # OffsetReloc
1243758
+; CHECK-NEXT:        .long   39                      # Offset reloc section string offset=39
1243758
+; CHECK-NEXT:        .long   2
1243758
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
1243758
+; CHECK-NEXT:        .long   [[TID1]]
1243758
+; CHECK-NEXT:        .long   45
1243758
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
1243758
+; CHECK-NEXT:        .long   [[TID2]]
1243758
+; CHECK-NEXT:        .long   45
1243758
+
1243758
+declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
1243758
+
1243758
+; Function Attrs: nounwind readnone
1243758
+declare %union.v3* @llvm.preserve.union.access.index.p0s_union.v3s.p0s_union.v3s(%union.v3*, i32) #2
1243758
+
1243758
+; Function Attrs: nounwind readnone
1243758
+declare %union.v1* @llvm.preserve.union.access.index.p0s_union.v1s.p0s_union.v1s(%union.v1*, i32) #2
1243758
+
1243758
+; Function Attrs: nounwind readnone speculatable willreturn
1243758
+declare void @llvm.dbg.value(metadata, metadata, metadata) #3
1243758
+
1243758
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
1243758
+attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
1243758
+attributes #2 = { nounwind readnone }
1243758
+attributes #3 = { nounwind readnone speculatable willreturn }
1243758
+attributes #4 = { nounwind }
1243758
+
1243758
+!llvm.dbg.cu = !{!0}
1243758
+!llvm.module.flags = !{!11, !12, !13}
1243758
+!llvm.ident = !{!14}
1243758
+
1243758
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None)
1243758
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
1243758
+!2 = !{}
1243758
+!3 = !{!4}
1243758
+!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64)
1243758
+!5 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v1", file: !1, line: 2, baseType: !6)
1243758
+!6 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "v1", file: !1, line: 1, size: 32, elements: !7)
1243758
+!7 = !{!8, !10}
1243758
+!8 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !6, file: !1, line: 1, baseType: !9, size: 32)
1243758
+!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
1243758
+!10 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !6, file: !1, line: 1, baseType: !9, size: 32)
1243758
+!11 = !{i32 2, !"Dwarf Version", i32 4}
1243758
+!12 = !{i32 2, !"Debug Info Version", i32 3}
1243758
+!13 = !{i32 1, !"wchar_size", i32 4}
1243758
+!14 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
1243758
+!15 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 10, type: !16, scopeLine: 10, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !32)
1243758
+!16 = !DISubroutineType(types: !17)
1243758
+!17 = !{!9, !18}
1243758
+!18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !19, size: 64)
1243758
+!19 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v3", file: !1, line: 6, baseType: !20)
1243758
+!20 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "v3", file: !1, line: 5, size: 32, elements: !21)
1243758
+!21 = !{!22, !24}
1243758
+!22 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !20, file: !1, line: 5, baseType: !23, size: 8)
1243758
+!23 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
1243758
+!24 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !20, file: !1, line: 5, baseType: !25, size: 32)
1243758
+!25 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !26)
1243758
+!26 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !27)
1243758
+!27 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v2", file: !1, line: 4, baseType: !28)
1243758
+!28 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "v2", file: !1, line: 3, size: 32, elements: !29)
1243758
+!29 = !{!30, !31}
1243758
+!30 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !28, file: !1, line: 3, baseType: !9, size: 32)
1243758
+!31 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !28, file: !1, line: 3, baseType: !9, size: 32)
1243758
+!32 = !{!33}
1243758
+!33 = !DILocalVariable(name: "arg", arg: 1, scope: !15, file: !1, line: 10, type: !18)
1243758
+!34 = !DILocation(line: 0, scope: !15)
1243758
+!35 = !DILocation(line: 11, column: 20, scope: !15)
1243758
+!36 = !DILocation(line: 11, column: 10, scope: !15)
1243758
+!37 = !DILocation(line: 11, column: 3, scope: !15)
1243758
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-union-2.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-union-2.ll
1243758
new file mode 100644
1243758
index 0000000..320b0a9
1243758
--- /dev/null
1243758
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-union-2.ll
1243758
@@ -0,0 +1,118 @@
1243758
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
1243758
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
1243758
+; Source code:
1243758
+;   union v1 { int a; int b; };
1243758
+;   typedef union v1 __v1;
1243758
+;   typedef int __int;
1243758
+;   union v3 { char c; __int d[40]; };
1243758
+;   typedef union v3 __v3;
1243758
+;   #define _(x) (__builtin_preserve_access_index(x))
1243758
+;   #define cast_to_v1(x) ((__v1 *)(x))
1243758
+;   int get_value(const int *arg);
1243758
+;   int test(__v3 *arg) {
1243758
+;     return get_value(_(&cast_to_v1(&arg->d[4])->b));
1243758
+;   }
1243758
+; Compilation flag:
1243758
+;   clang -target bpf -O2 -g -S -emit-llvm test.c
1243758
+
1243758
+%union.v3 = type { [40 x i32] }
1243758
+%union.v1 = type { i32 }
1243758
+
1243758
+; Function Attrs: nounwind
1243758
+define dso_local i32 @test(%union.v3* %arg) local_unnamed_addr #0 !dbg !19 {
1243758
+entry:
1243758
+  call void @llvm.dbg.value(metadata %union.v3* %arg, metadata !30, metadata !DIExpression()), !dbg !31
1243758
+  %0 = tail call %union.v3* @llvm.preserve.union.access.index.p0s_union.v3s.p0s_union.v3s(%union.v3* %arg, i32 1), !dbg !32, !llvm.preserve.access.index !24
1243758
+  %d = getelementptr inbounds %union.v3, %union.v3* %0, i64 0, i32 0, !dbg !32
1243758
+  %1 = tail call i32* @llvm.preserve.array.access.index.p0i32.p0a40i32([40 x i32]* %d, i32 1, i32 4), !dbg !32, !llvm.preserve.access.index !11
1243758
+  %2 = bitcast i32* %1 to %union.v1*, !dbg !32
1243758
+  %3 = tail call %union.v1* @llvm.preserve.union.access.index.p0s_union.v1s.p0s_union.v1s(%union.v1* %2, i32 1), !dbg !32, !llvm.preserve.access.index !6
1243758
+  %b = getelementptr inbounds %union.v1, %union.v1* %3, i64 0, i32 0, !dbg !32
1243758
+  %call = tail call i32 @get_value(i32* %b) #4, !dbg !33
1243758
+  ret i32 %call, !dbg !34
1243758
+}
1243758
+
1243758
+; CHECK:             r2 = 16
1243758
+; CHECK:             r1 += r2
1243758
+; CHECK:             r2 = 0
1243758
+; CHECK:             r1 += r2
1243758
+; CHECK:             call get_value
1243758
+
1243758
+; CHECK:             .long   6                       # BTF_KIND_UNION(id = [[TID1:[0-9]+]])
1243758
+; CHECK:             .long   111                     # BTF_KIND_UNION(id = [[TID2:[0-9]+]])
1243758
+
1243758
+; CHECK:             .ascii  "v3"                    # string offset=6
1243758
+; CHECK:             .ascii  ".text"                 # string offset=57
1243758
+; CHECK:             .ascii  "0:1:4"                 # string offset=63
1243758
+; CHECK:             .ascii  "v1"                    # string offset=111
1243758
+; CHECK:             .ascii  "0:1"                   # string offset=118
1243758
+
1243758
+; CHECK:             .long   12                      # OffsetReloc
1243758
+; CHECK-NEXT:        .long   57                      # Offset reloc section string offset=57
1243758
+; CHECK-NEXT:        .long   2
1243758
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
1243758
+; CHECK-NEXT:        .long   [[TID1]]
1243758
+; CHECK-NEXT:        .long   63
1243758
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
1243758
+; CHECK-NEXT:        .long   [[TID2]]
1243758
+; CHECK-NEXT:        .long   118
1243758
+
1243758
+declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
1243758
+
1243758
+; Function Attrs: nounwind readnone
1243758
+declare %union.v3* @llvm.preserve.union.access.index.p0s_union.v3s.p0s_union.v3s(%union.v3*, i32) #2
1243758
+
1243758
+; Function Attrs: nounwind readnone
1243758
+declare i32* @llvm.preserve.array.access.index.p0i32.p0a40i32([40 x i32]*, i32, i32) #2
1243758
+
1243758
+; Function Attrs: nounwind readnone
1243758
+declare %union.v1* @llvm.preserve.union.access.index.p0s_union.v1s.p0s_union.v1s(%union.v1*, i32) #2
1243758
+
1243758
+; Function Attrs: nounwind readnone speculatable willreturn
1243758
+declare void @llvm.dbg.value(metadata, metadata, metadata) #3
1243758
+
1243758
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
1243758
+attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
1243758
+attributes #2 = { nounwind readnone }
1243758
+attributes #3 = { nounwind readnone speculatable willreturn }
1243758
+attributes #4 = { nounwind }
1243758
+
1243758
+!llvm.dbg.cu = !{!0}
1243758
+!llvm.module.flags = !{!15, !16, !17}
1243758
+!llvm.ident = !{!18}
1243758
+
1243758
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None)
1243758
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
1243758
+!2 = !{}
1243758
+!3 = !{!4, !11}
1243758
+!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64)
1243758
+!5 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v1", file: !1, line: 2, baseType: !6)
1243758
+!6 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "v1", file: !1, line: 1, size: 32, elements: !7)
1243758
+!7 = !{!8, !10}
1243758
+!8 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !6, file: !1, line: 1, baseType: !9, size: 32)
1243758
+!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
1243758
+!10 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !6, file: !1, line: 1, baseType: !9, size: 32)
1243758
+!11 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 1280, elements: !13)
1243758
+!12 = !DIDerivedType(tag: DW_TAG_typedef, name: "__int", file: !1, line: 3, baseType: !9)
1243758
+!13 = !{!14}
1243758
+!14 = !DISubrange(count: 40)
1243758
+!15 = !{i32 2, !"Dwarf Version", i32 4}
1243758
+!16 = !{i32 2, !"Debug Info Version", i32 3}
1243758
+!17 = !{i32 1, !"wchar_size", i32 4}
1243758
+!18 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
1243758
+!19 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 9, type: !20, scopeLine: 9, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !29)
1243758
+!20 = !DISubroutineType(types: !21)
1243758
+!21 = !{!9, !22}
1243758
+!22 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !23, size: 64)
1243758
+!23 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v3", file: !1, line: 5, baseType: !24)
1243758
+!24 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "v3", file: !1, line: 4, size: 1280, elements: !25)
1243758
+!25 = !{!26, !28}
1243758
+!26 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !24, file: !1, line: 4, baseType: !27, size: 8)
1243758
+!27 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
1243758
+!28 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !24, file: !1, line: 4, baseType: !11, size: 1280)
1243758
+!29 = !{!30}
1243758
+!30 = !DILocalVariable(name: "arg", arg: 1, scope: !19, file: !1, line: 9, type: !22)
1243758
+!31 = !DILocation(line: 0, scope: !19)
1243758
+!32 = !DILocation(line: 10, column: 20, scope: !19)
1243758
+!33 = !DILocation(line: 10, column: 10, scope: !19)
1243758
+!34 = !DILocation(line: 10, column: 3, scope: !19)
1243758
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-global-1.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-global-1.ll
1243758
new file mode 100644
1243758
index 0000000..296e2d4
1243758
--- /dev/null
1243758
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-global-1.ll
1243758
@@ -0,0 +1,79 @@
1243758
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
1243758
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
1243758
+; Source code:
1243758
+;   typedef struct v3 { int a; int b; } __v3;
1243758
+;   #define _(x) (__builtin_preserve_access_index(x))
1243758
+;   int get_value(const int *arg);
1243758
+;   __v3 g __attribute__((section("stats")));
1243758
+;   int test() {
1243758
+;     return get_value(_(&g.b));
1243758
+;   }
1243758
+; Compilation flag:
1243758
+;   clang -target bpf -O2 -g -S -emit-llvm test.c
1243758
+
1243758
+%struct.v3 = type { i32, i32 }
1243758
+
1243758
+@g = dso_local global %struct.v3 zeroinitializer, section "stats", align 4, !dbg !0
1243758
+
1243758
+; Function Attrs: nounwind
1243758
+define dso_local i32 @test() local_unnamed_addr #0 !dbg !16 {
1243758
+entry:
1243758
+  %0 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v3s(%struct.v3* nonnull @g, i32 1, i32 1), !dbg !19, !llvm.preserve.access.index !7
1243758
+  %call = tail call i32 @get_value(i32* %0) #3, !dbg !20
1243758
+  ret i32 %call, !dbg !21
1243758
+}
1243758
+
1243758
+; CHECK:              r2 = 4
1243758
+; CHECK:              r1 = g ll
1243758
+; CHECK:              r1 += r2
1243758
+; CHECK:              call get_value
1243758
+
1243758
+; CHECK:              .long   16                      # BTF_KIND_STRUCT(id = [[TID1:[0-9]+]])
1243758
+
1243758
+; CHECK:              .ascii  ".text"                 # string offset=10
1243758
+; CHECK:              .ascii  "v3"                    # string offset=16
1243758
+; CHECK:              .ascii  "0:1"                   # string offset=23
1243758
+
1243758
+; CHECK:              .long   12                      # OffsetReloc
1243758
+; CHECK-NEXT:         .long   10                      # Offset reloc section string offset=10
1243758
+; CHECK-NEXT:         .long   1
1243758
+; CHECK-NEXT:         .long   .Ltmp{{[0-9]+}}
1243758
+; CHECK-NEXT:         .long   [[TID1]]
1243758
+; CHECK-NEXT:         .long   23
1243758
+
1243758
+declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
1243758
+
1243758
+; Function Attrs: nounwind readnone
1243758
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v3s(%struct.v3*, i32, i32) #2
1243758
+
1243758
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
1243758
+attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
1243758
+attributes #2 = { nounwind readnone }
1243758
+attributes #3 = { nounwind }
1243758
+
1243758
+!llvm.dbg.cu = !{!2}
1243758
+!llvm.module.flags = !{!12, !13, !14}
1243758
+!llvm.ident = !{!15}
1243758
+
1243758
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
1243758
+!1 = distinct !DIGlobalVariable(name: "g", scope: !2, file: !3, line: 4, type: !6, isLocal: false, isDefinition: true)
1243758
+!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None)
1243758
+!3 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
1243758
+!4 = !{}
1243758
+!5 = !{!0}
1243758
+!6 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v3", file: !3, line: 1, baseType: !7)
1243758
+!7 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !3, line: 1, size: 64, elements: !8)
1243758
+!8 = !{!9, !11}
1243758
+!9 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !7, file: !3, line: 1, baseType: !10, size: 32)
1243758
+!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
1243758
+!11 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !7, file: !3, line: 1, baseType: !10, size: 32, offset: 32)
1243758
+!12 = !{i32 2, !"Dwarf Version", i32 4}
1243758
+!13 = !{i32 2, !"Debug Info Version", i32 3}
1243758
+!14 = !{i32 1, !"wchar_size", i32 4}
1243758
+!15 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
1243758
+!16 = distinct !DISubprogram(name: "test", scope: !3, file: !3, line: 5, type: !17, scopeLine: 5, isDefinition: true, isOptimized: true, unit: !2, retainedNodes: !4)
1243758
+!17 = !DISubroutineType(types: !18)
1243758
+!18 = !{!10}
1243758
+!19 = !DILocation(line: 6, column: 20, scope: !16)
1243758
+!20 = !DILocation(line: 6, column: 10, scope: !16)
1243758
+!21 = !DILocation(line: 6, column: 3, scope: !16)
1243758
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-global-2.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-global-2.ll
1243758
new file mode 100644
1243758
index 0000000..721081e
1243758
--- /dev/null
1243758
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-global-2.ll
1243758
@@ -0,0 +1,95 @@
1243758
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
1243758
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
1243758
+; Source code:
1243758
+;   typedef struct v3 { int a; int b; } __v3;
1243758
+;   #define _(x) (__builtin_preserve_access_index(x))
1243758
+;   int get_value(const int *arg);
1243758
+;   __v3 g[4][5] __attribute__((section("stats")));
1243758
+;   int test() {
1243758
+;     return get_value(_(&g[1][2].b));
1243758
+;   }
1243758
+; Compilation flag:
1243758
+;   clang -target bpf -O2 -g -S -emit-llvm test.c
1243758
+
1243758
+%struct.v3 = type { i32, i32 }
1243758
+
1243758
+@g = dso_local global [4 x [5 x %struct.v3]] zeroinitializer, section "stats", align 4, !dbg !0
1243758
+
1243758
+; Function Attrs: nounwind
1243758
+define dso_local i32 @test() local_unnamed_addr #0 !dbg !23 {
1243758
+entry:
1243758
+  %0 = tail call [5 x %struct.v3]* @llvm.preserve.array.access.index.p0a5s_struct.v3s.p0a4a5s_struct.v3s([4 x [5 x %struct.v3]]* nonnull @g, i32 1, i32 1), !dbg !26, !llvm.preserve.access.index !6
1243758
+  %1 = tail call %struct.v3* @llvm.preserve.array.access.index.p0s_struct.v3s.p0a5s_struct.v3s([5 x %struct.v3]* %0, i32 1, i32 2), !dbg !26, !llvm.preserve.access.index !16
1243758
+  %2 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v3s(%struct.v3* %1, i32 1, i32 1), !dbg !26, !llvm.preserve.access.index !8
1243758
+  %call = tail call i32 @get_value(i32* %2) #3, !dbg !27
1243758
+  ret i32 %call, !dbg !28
1243758
+}
1243758
+
1243758
+; CHECK:              r2 = 60
1243758
+; CHECK:              r1 = g ll
1243758
+; CHECK:              r1 += r2
1243758
+; CHECK:              call get_value
1243758
+
1243758
+; CHECK:              .long   16                      # BTF_KIND_STRUCT(id = [[TID1:[0-9]+]])
1243758
+
1243758
+; CHECK:              .ascii  ".text"                 # string offset=10
1243758
+; CHECK:              .ascii  "v3"                    # string offset=16
1243758
+; CHECK:              .ascii  "7:1"                   # string offset=23
1243758
+
1243758
+; CHECK:              .long   12                      # OffsetReloc
1243758
+; CHECK-NEXT:         .long   10                      # Offset reloc section string offset=10
1243758
+; CHECK-NEXT:         .long   1
1243758
+; CHECK-NEXT:         .long   .Ltmp{{[0-9]+}}
1243758
+; CHECK-NEXT:         .long   [[TID1]]
1243758
+; CHECK-NEXT:         .long   23
1243758
+
1243758
+
1243758
+declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
1243758
+
1243758
+; Function Attrs: nounwind readnone
1243758
+declare [5 x %struct.v3]* @llvm.preserve.array.access.index.p0a5s_struct.v3s.p0a4a5s_struct.v3s([4 x [5 x %struct.v3]]*, i32, i32) #2
1243758
+
1243758
+; Function Attrs: nounwind readnone
1243758
+declare %struct.v3* @llvm.preserve.array.access.index.p0s_struct.v3s.p0a5s_struct.v3s([5 x %struct.v3]*, i32, i32) #2
1243758
+
1243758
+; Function Attrs: nounwind readnone
1243758
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v3s(%struct.v3*, i32, i32) #2
1243758
+
1243758
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
1243758
+attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
1243758
+attributes #2 = { nounwind readnone }
1243758
+attributes #3 = { nounwind }
1243758
+
1243758
+!llvm.dbg.cu = !{!2}
1243758
+!llvm.module.flags = !{!19, !20, !21}
1243758
+!llvm.ident = !{!22}
1243758
+
1243758
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
1243758
+!1 = distinct !DIGlobalVariable(name: "g", scope: !2, file: !3, line: 4, type: !6, isLocal: false, isDefinition: true)
1243758
+!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, retainedTypes: !5, globals: !18, nameTableKind: None)
1243758
+!3 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
1243758
+!4 = !{}
1243758
+!5 = !{!6, !16}
1243758
+!6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 1280, elements: !13)
1243758
+!7 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v3", file: !3, line: 1, baseType: !8)
1243758
+!8 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !3, line: 1, size: 64, elements: !9)
1243758
+!9 = !{!10, !12}
1243758
+!10 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !8, file: !3, line: 1, baseType: !11, size: 32)
1243758
+!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
1243758
+!12 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !8, file: !3, line: 1, baseType: !11, size: 32, offset: 32)
1243758
+!13 = !{!14, !15}
1243758
+!14 = !DISubrange(count: 4)
1243758
+!15 = !DISubrange(count: 5)
1243758
+!16 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 320, elements: !17)
1243758
+!17 = !{!15}
1243758
+!18 = !{!0}
1243758
+!19 = !{i32 2, !"Dwarf Version", i32 4}
1243758
+!20 = !{i32 2, !"Debug Info Version", i32 3}
1243758
+!21 = !{i32 1, !"wchar_size", i32 4}
1243758
+!22 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
1243758
+!23 = distinct !DISubprogram(name: "test", scope: !3, file: !3, line: 5, type: !24, scopeLine: 5, isDefinition: true, isOptimized: true, unit: !2, retainedNodes: !4)
1243758
+!24 = !DISubroutineType(types: !25)
1243758
+!25 = !{!11}
1243758
+!26 = !DILocation(line: 6, column: 20, scope: !23)
1243758
+!27 = !DILocation(line: 6, column: 10, scope: !23)
1243758
+!28 = !DILocation(line: 6, column: 3, scope: !23)
1243758
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-global-3.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-global-3.ll
1243758
new file mode 100644
1243758
index 0000000..394d04f
1243758
--- /dev/null
1243758
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-global-3.ll
1243758
@@ -0,0 +1,84 @@
1243758
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
1243758
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
1243758
+; Source code:
1243758
+;   typedef struct v3 { int a; int b; } __v3;
1243758
+;   #define _(x) (__builtin_preserve_access_index(x))
1243758
+;   int get_value(const int *arg);
1243758
+;   __v3 *g __attribute__((section("stats")));
1243758
+;   int test() {
1243758
+;     return get_value(_(&g->b));
1243758
+;   }
1243758
+; Compilation flag:
1243758
+;   clang -target bpf -O2 -g -S -emit-llvm test.c
1243758
+
1243758
+%struct.v3 = type { i32, i32 }
1243758
+
1243758
+@g = dso_local local_unnamed_addr global %struct.v3* null, section "stats", align 8, !dbg !0
1243758
+
1243758
+; Function Attrs: nounwind
1243758
+define dso_local i32 @test() local_unnamed_addr #0 !dbg !17 {
1243758
+entry:
1243758
+  %0 = load %struct.v3*, %struct.v3** @g, align 8, !dbg !20, !tbaa !21
1243758
+  %1 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v3s(%struct.v3* %0, i32 1, i32 1), !dbg !20, !llvm.preserve.access.index !8
1243758
+  %call = tail call i32 @get_value(i32* %1) #3, !dbg !25
1243758
+  ret i32 %call, !dbg !26
1243758
+}
1243758
+
1243758
+; CHECK:              r2 = 4
1243758
+; CHECK:              r1 += r2
1243758
+; CHECK:              call get_value
1243758
+
1243758
+; CHECK:              .long   16                      # BTF_KIND_STRUCT(id = [[TID1:[0-9]+]])
1243758
+
1243758
+; CHECK:              .ascii  ".text"                 # string offset=10
1243758
+; CHECK:              .ascii  "v3"                    # string offset=16
1243758
+; CHECK:              .ascii  "0:1"                   # string offset=23
1243758
+
1243758
+; CHECK:              .long   12                      # OffsetReloc
1243758
+; CHECK-NEXT:         .long   10                      # Offset reloc section string offset=10
1243758
+; CHECK-NEXT:         .long   1
1243758
+; CHECK-NEXT:         .long   .Ltmp{{[0-9]+}}
1243758
+; CHECK-NEXT:         .long   [[TID1]]
1243758
+; CHECK-NEXT:         .long   23
1243758
+
1243758
+declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
1243758
+
1243758
+; Function Attrs: nounwind readnone
1243758
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v3s(%struct.v3*, i32, i32) #2
1243758
+
1243758
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
1243758
+attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
1243758
+attributes #2 = { nounwind readnone }
1243758
+attributes #3 = { nounwind }
1243758
+
1243758
+!llvm.dbg.cu = !{!2}
1243758
+!llvm.module.flags = !{!13, !14, !15}
1243758
+!llvm.ident = !{!16}
1243758
+
1243758
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
1243758
+!1 = distinct !DIGlobalVariable(name: "g", scope: !2, file: !3, line: 4, type: !6, isLocal: false, isDefinition: true)
1243758
+!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None)
1243758
+!3 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
1243758
+!4 = !{}
1243758
+!5 = !{!0}
1243758
+!6 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64)
1243758
+!7 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v3", file: !3, line: 1, baseType: !8)
1243758
+!8 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !3, line: 1, size: 64, elements: !9)
1243758
+!9 = !{!10, !12}
1243758
+!10 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !8, file: !3, line: 1, baseType: !11, size: 32)
1243758
+!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
1243758
+!12 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !8, file: !3, line: 1, baseType: !11, size: 32, offset: 32)
1243758
+!13 = !{i32 2, !"Dwarf Version", i32 4}
1243758
+!14 = !{i32 2, !"Debug Info Version", i32 3}
1243758
+!15 = !{i32 1, !"wchar_size", i32 4}
1243758
+!16 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
1243758
+!17 = distinct !DISubprogram(name: "test", scope: !3, file: !3, line: 5, type: !18, scopeLine: 5, isDefinition: true, isOptimized: true, unit: !2, retainedNodes: !4)
1243758
+!18 = !DISubroutineType(types: !19)
1243758
+!19 = !{!11}
1243758
+!20 = !DILocation(line: 6, column: 20, scope: !17)
1243758
+!21 = !{!22, !22, i64 0}
1243758
+!22 = !{!"any pointer", !23, i64 0}
1243758
+!23 = !{!"omnipotent char", !24, i64 0}
1243758
+!24 = !{!"Simple C/C++ TBAA"}
1243758
+!25 = !DILocation(line: 6, column: 10, scope: !17)
1243758
+!26 = !DILocation(line: 6, column: 3, scope: !17)
1243758
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-ignore.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-ignore.ll
1243758
new file mode 100644
1243758
index 0000000..2d14e71
1243758
--- /dev/null
1243758
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-ignore.ll
1243758
@@ -0,0 +1,62 @@
1243758
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
1243758
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
1243758
+; Source code:
1243758
+;   #define _(x) (__builtin_preserve_access_index(x))
1243758
+;   int get_value(const int *arg);
1243758
+;   int test(int *arg) {
1243758
+;     return get_value(_(&arg[4]));
1243758
+;   }
1243758
+; Compilation flag:
1243758
+;   clang -target bpf -O2 -g -S -emit-llvm test.c
1243758
+
1243758
+; Function Attrs: nounwind
1243758
+define dso_local i32 @test(i32* %arg) local_unnamed_addr #0 !dbg !10 {
1243758
+entry:
1243758
+  call void @llvm.dbg.value(metadata i32* %arg, metadata !14, metadata !DIExpression()), !dbg !15
1243758
+  %0 = tail call i32* @llvm.preserve.array.access.index.p0i32.p0i32(i32* %arg, i32 0, i32 4), !dbg !16, !llvm.preserve.access.index !4
1243758
+  %call = tail call i32 @get_value(i32* %0) #4, !dbg !17
1243758
+  ret i32 %call, !dbg !18
1243758
+}
1243758
+
1243758
+; CHECK:             r1 += 16
1243758
+; CHECK:             call get_value
1243758
+; CHECK:             .section        .BTF.ext,"",@progbits
1243758
+; CHECK-NOT:         .long   12                      # OffsetReloc
1243758
+
1243758
+declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
1243758
+
1243758
+; Function Attrs: nounwind readnone
1243758
+declare i32* @llvm.preserve.array.access.index.p0i32.p0i32(i32*, i32, i32) #2
1243758
+
1243758
+; Function Attrs: nounwind readnone speculatable willreturn
1243758
+declare void @llvm.dbg.value(metadata, metadata, metadata) #3
1243758
+
1243758
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
1243758
+attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
1243758
+attributes #2 = { nounwind readnone }
1243758
+attributes #3 = { nounwind readnone speculatable willreturn }
1243758
+attributes #4 = { nounwind }
1243758
+
1243758
+!llvm.dbg.cu = !{!0}
1243758
+!llvm.module.flags = !{!6, !7, !8}
1243758
+!llvm.ident = !{!9}
1243758
+
1243758
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None)
1243758
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
1243758
+!2 = !{}
1243758
+!3 = !{!4}
1243758
+!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64)
1243758
+!5 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
1243758
+!6 = !{i32 2, !"Dwarf Version", i32 4}
1243758
+!7 = !{i32 2, !"Debug Info Version", i32 3}
1243758
+!8 = !{i32 1, !"wchar_size", i32 4}
1243758
+!9 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
1243758
+!10 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 3, type: !11, scopeLine: 3, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !13)
1243758
+!11 = !DISubroutineType(types: !12)
1243758
+!12 = !{!5, !4}
1243758
+!13 = !{!14}
1243758
+!14 = !DILocalVariable(name: "arg", arg: 1, scope: !10, file: !1, line: 3, type: !4)
1243758
+!15 = !DILocation(line: 0, scope: !10)
1243758
+!16 = !DILocation(line: 4, column: 20, scope: !10)
1243758
+!17 = !DILocation(line: 4, column: 10, scope: !10)
1243758
+!18 = !DILocation(line: 4, column: 3, scope: !10)
1243758
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-multi-array-1.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-multi-array-1.ll
1243758
new file mode 100644
1243758
index 0000000..7f79196f
1243758
--- /dev/null
1243758
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-multi-array-1.ll
1243758
@@ -0,0 +1,101 @@
1243758
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
1243758
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
1243758
+; Source code:
1243758
+;   typedef int __int;
1243758
+;   typedef struct v3 { int a; __int b[4][4]; } __v3;
1243758
+;   #define _(x) (__builtin_preserve_access_index(x))
1243758
+;   int get_value(const int *arg);
1243758
+;   int test(__v3 *arg) {
1243758
+;     return get_value(_(&arg[1].b[2][3]));
1243758
+;   }
1243758
+; Compilation flag:
1243758
+;   clang -target bpf -O2 -g -S -emit-llvm test.c
1243758
+
1243758
+%struct.v3 = type { i32, [4 x [4 x i32]] }
1243758
+
1243758
+; Function Attrs: nounwind
1243758
+define dso_local i32 @test(%struct.v3* %arg) local_unnamed_addr #0 !dbg !21 {
1243758
+entry:
1243758
+  call void @llvm.dbg.value(metadata %struct.v3* %arg, metadata !25, metadata !DIExpression()), !dbg !26
1243758
+  %0 = tail call %struct.v3* @llvm.preserve.array.access.index.p0s_struct.v3s.p0s_struct.v3s(%struct.v3* %arg, i32 0, i32 1), !dbg !27, !llvm.preserve.access.index !4
1243758
+  %1 = tail call [4 x [4 x i32]]* @llvm.preserve.struct.access.index.p0a4a4i32.p0s_struct.v3s(%struct.v3* %0, i32 1, i32 1), !dbg !27, !llvm.preserve.access.index !6
1243758
+  %2 = tail call [4 x i32]* @llvm.preserve.array.access.index.p0a4i32.p0a4a4i32([4 x [4 x i32]]* %1, i32 1, i32 2), !dbg !27, !llvm.preserve.access.index !11
1243758
+  %3 = tail call i32* @llvm.preserve.array.access.index.p0i32.p0a4i32([4 x i32]* %2, i32 1, i32 3), !dbg !27, !llvm.preserve.access.index !15
1243758
+  %call = tail call i32 @get_value(i32* %3) #4, !dbg !28
1243758
+  ret i32 %call, !dbg !29
1243758
+}
1243758
+
1243758
+; CHECK:              r2 = 116
1243758
+; CHECK:              r1 += r2
1243758
+; CHECK:              call get_value
1243758
+
1243758
+; CHECK:              .long   6                       # BTF_KIND_STRUCT(id = [[TID1:[0-9]+]])
1243758
+
1243758
+; CHECK:              .ascii  "v3"                    # string offset=6
1243758
+; CHECK:              .ascii  ".text"                 # string offset=52
1243758
+; CHECK:              .ascii  "1:1:2:3"               # string offset=58
1243758
+
1243758
+; CHECK:              .long   12                      # OffsetReloc
1243758
+; CHECK-NEXT:         .long   52                      # Offset reloc section string offset=52
1243758
+; CHECK-NEXT:         .long   1
1243758
+; CHECK-NEXT:         .long   .Ltmp{{[0-9]+}}
1243758
+; CHECK-NEXT:         .long   [[TID1]]
1243758
+; CHECK-NEXT:         .long   58
1243758
+
1243758
+declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
1243758
+
1243758
+; Function Attrs: nounwind readnone
1243758
+declare %struct.v3* @llvm.preserve.array.access.index.p0s_struct.v3s.p0s_struct.v3s(%struct.v3*, i32, i32) #2
1243758
+
1243758
+; Function Attrs: nounwind readnone
1243758
+declare [4 x [4 x i32]]* @llvm.preserve.struct.access.index.p0a4a4i32.p0s_struct.v3s(%struct.v3*, i32, i32) #2
1243758
+
1243758
+; Function Attrs: nounwind readnone
1243758
+declare [4 x i32]* @llvm.preserve.array.access.index.p0a4i32.p0a4a4i32([4 x [4 x i32]]*, i32, i32) #2
1243758
+
1243758
+; Function Attrs: nounwind readnone
1243758
+declare i32* @llvm.preserve.array.access.index.p0i32.p0a4i32([4 x i32]*, i32, i32) #2
1243758
+
1243758
+; Function Attrs: nounwind readnone speculatable willreturn
1243758
+declare void @llvm.dbg.value(metadata, metadata, metadata) #3
1243758
+
1243758
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
1243758
+attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
1243758
+attributes #2 = { nounwind readnone }
1243758
+attributes #3 = { nounwind readnone speculatable willreturn }
1243758
+attributes #4 = { nounwind }
1243758
+
1243758
+!llvm.dbg.cu = !{!0}
1243758
+!llvm.module.flags = !{!17, !18, !19}
1243758
+!llvm.ident = !{!20}
1243758
+
1243758
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None)
1243758
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
1243758
+!2 = !{}
1243758
+!3 = !{!4, !11, !15}
1243758
+!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64)
1243758
+!5 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v3", file: !1, line: 2, baseType: !6)
1243758
+!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !1, line: 2, size: 544, elements: !7)
1243758
+!7 = !{!8, !10}
1243758
+!8 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !6, file: !1, line: 2, baseType: !9, size: 32)
1243758
+!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
1243758
+!10 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !6, file: !1, line: 2, baseType: !11, size: 512, offset: 32)
1243758
+!11 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 512, elements: !13)
1243758
+!12 = !DIDerivedType(tag: DW_TAG_typedef, name: "__int", file: !1, line: 1, baseType: !9)
1243758
+!13 = !{!14, !14}
1243758
+!14 = !DISubrange(count: 4)
1243758
+!15 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 128, elements: !16)
1243758
+!16 = !{!14}
1243758
+!17 = !{i32 2, !"Dwarf Version", i32 4}
1243758
+!18 = !{i32 2, !"Debug Info Version", i32 3}
1243758
+!19 = !{i32 1, !"wchar_size", i32 4}
1243758
+!20 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
1243758
+!21 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 5, type: !22, scopeLine: 5, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !24)
1243758
+!22 = !DISubroutineType(types: !23)
1243758
+!23 = !{!9, !4}
1243758
+!24 = !{!25}
1243758
+!25 = !DILocalVariable(name: "arg", arg: 1, scope: !21, file: !1, line: 5, type: !4)
1243758
+!26 = !DILocation(line: 0, scope: !21)
1243758
+!27 = !DILocation(line: 6, column: 20, scope: !21)
1243758
+!28 = !DILocation(line: 6, column: 10, scope: !21)
1243758
+!29 = !DILocation(line: 6, column: 3, scope: !21)
1243758
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-multi-array-2.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-multi-array-2.ll
1243758
new file mode 100644
1243758
index 0000000..a9c29aa
1243758
--- /dev/null
1243758
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-multi-array-2.ll
1243758
@@ -0,0 +1,107 @@
1243758
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
1243758
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
1243758
+; Source code:
1243758
+;   typedef int __int;
1243758
+;   typedef struct v3 { int a; __int b[4][4][4]; } __v3;
1243758
+;   #define _(x) (__builtin_preserve_access_index(x))
1243758
+;   int get_value(const int *arg);
1243758
+;   int test(__v3 *arg) {
1243758
+;     return get_value(_(&arg[1].b[2][3][2]));
1243758
+;   }
1243758
+; Compilation flag:
1243758
+;   clang -target bpf -O2 -g -S -emit-llvm test.c
1243758
+
1243758
+%struct.v3 = type { i32, [4 x [4 x [4 x i32]]] }
1243758
+
1243758
+; Function Attrs: nounwind
1243758
+define dso_local i32 @test(%struct.v3* %arg) local_unnamed_addr #0 !dbg !23 {
1243758
+entry:
1243758
+  call void @llvm.dbg.value(metadata %struct.v3* %arg, metadata !27, metadata !DIExpression()), !dbg !28
1243758
+  %0 = tail call %struct.v3* @llvm.preserve.array.access.index.p0s_struct.v3s.p0s_struct.v3s(%struct.v3* %arg, i32 0, i32 1), !dbg !29, !llvm.preserve.access.index !4
1243758
+  %1 = tail call [4 x [4 x [4 x i32]]]* @llvm.preserve.struct.access.index.p0a4a4a4i32.p0s_struct.v3s(%struct.v3* %0, i32 1, i32 1), !dbg !29, !llvm.preserve.access.index !6
1243758
+  %2 = tail call [4 x [4 x i32]]* @llvm.preserve.array.access.index.p0a4a4i32.p0a4a4a4i32([4 x [4 x [4 x i32]]]* %1, i32 1, i32 2), !dbg !29, !llvm.preserve.access.index !11
1243758
+  %3 = tail call [4 x i32]* @llvm.preserve.array.access.index.p0a4i32.p0a4a4i32([4 x [4 x i32]]* %2, i32 1, i32 3), !dbg !29, !llvm.preserve.access.index !15
1243758
+  %4 = tail call i32* @llvm.preserve.array.access.index.p0i32.p0a4i32([4 x i32]* %3, i32 1, i32 2), !dbg !29, !llvm.preserve.access.index !17
1243758
+  %call = tail call i32 @get_value(i32* %4) #4, !dbg !30
1243758
+  ret i32 %call, !dbg !31
1243758
+}
1243758
+
1243758
+; CHECK:             r2 = 448
1243758
+; CHECK:             r1 += r2
1243758
+; CHECK:             call get_value
1243758
+
1243758
+; CHECK:             .long   6                       # BTF_KIND_STRUCT(id = [[TID1:[0-9]+]])
1243758
+
1243758
+; CHECK:             .ascii  "v3"                    # string offset=6
1243758
+; CHECK:             .ascii  ".text"                 # string offset=52
1243758
+; CHECK:             .ascii  "1:1:2:3:2"             # string offset=58
1243758
+
1243758
+; CHECK:             .long   12                      # OffsetReloc
1243758
+; CHECK-NEXT:        .long   52                      # Offset reloc section string offset=52
1243758
+; CHECK-NEXT:        .long   1
1243758
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
1243758
+; CHECK-NEXT:        .long   [[TID1]]
1243758
+; CHECK-NEXT:        .long   58
1243758
+
1243758
+declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
1243758
+
1243758
+; Function Attrs: nounwind readnone
1243758
+declare %struct.v3* @llvm.preserve.array.access.index.p0s_struct.v3s.p0s_struct.v3s(%struct.v3*, i32, i32) #2
1243758
+
1243758
+; Function Attrs: nounwind readnone
1243758
+declare [4 x [4 x [4 x i32]]]* @llvm.preserve.struct.access.index.p0a4a4a4i32.p0s_struct.v3s(%struct.v3*, i32, i32) #2
1243758
+
1243758
+; Function Attrs: nounwind readnone
1243758
+declare [4 x [4 x i32]]* @llvm.preserve.array.access.index.p0a4a4i32.p0a4a4a4i32([4 x [4 x [4 x i32]]]*, i32, i32) #2
1243758
+
1243758
+; Function Attrs: nounwind readnone
1243758
+declare [4 x i32]* @llvm.preserve.array.access.index.p0a4i32.p0a4a4i32([4 x [4 x i32]]*, i32, i32) #2
1243758
+
1243758
+; Function Attrs: nounwind readnone
1243758
+declare i32* @llvm.preserve.array.access.index.p0i32.p0a4i32([4 x i32]*, i32, i32) #2
1243758
+
1243758
+; Function Attrs: nounwind readnone speculatable willreturn
1243758
+declare void @llvm.dbg.value(metadata, metadata, metadata) #3
1243758
+
1243758
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
1243758
+attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
1243758
+attributes #2 = { nounwind readnone }
1243758
+attributes #3 = { nounwind readnone speculatable willreturn }
1243758
+attributes #4 = { nounwind }
1243758
+
1243758
+!llvm.dbg.cu = !{!0}
1243758
+!llvm.module.flags = !{!19, !20, !21}
1243758
+!llvm.ident = !{!22}
1243758
+
1243758
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None)
1243758
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
1243758
+!2 = !{}
1243758
+!3 = !{!4, !11, !15, !17}
1243758
+!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64)
1243758
+!5 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v3", file: !1, line: 2, baseType: !6)
1243758
+!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !1, line: 2, size: 2080, elements: !7)
1243758
+!7 = !{!8, !10}
1243758
+!8 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !6, file: !1, line: 2, baseType: !9, size: 32)
1243758
+!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
1243758
+!10 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !6, file: !1, line: 2, baseType: !11, size: 2048, offset: 32)
1243758
+!11 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 2048, elements: !13)
1243758
+!12 = !DIDerivedType(tag: DW_TAG_typedef, name: "__int", file: !1, line: 1, baseType: !9)
1243758
+!13 = !{!14, !14, !14}
1243758
+!14 = !DISubrange(count: 4)
1243758
+!15 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 512, elements: !16)
1243758
+!16 = !{!14, !14}
1243758
+!17 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 128, elements: !18)
1243758
+!18 = !{!14}
1243758
+!19 = !{i32 2, !"Dwarf Version", i32 4}
1243758
+!20 = !{i32 2, !"Debug Info Version", i32 3}
1243758
+!21 = !{i32 1, !"wchar_size", i32 4}
1243758
+!22 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
1243758
+!23 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 5, type: !24, scopeLine: 5, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !26)
1243758
+!24 = !DISubroutineType(types: !25)
1243758
+!25 = !{!9, !4}
1243758
+!26 = !{!27}
1243758
+!27 = !DILocalVariable(name: "arg", arg: 1, scope: !23, file: !1, line: 5, type: !4)
1243758
+!28 = !DILocation(line: 0, scope: !23)
1243758
+!29 = !DILocation(line: 6, column: 20, scope: !23)
1243758
+!30 = !DILocation(line: 6, column: 10, scope: !23)
1243758
+!31 = !DILocation(line: 6, column: 3, scope: !23)
1243758
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-pointer-1.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-pointer-1.ll
1243758
new file mode 100644
1243758
index 0000000..e85b393
1243758
--- /dev/null
1243758
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-pointer-1.ll
1243758
@@ -0,0 +1,83 @@
1243758
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
1243758
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
1243758
+; Source code:
1243758
+;   typedef struct v3 { int a; int b; } __v3;
1243758
+;   #define _(x) (__builtin_preserve_access_index(x))
1243758
+;   int get_value(const int *arg);
1243758
+;   int test(__v3 *arg) {
1243758
+;     return get_value(_(&arg[1]));
1243758
+;   }
1243758
+; Compilation flag:
1243758
+;   clang -target bpf -O2 -g -S -emit-llvm test.c
1243758
+
1243758
+%struct.v3 = type { i32, i32 }
1243758
+
1243758
+; Function Attrs: nounwind
1243758
+define dso_local i32 @test(%struct.v3* %arg) local_unnamed_addr #0 !dbg !15 {
1243758
+entry:
1243758
+  call void @llvm.dbg.value(metadata %struct.v3* %arg, metadata !19, metadata !DIExpression()), !dbg !20
1243758
+  %0 = tail call %struct.v3* @llvm.preserve.array.access.index.p0s_struct.v3s.p0s_struct.v3s(%struct.v3* %arg, i32 0, i32 1), !dbg !21, !llvm.preserve.access.index !4
1243758
+  %1 = getelementptr inbounds %struct.v3, %struct.v3* %0, i64 0, i32 0, !dbg !21
1243758
+  %call = tail call i32 @get_value(i32* %1) #4, !dbg !22
1243758
+  ret i32 %call, !dbg !23
1243758
+}
1243758
+
1243758
+; CHECK:              r2 = 8
1243758
+; CHECK:              r1 += r2
1243758
+; CHECK:              call get_value
1243758
+
1243758
+; CHECK:              .long   6                       # BTF_KIND_STRUCT(id = [[TID1:[0-9]+]])
1243758
+
1243758
+; CHECK:              .ascii  "v3"                    # string offset=6
1243758
+; CHECK:              .ascii  ".text"                 # string offset=26
1243758
+; CHECK:              .byte   49                      # string offset=32
1243758
+
1243758
+; CHECK:              .long   12                      # OffsetReloc
1243758
+; CHECK-NEXT:         .long   26                      # Offset reloc section string offset=26
1243758
+; CHECK-NEXT:         .long   1
1243758
+; CHECK-NEXT:         .long   .Ltmp{{[0-9]+}}
1243758
+; CHECK-NEXT:         .long   [[TID1]]
1243758
+; CHECK-NEXT:         .long   32
1243758
+
1243758
+declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
1243758
+
1243758
+; Function Attrs: nounwind readnone
1243758
+declare %struct.v3* @llvm.preserve.array.access.index.p0s_struct.v3s.p0s_struct.v3s(%struct.v3*, i32, i32) #2
1243758
+
1243758
+; Function Attrs: nounwind readnone speculatable willreturn
1243758
+declare void @llvm.dbg.value(metadata, metadata, metadata) #3
1243758
+
1243758
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
1243758
+attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
1243758
+attributes #2 = { nounwind readnone }
1243758
+attributes #3 = { nounwind readnone speculatable willreturn }
1243758
+attributes #4 = { nounwind }
1243758
+
1243758
+!llvm.dbg.cu = !{!0}
1243758
+!llvm.module.flags = !{!11, !12, !13}
1243758
+!llvm.ident = !{!14}
1243758
+
1243758
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None)
1243758
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
1243758
+!2 = !{}
1243758
+!3 = !{!4}
1243758
+!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64)
1243758
+!5 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v3", file: !1, line: 1, baseType: !6)
1243758
+!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !1, line: 1, size: 64, elements: !7)
1243758
+!7 = !{!8, !10}
1243758
+!8 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !6, file: !1, line: 1, baseType: !9, size: 32)
1243758
+!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
1243758
+!10 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !6, file: !1, line: 1, baseType: !9, size: 32, offset: 32)
1243758
+!11 = !{i32 2, !"Dwarf Version", i32 4}
1243758
+!12 = !{i32 2, !"Debug Info Version", i32 3}
1243758
+!13 = !{i32 1, !"wchar_size", i32 4}
1243758
+!14 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
1243758
+!15 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 4, type: !16, scopeLine: 4, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !18)
1243758
+!16 = !DISubroutineType(types: !17)
1243758
+!17 = !{!9, !4}
1243758
+!18 = !{!19}
1243758
+!19 = !DILocalVariable(name: "arg", arg: 1, scope: !15, file: !1, line: 4, type: !4)
1243758
+!20 = !DILocation(line: 0, scope: !15)
1243758
+!21 = !DILocation(line: 5, column: 20, scope: !15)
1243758
+!22 = !DILocation(line: 5, column: 10, scope: !15)
1243758
+!23 = !DILocation(line: 5, column: 3, scope: !15)
1243758
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-pointer-2.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-pointer-2.ll
1243758
new file mode 100644
1243758
index 0000000..1c54935
1243758
--- /dev/null
1243758
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-pointer-2.ll
1243758
@@ -0,0 +1,85 @@
1243758
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
1243758
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
1243758
+; Source code:
1243758
+;   typedef struct v3 { int a; int b; } __v3;
1243758
+;   #define _(x) (__builtin_preserve_access_index(x))
1243758
+;   int get_value(const int *arg);
1243758
+;   int test(__v3 *arg) {
1243758
+;     return get_value(_(&arg[1].b));
1243758
+;   }
1243758
+; Compilation flag:
1243758
+;   clang -target bpf -O2 -g -S -emit-llvm test.c
1243758
+
1243758
+%struct.v3 = type { i32, i32 }
1243758
+
1243758
+; Function Attrs: nounwind
1243758
+define dso_local i32 @test(%struct.v3* %arg) local_unnamed_addr #0 !dbg !15 {
1243758
+entry:
1243758
+  call void @llvm.dbg.value(metadata %struct.v3* %arg, metadata !19, metadata !DIExpression()), !dbg !20
1243758
+  %0 = tail call %struct.v3* @llvm.preserve.array.access.index.p0s_struct.v3s.p0s_struct.v3s(%struct.v3* %arg, i32 0, i32 1), !dbg !21, !llvm.preserve.access.index !4
1243758
+  %1 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v3s(%struct.v3* %0, i32 1, i32 1), !dbg !21, !llvm.preserve.access.index !6
1243758
+  %call = tail call i32 @get_value(i32* %1) #4, !dbg !22
1243758
+  ret i32 %call, !dbg !23
1243758
+}
1243758
+
1243758
+; CHECK:              r2 = 12
1243758
+; CHECK-NEXT:         r1 += r2
1243758
+; CHECK:              call get_value
1243758
+
1243758
+; CHECK:              .long   6                       # BTF_KIND_STRUCT(id = [[TID1:[0-9]+]])
1243758
+; CHECK:              .ascii  "v3"                    # string offset=6
1243758
+; CHECK:              .ascii  ".text"                 # string offset=26
1243758
+; CHECK:              .ascii  "1:1"                   # string offset=32
1243758
+
1243758
+; CHECK:              .long   12                      # OffsetReloc
1243758
+; CHECK-NEXT:         .long   26                      # Offset reloc section string offset=26
1243758
+; CHECK-NEXT:         .long   1
1243758
+; CHECK-NEXT:         .long   .Ltmp{{[0-9]+}}
1243758
+; CHECK-NEXT:         .long   [[TID1]]
1243758
+; CHECK-NEXT:         .long   32
1243758
+
1243758
+declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
1243758
+
1243758
+; Function Attrs: nounwind readnone
1243758
+declare %struct.v3* @llvm.preserve.array.access.index.p0s_struct.v3s.p0s_struct.v3s(%struct.v3*, i32, i32) #2
1243758
+
1243758
+; Function Attrs: nounwind readnone
1243758
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v3s(%struct.v3*, i32, i32) #2
1243758
+
1243758
+; Function Attrs: nounwind readnone speculatable willreturn
1243758
+declare void @llvm.dbg.value(metadata, metadata, metadata) #3
1243758
+
1243758
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
1243758
+attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
1243758
+attributes #2 = { nounwind readnone }
1243758
+attributes #3 = { nounwind readnone speculatable willreturn }
1243758
+attributes #4 = { nounwind }
1243758
+
1243758
+!llvm.dbg.cu = !{!0}
1243758
+!llvm.module.flags = !{!11, !12, !13}
1243758
+!llvm.ident = !{!14}
1243758
+
1243758
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None)
1243758
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
1243758
+!2 = !{}
1243758
+!3 = !{!4}
1243758
+!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64)
1243758
+!5 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v3", file: !1, line: 1, baseType: !6)
1243758
+!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !1, line: 1, size: 64, elements: !7)
1243758
+!7 = !{!8, !10}
1243758
+!8 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !6, file: !1, line: 1, baseType: !9, size: 32)
1243758
+!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
1243758
+!10 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !6, file: !1, line: 1, baseType: !9, size: 32, offset: 32)
1243758
+!11 = !{i32 2, !"Dwarf Version", i32 4}
1243758
+!12 = !{i32 2, !"Debug Info Version", i32 3}
1243758
+!13 = !{i32 1, !"wchar_size", i32 4}
1243758
+!14 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
1243758
+!15 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 4, type: !16, scopeLine: 4, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !18)
1243758
+!16 = !DISubroutineType(types: !17)
1243758
+!17 = !{!9, !4}
1243758
+!18 = !{!19}
1243758
+!19 = !DILocalVariable(name: "arg", arg: 1, scope: !15, file: !1, line: 4, type: !4)
1243758
+!20 = !DILocation(line: 0, scope: !15)
1243758
+!21 = !DILocation(line: 5, column: 20, scope: !15)
1243758
+!22 = !DILocation(line: 5, column: 10, scope: !15)
1243758
+!23 = !DILocation(line: 5, column: 3, scope: !15)
1243758
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-anonymous.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-anonymous.ll
1243758
index 732187c..08a204f 100644
1243758
--- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-anonymous.ll
1243758
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-anonymous.ll
1243758
@@ -30,7 +30,7 @@ define dso_local i32 @bpf_prog(%struct.sk_buff*) local_unnamed_addr #0 !dbg !15
1243758
   %3 = bitcast i32* %2 to i8*, !dbg !34
1243758
   call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %3) #4, !dbg !34
1243758
   %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
1243758
-  %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
1243758
+  %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, !llvm.preserve.access.index !23
1243758
   %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
1243758
   %7 = bitcast i32* %6 to i8*, !dbg !35
1243758
   %8 = call i32 inttoptr (i64 4 to i32 (i8*, i32, i8*)*)(i8* nonnull %3, i32 4, i8* %7) #4, !dbg !36
1243758
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-array.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-array.ll
1243758
index 77d2375..b18a4ab 100644
1243758
--- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-array.ll
1243758
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-array.ll
1243758
@@ -31,7 +31,7 @@ define dso_local i32 @bpf_prog(%struct.sk_buff*) local_unnamed_addr #0 !dbg !15
1243758
   %3 = bitcast i32* %2 to i8*, !dbg !34
1243758
   call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %3) #4, !dbg !34
1243758
   %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
1243758
-  %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
1243758
+  %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, !llvm.preserve.access.index !23
1243758
   %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
1243758
   %7 = bitcast i32* %6 to i8*, !dbg !35
1243758
   %8 = call i32 inttoptr (i64 4 to i32 (i8*, i32, i8*)*)(i8* nonnull %3, i32 4, i8* %7) #4, !dbg !36
1243758
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-array.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-array.ll
1243758
index 7843c52..d63bc07 100644
1243758
--- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-array.ll
1243758
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-array.ll
1243758
@@ -21,7 +21,7 @@ define dso_local i32 @test(%struct.__s* %arg) local_unnamed_addr #0 !dbg !7 {
1243758
 entry:
1243758
   call void @llvm.dbg.value(metadata %struct.__s* %arg, metadata !24, metadata !DIExpression()), !dbg !25
1243758
   %0 = tail call [7 x i32]* @llvm.preserve.struct.access.index.p0a7i32.p0s_struct.__ss(%struct.__s* %arg, i32 0, i32 0), !dbg !26, !llvm.preserve.access.index !13
1243758
-  %1 = tail call i32* @llvm.preserve.array.access.index.p0i32.p0a7i32([7 x i32]* %0, i32 1, i32 1), !dbg !26
1243758
+  %1 = tail call i32* @llvm.preserve.array.access.index.p0i32.p0a7i32([7 x i32]* %0, i32 1, i32 1), !dbg !26, !llvm.preserve.access.index !19
1243758
   %2 = bitcast i32* %1 to i8*, !dbg !26
1243758
   %call = tail call i32 @get_value(i8* %2) #4, !dbg !27
1243758
   ret i32 %call, !dbg !28
1243758
diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef.ll
1243758
index c09d979..8281694 100644
1243758
--- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef.ll
1243758
+++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef.ll
1243758
@@ -24,7 +24,7 @@
1243758
 define dso_local i32 @test([7 x %union.u]* %arg) local_unnamed_addr #0 !dbg !7 {
1243758
 entry:
1243758
   call void @llvm.dbg.value(metadata [7 x %union.u]* %arg, metadata !28, metadata !DIExpression()), !dbg !29
1243758
-  %0 = tail call [7 x %union.u]* @llvm.preserve.array.access.index.p0a7s_union.us.p0a7s_union.us([7 x %union.u]* %arg, i32 0, i32 1), !dbg !30
1243758
+  %0 = tail call [7 x %union.u]* @llvm.preserve.array.access.index.p0a7s_union.us.p0a7s_union.us([7 x %union.u]* %arg, i32 0, i32 1), !dbg !30, !llvm.preserve.access.index !14
1243758
   %arraydecay = getelementptr inbounds [7 x %union.u], [7 x %union.u]* %0, i64 0, i64 0, !dbg !30
1243758
   %1 = tail call %union.u* @llvm.preserve.union.access.index.p0s_union.us.p0s_union.us(%union.u* %arraydecay, i32 1), !dbg !30, !llvm.preserve.access.index !16
1243758
   %d = getelementptr inbounds %union.u, %union.u* %1, i64 0, i32 0, !dbg !30
1243758
-- 
1243758
1.8.3.1
1243758