diff --git a/.gitignore b/.gitignore
index 02ad497..7adc32b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1 @@
-SOURCES/llvm-8.0.1.src.tar.xz
+SOURCES/llvm-9.0.1.src.tar.xz
diff --git a/.llvm.metadata b/.llvm.metadata
index 59cfa37..fe0c8ba 100644
--- a/.llvm.metadata
+++ b/.llvm.metadata
@@ -1 +1 @@
-09964f9eabc364f221a3caefbdaea28557273b4a SOURCES/llvm-8.0.1.src.tar.xz
+f7fcf3bd92d130784513c06efe6910f135372ce3 SOURCES/llvm-9.0.1.src.tar.xz
diff --git a/SOURCES/0001-BPF-Handling-type-conversions-correctly-for-CO-RE.patch b/SOURCES/0001-BPF-Handling-type-conversions-correctly-for-CO-RE.patch
new file mode 100644
index 0000000..bfde9bc
--- /dev/null
+++ b/SOURCES/0001-BPF-Handling-type-conversions-correctly-for-CO-RE.patch
@@ -0,0 +1,2510 @@
+From 20253836fbb1baf5c7cd6fb6558bd12dff682855 Mon Sep 17 00:00:00 2001
+From: Yonghong Song <yhs@fb.com>
+Date: Fri, 2 Aug 2019 23:16:44 +0000
+Subject: [PATCH] [BPF] Handling type conversions correctly for CO-RE
+
+With newly added debuginfo type
+metadata for preserve_array_access_index() intrinsic,
+this patch did the following two things:
+ (1). checking validity before adding a new access index
+      to the access chain.
+ (2). calculating access byte offset in IR phase
+      BPFAbstractMemberAccess instead of when BTF is emitted.
+
+For (1), the metadata provided by all preserve_*_access_index()
+intrinsics are used to check whether the to-be-added type
+is a proper struct/union member or array element.
+
+For (2), with all available metadata, calculating access byte
+offset becomes easier in BPFAbstractMemberAccess IR phase.
+This enables us to remove the unnecessary complexity in
+BTFDebug.cpp.
+
+New tests are added for
+  . user explicit casting to array/structure/union
+  . global variable (or its dereference) as the source of base
+  . multi demensional arrays
+  . array access given a base pointer
+  . cases where we won't generate relocation if we cannot find
+    type name.
+
+Differential Revision: https://reviews.llvm.org/D65618
+
+llvm-svn: 367735
+(cherry picked from commit 37d24a696bf74f4830f2582d2f36256ca1b6bb30)
+---
+ llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp    | 332 +++++++++++++++++----
+ llvm/lib/Target/BPF/BTFDebug.cpp                   | 110 +------
+ llvm/lib/Target/BPF/BTFDebug.h                     |  15 +-
+ .../CodeGen/BPF/CORE/offset-reloc-cast-array-1.ll  | 124 ++++++++
+ .../CodeGen/BPF/CORE/offset-reloc-cast-array-2.ll  | 131 ++++++++
+ .../CodeGen/BPF/CORE/offset-reloc-cast-struct-1.ll | 112 +++++++
+ .../CodeGen/BPF/CORE/offset-reloc-cast-struct-2.ll | 117 ++++++++
+ .../CodeGen/BPF/CORE/offset-reloc-cast-struct-3.ll | 116 +++++++
+ .../CodeGen/BPF/CORE/offset-reloc-cast-union-1.ll  | 117 ++++++++
+ .../CodeGen/BPF/CORE/offset-reloc-cast-union-2.ll  | 118 ++++++++
+ .../test/CodeGen/BPF/CORE/offset-reloc-global-1.ll |  79 +++++
+ .../test/CodeGen/BPF/CORE/offset-reloc-global-2.ll |  95 ++++++
+ .../test/CodeGen/BPF/CORE/offset-reloc-global-3.ll |  84 ++++++
+ llvm/test/CodeGen/BPF/CORE/offset-reloc-ignore.ll  |  62 ++++
+ .../CodeGen/BPF/CORE/offset-reloc-multi-array-1.ll | 101 +++++++
+ .../CodeGen/BPF/CORE/offset-reloc-multi-array-2.ll | 107 +++++++
+ .../CodeGen/BPF/CORE/offset-reloc-pointer-1.ll     |  83 ++++++
+ .../CodeGen/BPF/CORE/offset-reloc-pointer-2.ll     |  85 ++++++
+ .../BPF/CORE/offset-reloc-struct-anonymous.ll      |   2 +-
+ .../CodeGen/BPF/CORE/offset-reloc-struct-array.ll  |   2 +-
+ .../CodeGen/BPF/CORE/offset-reloc-typedef-array.ll |   2 +-
+ llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef.ll |   2 +-
+ 22 files changed, 1812 insertions(+), 184 deletions(-)
+ create mode 100644 llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-array-1.ll
+ create mode 100644 llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-array-2.ll
+ create mode 100644 llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-1.ll
+ create mode 100644 llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-2.ll
+ create mode 100644 llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-3.ll
+ create mode 100644 llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-union-1.ll
+ create mode 100644 llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-union-2.ll
+ create mode 100644 llvm/test/CodeGen/BPF/CORE/offset-reloc-global-1.ll
+ create mode 100644 llvm/test/CodeGen/BPF/CORE/offset-reloc-global-2.ll
+ create mode 100644 llvm/test/CodeGen/BPF/CORE/offset-reloc-global-3.ll
+ create mode 100644 llvm/test/CodeGen/BPF/CORE/offset-reloc-ignore.ll
+ create mode 100644 llvm/test/CodeGen/BPF/CORE/offset-reloc-multi-array-1.ll
+ create mode 100644 llvm/test/CodeGen/BPF/CORE/offset-reloc-multi-array-2.ll
+ create mode 100644 llvm/test/CodeGen/BPF/CORE/offset-reloc-pointer-1.ll
+ create mode 100644 llvm/test/CodeGen/BPF/CORE/offset-reloc-pointer-2.ll
+
+diff --git a/llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp b/llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp
+index 509484b..f55f6f9 100644
+--- a/llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp
++++ b/llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp
+@@ -65,6 +65,7 @@
+ #include "llvm/IR/Value.h"
+ #include "llvm/Pass.h"
+ #include "llvm/Transforms/Utils/BasicBlockUtils.h"
++#include <stack>
+ 
+ #define DEBUG_TYPE "bpf-abstract-member-access"
+ 
+@@ -106,18 +107,24 @@ private:
+ 
+   bool doTransformation(Module &M);
+ 
+-  void traceAICall(CallInst *Call, uint32_t Kind);
+-  void traceBitCast(BitCastInst *BitCast, CallInst *Parent, uint32_t Kind);
+-  void traceGEP(GetElementPtrInst *GEP, CallInst *Parent, uint32_t Kind);
++  void traceAICall(CallInst *Call, uint32_t Kind, const MDNode *ParentMeta,
++                   uint32_t ParentAI);
++  void traceBitCast(BitCastInst *BitCast, CallInst *Parent, uint32_t Kind,
++                    const MDNode *ParentMeta, uint32_t ParentAI);
++  void traceGEP(GetElementPtrInst *GEP, CallInst *Parent, uint32_t Kind,
++                const MDNode *ParentMeta, uint32_t ParentAI);
+   void collectAICallChains(Module &M, Function &F);
+ 
+-  bool IsPreserveDIAccessIndexCall(const CallInst *Call, uint32_t &Kind);
++  bool IsPreserveDIAccessIndexCall(const CallInst *Call, uint32_t &Kind,
++                                   const MDNode *&TypeMeta, uint32_t &AccessIndex);
++  bool IsValidAIChain(const MDNode *ParentMeta, uint32_t ParentAI,
++                      const MDNode *ChildMeta);
+   bool removePreserveAccessIndexIntrinsic(Module &M);
+   void replaceWithGEP(std::vector<CallInst *> &CallList,
+                       uint32_t NumOfZerosIndex, uint32_t DIIndex);
+ 
+   Value *computeBaseAndAccessKey(CallInst *Call, std::string &AccessKey,
+-                                 uint32_t Kind, MDNode *&TypeMeta);
++                                 uint32_t Kind, MDNode *&BaseMeta);
+   bool getAccessIndex(const Value *IndexValue, uint64_t &AccessIndex);
+   bool transformGEPChain(Module &M, CallInst *Call, uint32_t Kind);
+ };
+@@ -141,9 +148,53 @@ bool BPFAbstractMemberAccess::runOnModule(Module &M) {
+   return doTransformation(M);
+ }
+ 
++static bool SkipDIDerivedTag(unsigned Tag) {
++  if (Tag != dwarf::DW_TAG_typedef && Tag != dwarf::DW_TAG_const_type &&
++      Tag != dwarf::DW_TAG_volatile_type &&
++      Tag != dwarf::DW_TAG_restrict_type &&
++      Tag != dwarf::DW_TAG_member)
++     return false;
++  return true;
++}
++
++static DIType * stripQualifiers(DIType *Ty) {
++  while (auto *DTy = dyn_cast<DIDerivedType>(Ty)) {
++    if (!SkipDIDerivedTag(DTy->getTag()))
++      break;
++    Ty = DTy->getBaseType();
++  }
++  return Ty;
++}
++
++static const DIType * stripQualifiers(const DIType *Ty) {
++  while (auto *DTy = dyn_cast<DIDerivedType>(Ty)) {
++    if (!SkipDIDerivedTag(DTy->getTag()))
++      break;
++    Ty = DTy->getBaseType();
++  }
++  return Ty;
++}
++
++static uint32_t calcArraySize(const DICompositeType *CTy, uint32_t StartDim) {
++  DINodeArray Elements = CTy->getElements();
++  uint32_t DimSize = 1;
++  for (uint32_t I = StartDim; I < Elements.size(); ++I) {
++    if (auto *Element = dyn_cast_or_null<DINode>(Elements[I]))
++      if (Element->getTag() == dwarf::DW_TAG_subrange_type) {
++        const DISubrange *SR = cast<DISubrange>(Element);
++        auto *CI = SR->getCount().dyn_cast<ConstantInt *>();
++        DimSize *= CI->getSExtValue();
++      }
++  }
++
++  return DimSize;
++}
++
+ /// Check whether a call is a preserve_*_access_index intrinsic call or not.
+ bool BPFAbstractMemberAccess::IsPreserveDIAccessIndexCall(const CallInst *Call,
+-                                                          uint32_t &Kind) {
++                                                          uint32_t &Kind,
++                                                          const MDNode *&TypeMeta,
++                                                          uint32_t &AccessIndex) {
+   if (!Call)
+     return false;
+ 
+@@ -152,14 +203,29 @@ bool BPFAbstractMemberAccess::IsPreserveDIAccessIndexCall(const CallInst *Call,
+     return false;
+   if (GV->getName().startswith("llvm.preserve.array.access.index")) {
+     Kind = BPFPreserveArrayAI;
++    TypeMeta = Call->getMetadata(LLVMContext::MD_preserve_access_index);
++    if (!TypeMeta)
++      report_fatal_error("Missing metadata for llvm.preserve.array.access.index intrinsic");
++    AccessIndex = cast<ConstantInt>(Call->getArgOperand(2))
++                      ->getZExtValue();
+     return true;
+   }
+   if (GV->getName().startswith("llvm.preserve.union.access.index")) {
+     Kind = BPFPreserveUnionAI;
++    TypeMeta = Call->getMetadata(LLVMContext::MD_preserve_access_index);
++    if (!TypeMeta)
++      report_fatal_error("Missing metadata for llvm.preserve.union.access.index intrinsic");
++    AccessIndex = cast<ConstantInt>(Call->getArgOperand(1))
++                      ->getZExtValue();
+     return true;
+   }
+   if (GV->getName().startswith("llvm.preserve.struct.access.index")) {
+     Kind = BPFPreserveStructAI;
++    TypeMeta = Call->getMetadata(LLVMContext::MD_preserve_access_index);
++    if (!TypeMeta)
++      report_fatal_error("Missing metadata for llvm.preserve.struct.access.index intrinsic");
++    AccessIndex = cast<ConstantInt>(Call->getArgOperand(2))
++                      ->getZExtValue();
+     return true;
+   }
+ 
+@@ -200,7 +266,9 @@ bool BPFAbstractMemberAccess::removePreserveAccessIndexIntrinsic(Module &M) {
+       for (auto &I : BB) {
+         auto *Call = dyn_cast<CallInst>(&I);
+         uint32_t Kind;
+-        if (!IsPreserveDIAccessIndexCall(Call, Kind))
++        const MDNode *TypeMeta;
++        uint32_t AccessIndex;
++        if (!IsPreserveDIAccessIndexCall(Call, Kind, TypeMeta, AccessIndex))
+           continue;
+ 
+         Found = true;
+@@ -232,25 +300,79 @@ bool BPFAbstractMemberAccess::removePreserveAccessIndexIntrinsic(Module &M) {
+   return Found;
+ }
+ 
+-void BPFAbstractMemberAccess::traceAICall(CallInst *Call, uint32_t Kind) {
++/// Check whether the access index chain is valid. We check
++/// here because there may be type casts between two
++/// access indexes. We want to ensure memory access still valid.
++bool BPFAbstractMemberAccess::IsValidAIChain(const MDNode *ParentType,
++                                             uint32_t ParentAI,
++                                             const MDNode *ChildType) {
++  const DIType *PType = stripQualifiers(cast<DIType>(ParentType));
++  const DIType *CType = stripQualifiers(cast<DIType>(ChildType));
++
++  // Child is a derived/pointer type, which is due to type casting.
++  // Pointer type cannot be in the middle of chain.
++  if (const auto *PtrTy = dyn_cast<DIDerivedType>(CType))
++    return false;
++
++  // Parent is a pointer type.
++  if (const auto *PtrTy = dyn_cast<DIDerivedType>(PType)) {
++    if (PtrTy->getTag() != dwarf::DW_TAG_pointer_type)
++      return false;
++    return stripQualifiers(PtrTy->getBaseType()) == CType;
++  }
++
++  // Otherwise, struct/union/array types
++  const auto *PTy = dyn_cast<DICompositeType>(PType);
++  const auto *CTy = dyn_cast<DICompositeType>(CType);
++  assert(PTy && CTy && "ParentType or ChildType is null or not composite");
++
++  uint32_t PTyTag = PTy->getTag();
++  assert(PTyTag == dwarf::DW_TAG_array_type ||
++         PTyTag == dwarf::DW_TAG_structure_type ||
++         PTyTag == dwarf::DW_TAG_union_type);
++
++  uint32_t CTyTag = CTy->getTag();
++  assert(CTyTag == dwarf::DW_TAG_array_type ||
++         CTyTag == dwarf::DW_TAG_structure_type ||
++         CTyTag == dwarf::DW_TAG_union_type);
++
++  // Multi dimensional arrays, base element should be the same
++  if (PTyTag == dwarf::DW_TAG_array_type && PTyTag == CTyTag)
++    return PTy->getBaseType() == CTy->getBaseType();
++
++  DIType *Ty;
++  if (PTyTag == dwarf::DW_TAG_array_type)
++    Ty = PTy->getBaseType();
++  else
++    Ty = dyn_cast<DIType>(PTy->getElements()[ParentAI]);
++
++  return dyn_cast<DICompositeType>(stripQualifiers(Ty)) == CTy;
++}
++
++void BPFAbstractMemberAccess::traceAICall(CallInst *Call, uint32_t Kind,
++                                          const MDNode *ParentMeta,
++                                          uint32_t ParentAI) {
+   for (User *U : Call->users()) {
+     Instruction *Inst = dyn_cast<Instruction>(U);
+     if (!Inst)
+       continue;
+ 
+     if (auto *BI = dyn_cast<BitCastInst>(Inst)) {
+-      traceBitCast(BI, Call, Kind);
++      traceBitCast(BI, Call, Kind, ParentMeta, ParentAI);
+     } else if (auto *CI = dyn_cast<CallInst>(Inst)) {
+       uint32_t CIKind;
+-      if (IsPreserveDIAccessIndexCall(CI, CIKind)) {
++      const MDNode *ChildMeta;
++      uint32_t ChildAI;
++      if (IsPreserveDIAccessIndexCall(CI, CIKind, ChildMeta, ChildAI) &&
++          IsValidAIChain(ParentMeta, ParentAI, ChildMeta)) {
+         AIChain[CI] = std::make_pair(Call, Kind);
+-        traceAICall(CI, CIKind);
++        traceAICall(CI, CIKind, ChildMeta, ChildAI);
+       } else {
+         BaseAICalls[Call] = Kind;
+       }
+     } else if (auto *GI = dyn_cast<GetElementPtrInst>(Inst)) {
+       if (GI->hasAllZeroIndices())
+-        traceGEP(GI, Call, Kind);
++        traceGEP(GI, Call, Kind, ParentMeta, ParentAI);
+       else
+         BaseAICalls[Call] = Kind;
+     }
+@@ -258,25 +380,30 @@ void BPFAbstractMemberAccess::traceAICall(CallInst *Call, uint32_t Kind) {
+ }
+ 
+ void BPFAbstractMemberAccess::traceBitCast(BitCastInst *BitCast,
+-                                           CallInst *Parent, uint32_t Kind) {
++                                           CallInst *Parent, uint32_t Kind,
++                                           const MDNode *ParentMeta,
++                                           uint32_t ParentAI) {
+   for (User *U : BitCast->users()) {
+     Instruction *Inst = dyn_cast<Instruction>(U);
+     if (!Inst)
+       continue;
+ 
+     if (auto *BI = dyn_cast<BitCastInst>(Inst)) {
+-      traceBitCast(BI, Parent, Kind);
++      traceBitCast(BI, Parent, Kind, ParentMeta, ParentAI);
+     } else if (auto *CI = dyn_cast<CallInst>(Inst)) {
+       uint32_t CIKind;
+-      if (IsPreserveDIAccessIndexCall(CI, CIKind)) {
++      const MDNode *ChildMeta;
++      uint32_t ChildAI;
++      if (IsPreserveDIAccessIndexCall(CI, CIKind, ChildMeta, ChildAI) &&
++          IsValidAIChain(ParentMeta, ParentAI, ChildMeta)) {
+         AIChain[CI] = std::make_pair(Parent, Kind);
+-        traceAICall(CI, CIKind);
++        traceAICall(CI, CIKind, ChildMeta, ChildAI);
+       } else {
+         BaseAICalls[Parent] = Kind;
+       }
+     } else if (auto *GI = dyn_cast<GetElementPtrInst>(Inst)) {
+       if (GI->hasAllZeroIndices())
+-        traceGEP(GI, Parent, Kind);
++        traceGEP(GI, Parent, Kind, ParentMeta, ParentAI);
+       else
+         BaseAICalls[Parent] = Kind;
+     }
+@@ -284,25 +411,29 @@ void BPFAbstractMemberAccess::traceBitCast(BitCastInst *BitCast,
+ }
+ 
+ void BPFAbstractMemberAccess::traceGEP(GetElementPtrInst *GEP, CallInst *Parent,
+-                                       uint32_t Kind) {
++                                       uint32_t Kind, const MDNode *ParentMeta,
++                                       uint32_t ParentAI) {
+   for (User *U : GEP->users()) {
+     Instruction *Inst = dyn_cast<Instruction>(U);
+     if (!Inst)
+       continue;
+ 
+     if (auto *BI = dyn_cast<BitCastInst>(Inst)) {
+-      traceBitCast(BI, Parent, Kind);
++      traceBitCast(BI, Parent, Kind, ParentMeta, ParentAI);
+     } else if (auto *CI = dyn_cast<CallInst>(Inst)) {
+       uint32_t CIKind;
+-      if (IsPreserveDIAccessIndexCall(CI, CIKind)) {
++      const MDNode *ChildMeta;
++      uint32_t ChildAI;
++      if (IsPreserveDIAccessIndexCall(CI, CIKind, ChildMeta, ChildAI) &&
++          IsValidAIChain(ParentMeta, ParentAI, ChildMeta)) {
+         AIChain[CI] = std::make_pair(Parent, Kind);
+-        traceAICall(CI, CIKind);
++        traceAICall(CI, CIKind, ChildMeta, ChildAI);
+       } else {
+         BaseAICalls[Parent] = Kind;
+       }
+     } else if (auto *GI = dyn_cast<GetElementPtrInst>(Inst)) {
+       if (GI->hasAllZeroIndices())
+-        traceGEP(GI, Parent, Kind);
++        traceGEP(GI, Parent, Kind, ParentMeta, ParentAI);
+       else
+         BaseAICalls[Parent] = Kind;
+     }
+@@ -316,12 +447,14 @@ void BPFAbstractMemberAccess::collectAICallChains(Module &M, Function &F) {
+   for (auto &BB : F)
+     for (auto &I : BB) {
+       uint32_t Kind;
++      const MDNode *TypeMeta;
++      uint32_t AccessIndex;
+       auto *Call = dyn_cast<CallInst>(&I);
+-      if (!IsPreserveDIAccessIndexCall(Call, Kind) ||
++      if (!IsPreserveDIAccessIndexCall(Call, Kind, TypeMeta, AccessIndex) ||
+           AIChain.find(Call) != AIChain.end())
+         continue;
+ 
+-      traceAICall(Call, Kind);
++      traceAICall(Call, Kind, TypeMeta, AccessIndex);
+     }
+ }
+ 
+@@ -344,62 +477,131 @@ Value *BPFAbstractMemberAccess::computeBaseAndAccessKey(CallInst *Call,
+                                                         uint32_t Kind,
+                                                         MDNode *&TypeMeta) {
+   Value *Base = nullptr;
+-  std::vector<uint64_t> AccessIndices;
+-  uint64_t TypeNameIndex = 0;
+-  std::string LastTypeName;
++  std::string TypeName;
++  std::stack<std::pair<CallInst *, uint32_t>> CallStack;
+ 
++  // Put the access chain into a stack with the top as the head of the chain.
+   while (Call) {
+-    // Base of original corresponding GEP
+-    Base = Call->getArgOperand(0);
++    CallStack.push(std::make_pair(Call, Kind));
++    Kind = AIChain[Call].second;
++    Call = AIChain[Call].first;
++  }
+ 
+-    // Type Name
+-    std::string TypeName;
+-    MDNode *MDN;
++  // The access offset from the base of the head of chain is also
++  // calculated here as all debuginfo types are available.
++
++  // Get type name and calculate the first index.
++  // We only want to get type name from structure or union.
++  // If user wants a relocation like
++  //    int *p; ... __builtin_preserve_access_index(&p[4]) ...
++  // or
++  //    int a[10][20]; ... __builtin_preserve_access_index(&a[2][3]) ...
++  // we will skip them.
++  uint32_t FirstIndex = 0;
++  uint32_t AccessOffset = 0;
++  while (CallStack.size()) {
++    auto StackElem = CallStack.top();
++    Call = StackElem.first;
++    Kind = StackElem.second;
++
++    if (!Base)
++      Base = Call->getArgOperand(0);
++
++    MDNode *MDN = Call->getMetadata(LLVMContext::MD_preserve_access_index);
++    DIType *Ty = stripQualifiers(cast<DIType>(MDN));
+     if (Kind == BPFPreserveUnionAI || Kind == BPFPreserveStructAI) {
+-      MDN = Call->getMetadata(LLVMContext::MD_preserve_access_index);
+-      if (!MDN)
+-        return nullptr;
++      // struct or union type
++      TypeName = Ty->getName();
++      TypeMeta = Ty;
++      AccessOffset += FirstIndex * Ty->getSizeInBits() >> 3;
++      break;
++    }
+ 
+-      DIType *Ty = dyn_cast<DIType>(MDN);
+-      if (!Ty)
++    // Array entries will always be consumed for accumulative initial index.
++    CallStack.pop();
++
++    // BPFPreserveArrayAI
++    uint64_t AccessIndex;
++    if (!getAccessIndex(Call->getArgOperand(2), AccessIndex))
++      return nullptr;
++
++    DIType *BaseTy = nullptr;
++    bool CheckElemType = false;
++    if (const auto *CTy = dyn_cast<DICompositeType>(Ty)) {
++      // array type
++      assert(CTy->getTag() == dwarf::DW_TAG_array_type);
++
++
++      FirstIndex += AccessIndex * calcArraySize(CTy, 1);
++      BaseTy = stripQualifiers(CTy->getBaseType());
++      CheckElemType = CTy->getElements().size() == 1;
++    } else {
++      // pointer type
++      auto *DTy = cast<DIDerivedType>(Ty);
++      assert(DTy->getTag() == dwarf::DW_TAG_pointer_type);
++
++      BaseTy = stripQualifiers(DTy->getBaseType());
++      CTy = dyn_cast<DICompositeType>(BaseTy);
++      if (!CTy) {
++        CheckElemType = true;
++      } else if (CTy->getTag() != dwarf::DW_TAG_array_type) {
++        FirstIndex += AccessIndex;
++        CheckElemType = true;
++      } else {
++        FirstIndex += AccessIndex * calcArraySize(CTy, 0);
++      }
++    }
++
++    if (CheckElemType) {
++      auto *CTy = dyn_cast<DICompositeType>(BaseTy);
++      if (!CTy)
+         return nullptr;
+ 
+-      TypeName = Ty->getName();
++      unsigned CTag = CTy->getTag();
++      if (CTag != dwarf::DW_TAG_structure_type && CTag != dwarf::DW_TAG_union_type)
++        return nullptr;
++      else
++        TypeName = CTy->getName();
++      TypeMeta = CTy;
++      AccessOffset += FirstIndex * CTy->getSizeInBits() >> 3;
++      break;
+     }
++  }
++  assert(TypeName.size());
++  AccessKey += std::to_string(FirstIndex);
++
++  // Traverse the rest of access chain to complete offset calculation
++  // and access key construction.
++  while (CallStack.size()) {
++    auto StackElem = CallStack.top();
++    Call = StackElem.first;
++    Kind = StackElem.second;
++    CallStack.pop();
+ 
+     // Access Index
+     uint64_t AccessIndex;
+     uint32_t ArgIndex = (Kind == BPFPreserveUnionAI) ? 1 : 2;
+     if (!getAccessIndex(Call->getArgOperand(ArgIndex), AccessIndex))
+       return nullptr;
+-
+-    AccessIndices.push_back(AccessIndex);
+-    if (TypeName.size()) {
+-      TypeNameIndex = AccessIndices.size() - 1;
+-      LastTypeName = TypeName;
+-      TypeMeta = MDN;
++    AccessKey += ":" + std::to_string(AccessIndex);
++
++    MDNode *MDN = Call->getMetadata(LLVMContext::MD_preserve_access_index);
++    // At this stage, it cannot be pointer type.
++    auto *CTy = cast<DICompositeType>(stripQualifiers(cast<DIType>(MDN)));
++    uint32_t Tag = CTy->getTag();
++    if (Tag == dwarf::DW_TAG_structure_type) {
++      auto *MemberTy = cast<DIDerivedType>(CTy->getElements()[AccessIndex]);
++      AccessOffset += MemberTy->getOffsetInBits() >> 3;
++    } else if (Tag == dwarf::DW_TAG_array_type) {
++      auto *EltTy = stripQualifiers(CTy->getBaseType());
++      AccessOffset += AccessIndex * calcArraySize(CTy, 1) *
++                      EltTy->getSizeInBits() >> 3;
+     }
+-
+-    Kind = AIChain[Call].second;
+-    Call = AIChain[Call].first;
+   }
+ 
+-  // The intial type name is required.
+-  // FIXME: if the initial type access is an array index, e.g.,
+-  // &a[3].b.c, only one dimentional array is supported.
+-  if (!LastTypeName.size() || AccessIndices.size() > TypeNameIndex + 2)
+-    return nullptr;
+-
+-  // Construct the type string AccessKey.
+-  for (unsigned I = 0; I < AccessIndices.size(); ++I)
+-    AccessKey = std::to_string(AccessIndices[I]) + ":" + AccessKey;
+-
+-  if (TypeNameIndex == AccessIndices.size() - 1)
+-    AccessKey = "0:" + AccessKey;
+-
+   // Access key is the type name + access string, uniquely identifying
+   // one kernel memory access.
+-  AccessKey = LastTypeName + ":" + AccessKey;
++  AccessKey = TypeName + ":" + std::to_string(AccessOffset) + "$" + AccessKey;
+ 
+   return Base;
+ }
+@@ -409,7 +611,7 @@ Value *BPFAbstractMemberAccess::computeBaseAndAccessKey(CallInst *Call,
+ bool BPFAbstractMemberAccess::transformGEPChain(Module &M, CallInst *Call,
+                                                 uint32_t Kind) {
+   std::string AccessKey;
+-  MDNode *TypeMeta = nullptr;
++  MDNode *TypeMeta;
+   Value *Base =
+       computeBaseAndAccessKey(Call, AccessKey, Kind, TypeMeta);
+   if (!Base)
+@@ -419,7 +621,7 @@ bool BPFAbstractMemberAccess::transformGEPChain(Module &M, CallInst *Call,
+   // For any original GEP Call and Base %2 like
+   //   %4 = bitcast %struct.net_device** %dev1 to i64*
+   // it is transformed to:
+-  //   %6 = load __BTF_0:sk_buff:0:0:2:0:
++  //   %6 = load sk_buff:50:$0:0:0:2:0
+   //   %7 = bitcast %struct.sk_buff* %2 to i8*
+   //   %8 = getelementptr i8, i8* %7, %6
+   //   %9 = bitcast i8* %8 to i64*
+@@ -432,9 +634,7 @@ bool BPFAbstractMemberAccess::transformGEPChain(Module &M, CallInst *Call,
+     GV = new GlobalVariable(M, Type::getInt64Ty(BB->getContext()), false,
+                             GlobalVariable::ExternalLinkage, NULL, AccessKey);
+     GV->addAttribute(BPFCoreSharedInfo::AmaAttr);
+-    // Set the metadata (debuginfo types) for the global.
+-    if (TypeMeta)
+-      GV->setMetadata(LLVMContext::MD_preserve_access_index, TypeMeta);
++    GV->setMetadata(LLVMContext::MD_preserve_access_index, TypeMeta);
+     GEPGlobals[AccessKey] = GV;
+   } else {
+     GV = GEPGlobals[AccessKey];
+diff --git a/llvm/lib/Target/BPF/BTFDebug.cpp b/llvm/lib/Target/BPF/BTFDebug.cpp
+index 5c542e7..9b966eb 100644
+--- a/llvm/lib/Target/BPF/BTFDebug.cpp
++++ b/llvm/lib/Target/BPF/BTFDebug.cpp
+@@ -30,18 +30,6 @@ static const char *BTFKindStr[] = {
+ #include "BTF.def"
+ };
+ 
+-static const DIType * stripQualifiers(const DIType *Ty) {
+-  while (const auto *DTy = dyn_cast<DIDerivedType>(Ty)) {
+-    unsigned Tag = DTy->getTag();
+-    if (Tag != dwarf::DW_TAG_typedef && Tag != dwarf::DW_TAG_const_type &&
+-        Tag != dwarf::DW_TAG_volatile_type && Tag != dwarf::DW_TAG_restrict_type)
+-      break;
+-    Ty = DTy->getBaseType();
+-  }
+-
+-  return Ty;
+-}
+-
+ /// Emit a BTF common type.
+ void BTFTypeBase::emitType(MCStreamer &OS) {
+   OS.AddComment(std::string(BTFKindStr[Kind]) + "(id = " + std::to_string(Id) +
+@@ -196,9 +184,7 @@ void BTFTypeEnum::emitType(MCStreamer &OS) {
+   }
+ }
+ 
+-BTFTypeArray::BTFTypeArray(const DIType *Ty, uint32_t ElemTypeId,
+-                           uint32_t ElemSize, uint32_t NumElems)
+-    : ElemTyNoQual(Ty), ElemSize(ElemSize) {
++BTFTypeArray::BTFTypeArray(uint32_t ElemTypeId, uint32_t NumElems) {
+   Kind = BTF::BTF_KIND_ARRAY;
+   BTFType.NameOff = 0;
+   BTFType.Info = Kind << 24;
+@@ -219,9 +205,6 @@ void BTFTypeArray::completeType(BTFDebug &BDebug) {
+   // created during initial type traversal. Just
+   // retrieve that type id.
+   ArrayInfo.IndexType = BDebug.getArrayIndexTypeId();
+-
+-  ElemTypeNoQual = ElemTyNoQual ? BDebug.getTypeId(ElemTyNoQual)
+-                                : ArrayInfo.ElemType;
+ }
+ 
+ void BTFTypeArray::emitType(MCStreamer &OS) {
+@@ -231,12 +214,6 @@ void BTFTypeArray::emitType(MCStreamer &OS) {
+   OS.EmitIntValue(ArrayInfo.Nelems, 4);
+ }
+ 
+-void BTFTypeArray::getLocInfo(uint32_t Loc, uint32_t &LocOffset,
+-                              uint32_t &ElementTypeId) {
+-  ElementTypeId = ElemTypeNoQual;
+-  LocOffset = Loc * ElemSize;
+-}
+-
+ /// Represent either a struct or a union.
+ BTFTypeStruct::BTFTypeStruct(const DICompositeType *STy, bool IsStruct,
+                              bool HasBitField, uint32_t Vlen)
+@@ -268,7 +245,6 @@ void BTFTypeStruct::completeType(BTFDebug &BDebug) {
+     }
+     const auto *BaseTy = DDTy->getBaseType();
+     BTFMember.Type = BDebug.getTypeId(BaseTy);
+-    MemberTypeNoQual.push_back(BDebug.getTypeId(stripQualifiers(BaseTy)));
+     Members.push_back(BTFMember);
+   }
+ }
+@@ -285,15 +261,6 @@ void BTFTypeStruct::emitType(MCStreamer &OS) {
+ 
+ std::string BTFTypeStruct::getName() { return STy->getName(); }
+ 
+-void BTFTypeStruct::getMemberInfo(uint32_t Loc, uint32_t &MemberOffset,
+-                                  uint32_t &MemberType) {
+-  MemberType = MemberTypeNoQual[Loc];
+-  MemberOffset =
+-      HasBitField ? Members[Loc].Offset & 0xffffff : Members[Loc].Offset;
+-}
+-
+-uint32_t BTFTypeStruct::getStructSize() { return STy->getSizeInBits() >> 3; }
+-
+ /// The Func kind represents both subprogram and pointee of function
+ /// pointers. If the FuncName is empty, it represents a pointee of function
+ /// pointer. Otherwise, it represents a subprogram. The func arg names
+@@ -511,12 +478,10 @@ void BTFDebug::visitArrayType(const DICompositeType *CTy, uint32_t &TypeId) {
+   visitTypeEntry(ElemType, ElemTypeId, false, false);
+ 
+   // Strip qualifiers from element type to get accurate element size.
+-  ElemType = stripQualifiers(ElemType);
+   ElemSize = ElemType->getSizeInBits() >> 3;
+ 
+   if (!CTy->getSizeInBits()) {
+-    auto TypeEntry = llvm::make_unique<BTFTypeArray>(ElemType, ElemTypeId, 0, 0);
+-    ArrayTypes.push_back(TypeEntry.get());
++    auto TypeEntry = llvm::make_unique<BTFTypeArray>(ElemTypeId, 0);
+     ElemTypeId = addType(std::move(TypeEntry), CTy);
+   } else {
+     // Visit array dimensions.
+@@ -527,12 +492,9 @@ void BTFDebug::visitArrayType(const DICompositeType *CTy, uint32_t &TypeId) {
+           const DISubrange *SR = cast<DISubrange>(Element);
+           auto *CI = SR->getCount().dyn_cast<ConstantInt *>();
+           int64_t Count = CI->getSExtValue();
+-          const DIType *ArrayElemTy = (I == 0) ? ElemType : nullptr;
+ 
+           auto TypeEntry =
+-              llvm::make_unique<BTFTypeArray>(ArrayElemTy, ElemTypeId,
+-                                              ElemSize, Count);
+-          ArrayTypes.push_back(TypeEntry.get());
++              llvm::make_unique<BTFTypeArray>(ElemTypeId, Count);
+           if (I == 0)
+             ElemTypeId = addType(std::move(TypeEntry), CTy);
+           else
+@@ -1002,74 +964,22 @@ unsigned BTFDebug::populateStructType(const DIType *Ty) {
+   return Id;
+ }
+ 
+-// Find struct/array debuginfo types given a type id.
+-void BTFDebug::setTypeFromId(uint32_t TypeId, BTFTypeStruct **PrevStructType,
+-                             BTFTypeArray **PrevArrayType) {
+-  for (const auto &StructType : StructTypes) {
+-    if (StructType->getId() == TypeId) {
+-      *PrevStructType = StructType;
+-      return;
+-    }
+-  }
+-  for (const auto &ArrayType : ArrayTypes) {
+-    if (ArrayType->getId() == TypeId) {
+-      *PrevArrayType = ArrayType;
+-      return;
+-    }
+-  }
+-}
+-
+ /// Generate a struct member offset relocation.
+ void BTFDebug::generateOffsetReloc(const MachineInstr *MI,
+                                    const MCSymbol *ORSym, DIType *RootTy,
+                                    StringRef AccessPattern) {
+-  BTFTypeStruct *PrevStructType = nullptr;
+-  BTFTypeArray *PrevArrayType = nullptr;
+   unsigned RootId = populateStructType(RootTy);
+-  setTypeFromId(RootId, &PrevStructType, &PrevArrayType);
+-  unsigned RootTySize = PrevStructType->getStructSize();
+-  StringRef IndexPattern = AccessPattern.substr(AccessPattern.find_first_of(':') + 1);
++  size_t FirstDollar = AccessPattern.find_first_of('$');
++  size_t FirstColon = AccessPattern.find_first_of(':');
++  StringRef IndexPattern = AccessPattern.substr(FirstDollar + 1);
++  StringRef OffsetStr = AccessPattern.substr(FirstColon + 1,
++      FirstDollar - FirstColon);
+ 
+   BTFOffsetReloc OffsetReloc;
+   OffsetReloc.Label = ORSym;
+-  OffsetReloc.OffsetNameOff = addString(IndexPattern.drop_back());
++  OffsetReloc.OffsetNameOff = addString(IndexPattern);
+   OffsetReloc.TypeID = RootId;
+-
+-  uint32_t Start = 0, End = 0, Offset = 0;
+-  bool FirstAccess = true;
+-  for (auto C : IndexPattern) {
+-    if (C != ':') {
+-      End++;
+-    } else {
+-      std::string SubStr = IndexPattern.substr(Start, End - Start);
+-      int Loc = std::stoi(SubStr);
+-
+-      if (FirstAccess) {
+-        Offset = Loc * RootTySize;
+-        FirstAccess = false;
+-      } else if (PrevStructType) {
+-        uint32_t MemberOffset, MemberTypeId;
+-        PrevStructType->getMemberInfo(Loc, MemberOffset, MemberTypeId);
+-
+-        Offset += MemberOffset >> 3;
+-        PrevStructType = nullptr;
+-        setTypeFromId(MemberTypeId, &PrevStructType, &PrevArrayType);
+-      } else if (PrevArrayType) {
+-        uint32_t LocOffset, ElementTypeId;
+-        PrevArrayType->getLocInfo(Loc, LocOffset, ElementTypeId);
+-
+-        Offset += LocOffset;
+-        PrevArrayType = nullptr;
+-        setTypeFromId(ElementTypeId, &PrevStructType, &PrevArrayType);
+-      } else {
+-        llvm_unreachable("Internal Error: BTF offset relocation type traversal error");
+-      }
+-
+-      Start = End + 1;
+-      End = Start;
+-    }
+-  }
+-  AccessOffsets[AccessPattern.str()] = Offset;
++  AccessOffsets[AccessPattern.str()] = std::stoi(OffsetStr);
+   OffsetRelocTable[SecNameOff].push_back(OffsetReloc);
+ }
+ 
+diff --git a/llvm/lib/Target/BPF/BTFDebug.h b/llvm/lib/Target/BPF/BTFDebug.h
+index e210d18..a79527d 100644
+--- a/llvm/lib/Target/BPF/BTFDebug.h
++++ b/llvm/lib/Target/BPF/BTFDebug.h
+@@ -104,18 +104,13 @@ public:
+ 
+ /// Handle array type.
+ class BTFTypeArray : public BTFTypeBase {
+-  const DIType *ElemTyNoQual;
+-  uint32_t ElemSize;
+   struct BTF::BTFArray ArrayInfo;
+-  uint32_t ElemTypeNoQual;
+ 
+ public:
+-  BTFTypeArray(const DIType *Ty, uint32_t ElemTypeId,
+-               uint32_t ElemSize, uint32_t NumElems);
++  BTFTypeArray(uint32_t ElemTypeId, uint32_t NumElems);
+   uint32_t getSize() { return BTFTypeBase::getSize() + BTF::BTFArraySize; }
+   void completeType(BTFDebug &BDebug);
+   void emitType(MCStreamer &OS);
+-  void getLocInfo(uint32_t Loc, uint32_t &LocOffset, uint32_t &ElementTypeId);
+ };
+ 
+ /// Handle struct/union type.
+@@ -123,7 +118,6 @@ class BTFTypeStruct : public BTFTypeBase {
+   const DICompositeType *STy;
+   bool HasBitField;
+   std::vector<struct BTF::BTFMember> Members;
+-  std::vector<uint32_t> MemberTypeNoQual;
+ 
+ public:
+   BTFTypeStruct(const DICompositeType *STy, bool IsStruct, bool HasBitField,
+@@ -134,8 +128,6 @@ public:
+   void completeType(BTFDebug &BDebug);
+   void emitType(MCStreamer &OS);
+   std::string getName();
+-  void getMemberInfo(uint32_t Loc, uint32_t &Offset, uint32_t &MemberType);
+-  uint32_t getStructSize();
+ };
+ 
+ /// Handle function pointer.
+@@ -262,7 +254,6 @@ class BTFDebug : public DebugHandlerBase {
+   StringMap<std::vector<std::string>> FileContent;
+   std::map<std::string, std::unique_ptr<BTFKindDataSec>> DataSecEntries;
+   std::vector<BTFTypeStruct *> StructTypes;
+-  std::vector<BTFTypeArray *> ArrayTypes;
+   std::map<std::string, int64_t> AccessOffsets;
+   std::map<StringRef, std::pair<bool, std::vector<BTFTypeDerived *>>>
+       FixupDerivedTypes;
+@@ -312,10 +303,6 @@ class BTFDebug : public DebugHandlerBase {
+   void generateOffsetReloc(const MachineInstr *MI, const MCSymbol *ORSym,
+                            DIType *RootTy, StringRef AccessPattern);
+ 
+-  /// Set the to-be-traversed Struct/Array Type based on TypeId.
+-  void setTypeFromId(uint32_t TypeId, BTFTypeStruct **PrevStructType,
+-                     BTFTypeArray **PrevArrayType);
+-
+   /// Populating unprocessed struct type.
+   unsigned populateStructType(const DIType *Ty);
+ 
+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
+new file mode 100644
+index 0000000..9e291cd
+--- /dev/null
++++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-array-1.ll
+@@ -0,0 +1,124 @@
++; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
++; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
++; Source code:
++;   struct v1 {int a; int b;};
++;   typedef struct v1 __v1;
++;   typedef __v1 arr[4];
++;   struct v3 { char c; int d[100]; };
++;   #define _(x) (__builtin_preserve_access_index(x))
++;   #define cast_to_arr(x) ((arr *)(x))
++;   int get_value(const int *arg);
++;   int test(struct v3 *arg) {
++;     return get_value(_(&cast_to_arr(&arg->d[0])[0][2].b));
++;   }
++; Compilation flag:
++;   clang -target bpf -O2 -g -S -emit-llvm test.c
++
++%struct.v3 = type { i8, [100 x i32] }
++%struct.v1 = type { i32, i32 }
++
++; Function Attrs: nounwind
++define dso_local i32 @test(%struct.v3* %arg) local_unnamed_addr #0 !dbg !22 {
++entry:
++  call void @llvm.dbg.value(metadata %struct.v3* %arg, metadata !32, metadata !DIExpression()), !dbg !33
++  %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
++  %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
++  %2 = bitcast i32* %1 to [4 x %struct.v1]*, !dbg !34
++  %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
++  %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
++  %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
++  %call = tail call i32 @get_value(i32* %5) #4, !dbg !35
++  ret i32 %call, !dbg !36
++}
++
++; CHECK:              r2 = 4
++; CHECK:              r1 += r2
++; CHECK:              r2 = 20
++; CHECK:              r1 += r2
++; CHECK:              call get_value
++
++; CHECK:              .long   1                       # BTF_KIND_STRUCT(id = [[TID1:[0-9]+]])
++; CHECK:              .long   100                     # BTF_KIND_STRUCT(id = [[TID2:[0-9]+]])
++
++; CHECK:              .ascii  "v3"                    # string offset=1
++; CHECK:              .ascii  ".text"                 # string offset=46
++; CHECK:              .ascii  "0:1:0"                 # string offset=52
++; CHECK:              .ascii  "2:1"                   # string offset=107
++
++; CHECK:              .long   12                      # OffsetReloc
++; CHECK-NEXT:         .long   46                      # Offset reloc section string offset=46
++; CHECK-NEXT:         .long   2
++; CHECK-NEXT:         .long   .Ltmp{{[0-9]+}}
++; CHECK-NEXT:         .long   [[TID1]]
++; CHECK-NEXT:         .long   52
++; CHECK-NEXT:         .long   .Ltmp{{[0-9]+}}
++; CHECK-NEXT:         .long   [[TID2]]
++; CHECK-NEXT:         .long   107
++
++declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
++
++; Function Attrs: nounwind readnone
++declare [100 x i32]* @llvm.preserve.struct.access.index.p0a100i32.p0s_struct.v3s(%struct.v3*, i32, i32) #2
++
++; Function Attrs: nounwind readnone
++declare i32* @llvm.preserve.array.access.index.p0i32.p0a100i32([100 x i32]*, i32, i32) #2
++
++; Function Attrs: nounwind readnone
++declare [4 x %struct.v1]* @llvm.preserve.array.access.index.p0a4s_struct.v1s.p0a4s_struct.v1s([4 x %struct.v1]*, i32, i32) #2
++
++; Function Attrs: nounwind readnone
++declare %struct.v1* @llvm.preserve.array.access.index.p0s_struct.v1s.p0a4s_struct.v1s([4 x %struct.v1]*, i32, i32) #2
++
++; Function Attrs: nounwind readnone
++declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v1s(%struct.v1*, i32, i32) #2
++
++; Function Attrs: nounwind readnone speculatable willreturn
++declare void @llvm.dbg.value(metadata, metadata, metadata) #3
++
++attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
++attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
++attributes #2 = { nounwind readnone }
++attributes #3 = { nounwind readnone speculatable willreturn }
++attributes #4 = { nounwind }
++
++!llvm.dbg.cu = !{!0}
++!llvm.module.flags = !{!18, !19, !20}
++!llvm.ident = !{!21}
++
++!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)
++!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
++!2 = !{}
++!3 = !{!4, !15, !5}
++!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64)
++!5 = !DIDerivedType(tag: DW_TAG_typedef, name: "arr", file: !1, line: 3, baseType: !6)
++!6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 256, elements: !13)
++!7 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v1", file: !1, line: 2, baseType: !8)
++!8 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v1", file: !1, line: 1, size: 64, elements: !9)
++!9 = !{!10, !12}
++!10 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !8, file: !1, line: 1, baseType: !11, size: 32)
++!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
++!12 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !8, file: !1, line: 1, baseType: !11, size: 32, offset: 32)
++!13 = !{!14}
++!14 = !DISubrange(count: 4)
++!15 = !DICompositeType(tag: DW_TAG_array_type, baseType: !11, size: 3200, elements: !16)
++!16 = !{!17}
++!17 = !DISubrange(count: 100)
++!18 = !{i32 2, !"Dwarf Version", i32 4}
++!19 = !{i32 2, !"Debug Info Version", i32 3}
++!20 = !{i32 1, !"wchar_size", i32 4}
++!21 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
++!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)
++!23 = !DISubroutineType(types: !24)
++!24 = !{!11, !25}
++!25 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !26, size: 64)
++!26 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !1, line: 4, size: 3232, elements: !27)
++!27 = !{!28, !30}
++!28 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !26, file: !1, line: 4, baseType: !29, size: 8)
++!29 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
++!30 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !26, file: !1, line: 4, baseType: !15, size: 3200, offset: 32)
++!31 = !{!32}
++!32 = !DILocalVariable(name: "arg", arg: 1, scope: !22, file: !1, line: 8, type: !25)
++!33 = !DILocation(line: 0, scope: !22)
++!34 = !DILocation(line: 9, column: 20, scope: !22)
++!35 = !DILocation(line: 9, column: 10, scope: !22)
++!36 = !DILocation(line: 9, column: 3, scope: !22)
+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
+new file mode 100644
+index 0000000..7903179
+--- /dev/null
++++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-array-2.ll
+@@ -0,0 +1,131 @@
++; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
++; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
++; Source code:
++;   struct v1 {int a; int b;};
++;   typedef struct v1 __v1;
++;   typedef __v1 arr[4][4];
++;   struct v3 { char c; int d[100]; };
++;   #define _(x) (__builtin_preserve_access_index(x))
++;   #define cast_to_arr(x) ((arr *)(x))
++;   int get_value(const int *arg);
++;   int test(struct v3 *arg) {
++;     return get_value(_(&cast_to_arr(&arg->d[0])[0][2][3].b));
++;   }
++; Compilation flag:
++;   clang -target bpf -O2 -g -S -emit-llvm test.c
++
++%struct.v3 = type { i8, [100 x i32] }
++%struct.v1 = type { i32, i32 }
++
++; Function Attrs: nounwind
++define dso_local i32 @test(%struct.v3* %arg) local_unnamed_addr #0 !dbg !24 {
++entry:
++  call void @llvm.dbg.value(metadata %struct.v3* %arg, metadata !34, metadata !DIExpression()), !dbg !35
++  %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
++  %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
++  %2 = bitcast i32* %1 to [4 x [4 x %struct.v1]]*, !dbg !36
++  %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
++  %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
++  %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
++  %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
++  %call = tail call i32 @get_value(i32* %6) #4, !dbg !37
++  ret i32 %call, !dbg !38
++}
++
++; CHECK:              r2 = 4
++; CHECK:              r1 += r2
++; CHECK:              r2 = 92
++; CHECK:              r1 += r2
++; CHECK:              call get_value
++
++; CHECK:              .long   1                       # BTF_KIND_STRUCT(id = [[TID1:[0-9]+]])
++; CHECK:              .long   100                     # BTF_KIND_STRUCT(id = [[TID2:[0-9]+]])
++
++; CHECK:              .ascii  "v3"                    # string offset=1
++; CHECK:              .ascii  ".text"                 # string offset=46
++; CHECK:              .ascii  "0:1:0"                 # string offset=52
++; CHECK:              .ascii  "v1"                    # string offset=100
++; CHECK:              .ascii  "11:1"                  # string offset=107
++
++; CHECK:              .long   12                      # OffsetReloc
++; CHECK-NEXT:         .long   46                      # Offset reloc section string offset=46
++; CHECK-NEXT:         .long   2
++; CHECK-NEXT:         .long   .Ltmp{{[0-9]+}}
++; CHECK-NEXT:         .long   [[TID1]]
++; CHECK-NEXT:         .long   52
++; CHECK-NEXT:         .long   .Ltmp{{[0-9]+}}
++; CHECK-NEXT:         .long   [[TID2]]
++; CHECK-NEXT:         .long   107
++
++declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
++
++; Function Attrs: nounwind readnone
++declare [100 x i32]* @llvm.preserve.struct.access.index.p0a100i32.p0s_struct.v3s(%struct.v3*, i32, i32) #2
++
++; Function Attrs: nounwind readnone
++declare i32* @llvm.preserve.array.access.index.p0i32.p0a100i32([100 x i32]*, i32, i32) #2
++
++; Function Attrs: nounwind readnone
++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
++
++; Function Attrs: nounwind readnone
++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
++
++; Function Attrs: nounwind readnone
++declare %struct.v1* @llvm.preserve.array.access.index.p0s_struct.v1s.p0a4s_struct.v1s([4 x %struct.v1]*, i32, i32) #2
++
++; Function Attrs: nounwind readnone
++declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v1s(%struct.v1*, i32, i32) #2
++
++; Function Attrs: nounwind readnone speculatable willreturn
++declare void @llvm.dbg.value(metadata, metadata, metadata) #3
++
++attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
++attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
++attributes #2 = { nounwind readnone }
++attributes #3 = { nounwind readnone speculatable willreturn }
++attributes #4 = { nounwind }
++
++!llvm.dbg.cu = !{!0}
++!llvm.module.flags = !{!20, !21, !22}
++!llvm.ident = !{!23}
++
++!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)
++!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
++!2 = !{}
++!3 = !{!4, !15, !5, !18}
++!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64)
++!5 = !DIDerivedType(tag: DW_TAG_typedef, name: "arr", file: !1, line: 3, baseType: !6)
++!6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 1024, elements: !13)
++!7 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v1", file: !1, line: 2, baseType: !8)
++!8 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v1", file: !1, line: 1, size: 64, elements: !9)
++!9 = !{!10, !12}
++!10 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !8, file: !1, line: 1, baseType: !11, size: 32)
++!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
++!12 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !8, file: !1, line: 1, baseType: !11, size: 32, offset: 32)
++!13 = !{!14, !14}
++!14 = !DISubrange(count: 4)
++!15 = !DICompositeType(tag: DW_TAG_array_type, baseType: !11, size: 3200, elements: !16)
++!16 = !{!17}
++!17 = !DISubrange(count: 100)
++!18 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 256, elements: !19)
++!19 = !{!14}
++!20 = !{i32 2, !"Dwarf Version", i32 4}
++!21 = !{i32 2, !"Debug Info Version", i32 3}
++!22 = !{i32 1, !"wchar_size", i32 4}
++!23 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
++!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)
++!25 = !DISubroutineType(types: !26)
++!26 = !{!11, !27}
++!27 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !28, size: 64)
++!28 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !1, line: 4, size: 3232, elements: !29)
++!29 = !{!30, !32}
++!30 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !28, file: !1, line: 4, baseType: !31, size: 8)
++!31 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
++!32 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !28, file: !1, line: 4, baseType: !15, size: 3200, offset: 32)
++!33 = !{!34}
++!34 = !DILocalVariable(name: "arg", arg: 1, scope: !24, file: !1, line: 8, type: !27)
++!35 = !DILocation(line: 0, scope: !24)
++!36 = !DILocation(line: 9, column: 20, scope: !24)
++!37 = !DILocation(line: 9, column: 10, scope: !24)
++!38 = !DILocation(line: 9, column: 3, scope: !24)
+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
+new file mode 100644
+index 0000000..a97c6a0
+--- /dev/null
++++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-1.ll
+@@ -0,0 +1,112 @@
++; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
++; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
++; Source code:
++;   struct v1 { int a; int b; };
++;   struct v2 { int c; int d; };
++;   struct v3 { char c; struct v2 d; };
++;   #define _(x) (__builtin_preserve_access_index(x))
++;   #define cast_to_v1(x) ((struct v1 *)(x))
++;   int get_value(const int *arg);
++;   int test(struct v3 *arg) {
++;     return get_value(_(&cast_to_v1(&arg->d)->b));
++;   }
++; Compilation flag:
++;   clang -target bpf -O2 -g -S -emit-llvm test.c
++
++%struct.v3 = type { i8, %struct.v2 }
++%struct.v2 = type { i32, i32 }
++%struct.v1 = type { i32, i32 }
++
++; Function Attrs: nounwind
++define dso_local i32 @test(%struct.v3* %arg) local_unnamed_addr #0 !dbg !14 {
++entry:
++  call void @llvm.dbg.value(metadata %struct.v3* %arg, metadata !28, metadata !DIExpression()), !dbg !29
++  %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
++  %1 = bitcast %struct.v2* %0 to %struct.v1*, !dbg !30
++  %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
++  %call = tail call i32 @get_value(i32* %2) #4, !dbg !31
++  ret i32 %call, !dbg !32
++}
++
++; CHECK:              r2 = 4
++; CHECK:              r1 += r2
++; CHECK:              r2 = 4
++; CHECK:              r1 += r2
++; CHECK:              call get_value
++
++; CHECK:             .long   1                       # BTF_KIND_STRUCT(id = [[V3_TID:[0-9]+]])
++; CHECK:             .long   81                      # BTF_KIND_STRUCT(id = [[V1_TID:[0-9]+]])
++
++; CHECK:             .ascii  "v3"                    # string offset=1
++; CHECK-NEXT:        .byte   0
++; CHECK:             .ascii  ".text"                 # string offset=[[SEC_STR:[0-9]+]]
++; CHECK-NEXT:        .byte   0
++; CHECK:             .ascii  "0:1"                   # string offset=[[ACCESS_STR:[0-9]+]]
++; CHECK-NEXT:        .byte   0
++; CHECK:             .ascii  "v1"                    # string offset=81
++; CHECK-NEXT:        .byte   0
++
++; CHECK:             .long   12                      # OffsetReloc
++; CHECK-NEXT:        .long   [[SEC_STR]]             # Offset reloc section string offset=[[SEC_STR]]
++; CHECK-NEXT:        .long   2
++; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
++; CHECK-NEXT:        .long   [[V3_TID]]
++; CHECK-NEXT:        .long   [[ACCESS_STR]]
++; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
++; CHECK-NEXT:        .long   [[V1_TID]]
++; CHECK-NEXT:        .long   [[ACCESS_STR]]
++
++declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
++
++; Function Attrs: nounwind readnone
++declare %struct.v2* @llvm.preserve.struct.access.index.p0s_struct.v2s.p0s_struct.v3s(%struct.v3*, i32, i32) #2
++
++; Function Attrs: nounwind readnone
++declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v1s(%struct.v1*, i32, i32) #2
++
++; Function Attrs: nounwind readnone speculatable willreturn
++declare void @llvm.dbg.value(metadata, metadata, metadata) #3
++
++attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
++attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
++attributes #2 = { nounwind readnone }
++attributes #3 = { nounwind readnone speculatable willreturn }
++attributes #4 = { nounwind }
++
++!llvm.dbg.cu = !{!0}
++!llvm.module.flags = !{!10, !11, !12}
++!llvm.ident = !{!13}
++
++!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)
++!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
++!2 = !{}
++!3 = !{!4}
++!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64)
++!5 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v1", file: !1, line: 1, size: 64, elements: !6)
++!6 = !{!7, !9}
++!7 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !5, file: !1, line: 1, baseType: !8, size: 32)
++!8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
++!9 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !5, file: !1, line: 1, baseType: !8, size: 32, offset: 32)
++!10 = !{i32 2, !"Dwarf Version", i32 4}
++!11 = !{i32 2, !"Debug Info Version", i32 3}
++!12 = !{i32 1, !"wchar_size", i32 4}
++!13 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
++!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)
++!15 = !DISubroutineType(types: !16)
++!16 = !{!8, !17}
++!17 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !18, size: 64)
++!18 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !1, line: 3, size: 96, elements: !19)
++!19 = !{!20, !22}
++!20 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !18, file: !1, line: 3, baseType: !21, size: 8)
++!21 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
++!22 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !18, file: !1, line: 3, baseType: !23, size: 64, offset: 32)
++!23 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v2", file: !1, line: 2, size: 64, elements: !24)
++!24 = !{!25, !26}
++!25 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !23, file: !1, line: 2, baseType: !8, size: 32)
++!26 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !23, file: !1, line: 2, baseType: !8, size: 32, offset: 32)
++!27 = !{!28}
++!28 = !DILocalVariable(name: "arg", arg: 1, scope: !14, file: !1, line: 7, type: !17)
++!29 = !DILocation(line: 0, scope: !14)
++!30 = !DILocation(line: 8, column: 20, scope: !14)
++!31 = !DILocation(line: 8, column: 10, scope: !14)
++!32 = !DILocation(line: 8, column: 3, scope: !14)
+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
+new file mode 100644
+index 0000000..f65b3f3
+--- /dev/null
++++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-2.ll
+@@ -0,0 +1,117 @@
++; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
++; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
++; Source code:
++;   struct v1 { int a; int b; };
++;   typedef struct v1 __v1;
++;   struct v2 { int c; int d; };
++;   typedef struct v2 __v2;
++;   struct v3 { char c; volatile const __v2 d; };
++;   typedef struct v3 __v3;
++;   #define _(x) (__builtin_preserve_access_index(x))
++;   #define cast_to_v1(x) ((__v1 *)(x))
++;   int get_value(const int *arg);
++;   int test(__v3 *arg) {
++;     return get_value(_(&cast_to_v1(&arg->d)->b));
++;   }
++; Compilation flag:
++;   clang -target bpf -O2 -g -S -emit-llvm test.c
++
++%struct.v3 = type { i8, %struct.v2 }
++%struct.v2 = type { i32, i32 }
++%struct.v1 = type { i32, i32 }
++
++; Function Attrs: nounwind
++define dso_local i32 @test(%struct.v3* %arg) local_unnamed_addr #0 !dbg !15 {
++entry:
++  call void @llvm.dbg.value(metadata %struct.v3* %arg, metadata !33, metadata !DIExpression()), !dbg !34
++  %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
++  %1 = bitcast %struct.v2* %0 to %struct.v1*, !dbg !35
++  %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
++  %call = tail call i32 @get_value(i32* %2) #4, !dbg !36
++  ret i32 %call, !dbg !37
++}
++
++; CHECK:             r2 = 4
++; CHECK:             r1 += r2
++; CHECK:             r2 = 4
++; CHECK:             r1 += r2
++; CHECK:             call get_value
++
++; CHECK:             .long   6                       # BTF_KIND_STRUCT(id = [[TID1:[0-9]+]])
++; CHECK:             .long   91                      # BTF_KIND_STRUCT(id = [[TID2:[0-9]+]])
++
++; CHECK:             .ascii  "v3"                    # string offset=6
++; CHECK:             .ascii  ".text"                 # string offset=39
++; CHECK:             .ascii  "0:1"                   # string offset=45
++; CHECK:             .ascii  "v1"                    # string offset=91
++
++
++; CHECK:             .long   12                      # OffsetReloc
++; CHECK-NEXT:        .long   39                      # Offset reloc section string offset=39
++; CHECK-NEXT:        .long   2
++; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
++; CHECK-NEXT:        .long   [[TID1]]
++; CHECK-NEXT:        .long   45
++; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
++; CHECK-NEXT:        .long   [[TID2]]
++; CHECK-NEXT:        .long   45
++
++declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
++
++; Function Attrs: nounwind readnone
++declare %struct.v2* @llvm.preserve.struct.access.index.p0s_struct.v2s.p0s_struct.v3s(%struct.v3*, i32, i32) #2
++
++; Function Attrs: nounwind readnone
++declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v1s(%struct.v1*, i32, i32) #2
++
++; Function Attrs: nounwind readnone speculatable willreturn
++declare void @llvm.dbg.value(metadata, metadata, metadata) #3
++
++attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
++attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
++attributes #2 = { nounwind readnone }
++attributes #3 = { nounwind readnone speculatable willreturn }
++attributes #4 = { nounwind }
++
++!llvm.dbg.cu = !{!0}
++!llvm.module.flags = !{!11, !12, !13}
++!llvm.ident = !{!14}
++
++!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None)
++!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
++!2 = !{}
++!3 = !{!4}
++!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64)
++!5 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v1", file: !1, line: 2, baseType: !6)
++!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v1", file: !1, line: 1, size: 64, elements: !7)
++!7 = !{!8, !10}
++!8 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !6, file: !1, line: 1, baseType: !9, size: 32)
++!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
++!10 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !6, file: !1, line: 1, baseType: !9, size: 32, offset: 32)
++!11 = !{i32 2, !"Dwarf Version", i32 4}
++!12 = !{i32 2, !"Debug Info Version", i32 3}
++!13 = !{i32 1, !"wchar_size", i32 4}
++!14 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
++!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)
++!16 = !DISubroutineType(types: !17)
++!17 = !{!9, !18}
++!18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !19, size: 64)
++!19 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v3", file: !1, line: 6, baseType: !20)
++!20 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !1, line: 5, size: 96, elements: !21)
++!21 = !{!22, !24}
++!22 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !20, file: !1, line: 5, baseType: !23, size: 8)
++!23 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
++!24 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !20, file: !1, line: 5, baseType: !25, size: 64, offset: 32)
++!25 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !26)
++!26 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !27)
++!27 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v2", file: !1, line: 4, baseType: !28)
++!28 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v2", file: !1, line: 3, size: 64, elements: !29)
++!29 = !{!30, !31}
++!30 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !28, file: !1, line: 3, baseType: !9, size: 32)
++!31 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !28, file: !1, line: 3, baseType: !9, size: 32, offset: 32)
++!32 = !{!33}
++!33 = !DILocalVariable(name: "arg", arg: 1, scope: !15, file: !1, line: 10, type: !18)
++!34 = !DILocation(line: 0, scope: !15)
++!35 = !DILocation(line: 11, column: 20, scope: !15)
++!36 = !DILocation(line: 11, column: 10, scope: !15)
++!37 = !DILocation(line: 11, column: 3, scope: !15)
+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
+new file mode 100644
+index 0000000..ed78b84
+--- /dev/null
++++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-3.ll
+@@ -0,0 +1,116 @@
++; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
++; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
++; Source code:
++;   struct v1 { int a; int b; };
++;   typedef struct v1 __v1;
++;   typedef int __int;
++;   struct v3 { char c; __int d[40]; };
++;   typedef struct v3 __v3;
++;   #define _(x) (__builtin_preserve_access_index(x))
++;   #define cast_to_v1(x) ((__v1 *)(x))
++;   int get_value(const int *arg);
++;   int test(__v3 *arg) {
++;     return get_value(_(&cast_to_v1(&arg->d[4])->b));
++;   }
++; Compilation flag:
++;   clang -target bpf -O2 -g -S -emit-llvm test.c
++
++%struct.v3 = type { i8, [40 x i32] }
++%struct.v1 = type { i32, i32 }
++
++; Function Attrs: nounwind
++define dso_local i32 @test(%struct.v3* %arg) local_unnamed_addr #0 !dbg !19 {
++entry:
++  call void @llvm.dbg.value(metadata %struct.v3* %arg, metadata !30, metadata !DIExpression()), !dbg !31
++  %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
++  %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
++  %2 = bitcast i32* %1 to %struct.v1*, !dbg !32
++  %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
++  %call = tail call i32 @get_value(i32* %3) #4, !dbg !33
++  ret i32 %call, !dbg !34
++}
++
++; CHECK:             r2 = 20
++; CHECK:             r1 += r2
++; CHECK:             r2 = 4
++; CHECK:             r1 += r2
++; CHECK:             call get_value
++
++; CHECK:             .long   6                       # BTF_KIND_STRUCT(id = [[TID1:[0-9]+]])
++; CHECK:             .long   111                     # BTF_KIND_STRUCT(id = [[TID2:[0-9]+]])
++
++; CHECK:             .ascii  "v3"                    # string offset=6
++; CHECK:             .ascii  ".text"                 # string offset=57
++; CHECK:             .ascii  "0:1:4"                 # string offset=63
++; CHECK:             .ascii  "v1"                    # string offset=111
++; CHECK:             .ascii  "0:1"                   # string offset=118
++
++; CHECK:             .long   12                      # OffsetReloc
++; CHECK-NEXT:        .long   57                      # Offset reloc section string offset=57
++; CHECK-NEXT:        .long   2
++; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
++; CHECK-NEXT:        .long   [[TID1]]
++; CHECK-NEXT:        .long   63
++; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
++; CHECK-NEXT:        .long   [[TID2]]
++; CHECK-NEXT:        .long   118
++
++declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
++
++; Function Attrs: nounwind readnone
++declare [40 x i32]* @llvm.preserve.struct.access.index.p0a40i32.p0s_struct.v3s(%struct.v3*, i32, i32) #2
++
++; Function Attrs: nounwind readnone
++declare i32* @llvm.preserve.array.access.index.p0i32.p0a40i32([40 x i32]*, i32, i32) #2
++
++; Function Attrs: nounwind readnone
++declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v1s(%struct.v1*, i32, i32) #2
++
++; Function Attrs: nounwind readnone speculatable willreturn
++declare void @llvm.dbg.value(metadata, metadata, metadata) #3
++
++attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
++attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
++attributes #2 = { nounwind readnone }
++attributes #3 = { nounwind readnone speculatable willreturn }
++attributes #4 = { nounwind }
++
++!llvm.dbg.cu = !{!0}
++!llvm.module.flags = !{!15, !16, !17}
++!llvm.ident = !{!18}
++
++!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)
++!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
++!2 = !{}
++!3 = !{!4, !11}
++!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64)
++!5 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v1", file: !1, line: 2, baseType: !6)
++!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v1", file: !1, line: 1, size: 64, elements: !7)
++!7 = !{!8, !10}
++!8 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !6, file: !1, line: 1, baseType: !9, size: 32)
++!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
++!10 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !6, file: !1, line: 1, baseType: !9, size: 32, offset: 32)
++!11 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 1280, elements: !13)
++!12 = !DIDerivedType(tag: DW_TAG_typedef, name: "__int", file: !1, line: 3, baseType: !9)
++!13 = !{!14}
++!14 = !DISubrange(count: 40)
++!15 = !{i32 2, !"Dwarf Version", i32 4}
++!16 = !{i32 2, !"Debug Info Version", i32 3}
++!17 = !{i32 1, !"wchar_size", i32 4}
++!18 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
++!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)
++!20 = !DISubroutineType(types: !21)
++!21 = !{!9, !22}
++!22 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !23, size: 64)
++!23 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v3", file: !1, line: 5, baseType: !24)
++!24 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !1, line: 4, size: 1312, elements: !25)
++!25 = !{!26, !28}
++!26 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !24, file: !1, line: 4, baseType: !27, size: 8)
++!27 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
++!28 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !24, file: !1, line: 4, baseType: !11, size: 1280, offset: 32)
++!29 = !{!30}
++!30 = !DILocalVariable(name: "arg", arg: 1, scope: !19, file: !1, line: 9, type: !22)
++!31 = !DILocation(line: 0, scope: !19)
++!32 = !DILocation(line: 10, column: 20, scope: !19)
++!33 = !DILocation(line: 10, column: 10, scope: !19)
++!34 = !DILocation(line: 10, column: 3, scope: !19)
+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
+new file mode 100644
+index 0000000..1e8f99c
+--- /dev/null
++++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-union-1.ll
+@@ -0,0 +1,117 @@
++; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
++; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
++; Source code:
++;   union v1 { int a; int b; };
++;   typedef union v1 __v1;
++;   union v2 { int c; int d; };
++;   typedef union v2 __v2;
++;   union v3 { char c; volatile const __v2 d; };
++;   typedef union v3 __v3;
++;   #define _(x) (__builtin_preserve_access_index(x))
++;   #define cast_to_v1(x) ((__v1 *)(x))
++;   int get_value(const int *arg);
++;   int test(__v3 *arg) {
++;     return get_value(_(&cast_to_v1(&arg->d)->b));
++;   }
++; Compilation flag:
++;   clang -target bpf -O2 -g -S -emit-llvm test.c
++
++%union.v3 = type { %union.v2 }
++%union.v2 = type { i32 }
++%union.v1 = type { i32 }
++
++; Function Attrs: nounwind
++define dso_local i32 @test(%union.v3* %arg) local_unnamed_addr #0 !dbg !15 {
++entry:
++  call void @llvm.dbg.value(metadata %union.v3* %arg, metadata !33, metadata !DIExpression()), !dbg !34
++  %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
++  %1 = bitcast %union.v3* %0 to %union.v1*, !dbg !35
++  %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
++  %b = getelementptr inbounds %union.v1, %union.v1* %2, i64 0, i32 0, !dbg !35
++  %call = tail call i32 @get_value(i32* %b) #4, !dbg !36
++  ret i32 %call, !dbg !37
++}
++
++; CHECK:             r2 = 0
++; CHECK:             r1 += r2
++; CHECK:             r2 = 0
++; CHECK:             r1 += r2
++; CHECK:             call get_value
++
++; CHECK:             .long   6                       # BTF_KIND_UNION(id = [[TID1:[0-9]+]])
++; CHECK:             .long   91                      # BTF_KIND_UNION(id = [[TID2:[0-9]+]])
++
++; CHECK:             .ascii  "v3"                    # string offset=6
++; CHECK:             .ascii  ".text"                 # string offset=39
++; CHECK:             .ascii  "0:1"                   # string offset=45
++; CHECK:             .ascii  "v1"                    # string offset=91
++
++; CHECK:             .long   12                      # OffsetReloc
++; CHECK-NEXT:        .long   39                      # Offset reloc section string offset=39
++; CHECK-NEXT:        .long   2
++; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
++; CHECK-NEXT:        .long   [[TID1]]
++; CHECK-NEXT:        .long   45
++; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
++; CHECK-NEXT:        .long   [[TID2]]
++; CHECK-NEXT:        .long   45
++
++declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
++
++; Function Attrs: nounwind readnone
++declare %union.v3* @llvm.preserve.union.access.index.p0s_union.v3s.p0s_union.v3s(%union.v3*, i32) #2
++
++; Function Attrs: nounwind readnone
++declare %union.v1* @llvm.preserve.union.access.index.p0s_union.v1s.p0s_union.v1s(%union.v1*, i32) #2
++
++; Function Attrs: nounwind readnone speculatable willreturn
++declare void @llvm.dbg.value(metadata, metadata, metadata) #3
++
++attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
++attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
++attributes #2 = { nounwind readnone }
++attributes #3 = { nounwind readnone speculatable willreturn }
++attributes #4 = { nounwind }
++
++!llvm.dbg.cu = !{!0}
++!llvm.module.flags = !{!11, !12, !13}
++!llvm.ident = !{!14}
++
++!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None)
++!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
++!2 = !{}
++!3 = !{!4}
++!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64)
++!5 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v1", file: !1, line: 2, baseType: !6)
++!6 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "v1", file: !1, line: 1, size: 32, elements: !7)
++!7 = !{!8, !10}
++!8 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !6, file: !1, line: 1, baseType: !9, size: 32)
++!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
++!10 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !6, file: !1, line: 1, baseType: !9, size: 32)
++!11 = !{i32 2, !"Dwarf Version", i32 4}
++!12 = !{i32 2, !"Debug Info Version", i32 3}
++!13 = !{i32 1, !"wchar_size", i32 4}
++!14 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
++!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)
++!16 = !DISubroutineType(types: !17)
++!17 = !{!9, !18}
++!18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !19, size: 64)
++!19 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v3", file: !1, line: 6, baseType: !20)
++!20 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "v3", file: !1, line: 5, size: 32, elements: !21)
++!21 = !{!22, !24}
++!22 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !20, file: !1, line: 5, baseType: !23, size: 8)
++!23 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
++!24 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !20, file: !1, line: 5, baseType: !25, size: 32)
++!25 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !26)
++!26 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !27)
++!27 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v2", file: !1, line: 4, baseType: !28)
++!28 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "v2", file: !1, line: 3, size: 32, elements: !29)
++!29 = !{!30, !31}
++!30 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !28, file: !1, line: 3, baseType: !9, size: 32)
++!31 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !28, file: !1, line: 3, baseType: !9, size: 32)
++!32 = !{!33}
++!33 = !DILocalVariable(name: "arg", arg: 1, scope: !15, file: !1, line: 10, type: !18)
++!34 = !DILocation(line: 0, scope: !15)
++!35 = !DILocation(line: 11, column: 20, scope: !15)
++!36 = !DILocation(line: 11, column: 10, scope: !15)
++!37 = !DILocation(line: 11, column: 3, scope: !15)
+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
+new file mode 100644
+index 0000000..320b0a9
+--- /dev/null
++++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-union-2.ll
+@@ -0,0 +1,118 @@
++; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
++; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
++; Source code:
++;   union v1 { int a; int b; };
++;   typedef union v1 __v1;
++;   typedef int __int;
++;   union v3 { char c; __int d[40]; };
++;   typedef union v3 __v3;
++;   #define _(x) (__builtin_preserve_access_index(x))
++;   #define cast_to_v1(x) ((__v1 *)(x))
++;   int get_value(const int *arg);
++;   int test(__v3 *arg) {
++;     return get_value(_(&cast_to_v1(&arg->d[4])->b));
++;   }
++; Compilation flag:
++;   clang -target bpf -O2 -g -S -emit-llvm test.c
++
++%union.v3 = type { [40 x i32] }
++%union.v1 = type { i32 }
++
++; Function Attrs: nounwind
++define dso_local i32 @test(%union.v3* %arg) local_unnamed_addr #0 !dbg !19 {
++entry:
++  call void @llvm.dbg.value(metadata %union.v3* %arg, metadata !30, metadata !DIExpression()), !dbg !31
++  %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
++  %d = getelementptr inbounds %union.v3, %union.v3* %0, i64 0, i32 0, !dbg !32
++  %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
++  %2 = bitcast i32* %1 to %union.v1*, !dbg !32
++  %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
++  %b = getelementptr inbounds %union.v1, %union.v1* %3, i64 0, i32 0, !dbg !32
++  %call = tail call i32 @get_value(i32* %b) #4, !dbg !33
++  ret i32 %call, !dbg !34
++}
++
++; CHECK:             r2 = 16
++; CHECK:             r1 += r2
++; CHECK:             r2 = 0
++; CHECK:             r1 += r2
++; CHECK:             call get_value
++
++; CHECK:             .long   6                       # BTF_KIND_UNION(id = [[TID1:[0-9]+]])
++; CHECK:             .long   111                     # BTF_KIND_UNION(id = [[TID2:[0-9]+]])
++
++; CHECK:             .ascii  "v3"                    # string offset=6
++; CHECK:             .ascii  ".text"                 # string offset=57
++; CHECK:             .ascii  "0:1:4"                 # string offset=63
++; CHECK:             .ascii  "v1"                    # string offset=111
++; CHECK:             .ascii  "0:1"                   # string offset=118
++
++; CHECK:             .long   12                      # OffsetReloc
++; CHECK-NEXT:        .long   57                      # Offset reloc section string offset=57
++; CHECK-NEXT:        .long   2
++; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
++; CHECK-NEXT:        .long   [[TID1]]
++; CHECK-NEXT:        .long   63
++; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
++; CHECK-NEXT:        .long   [[TID2]]
++; CHECK-NEXT:        .long   118
++
++declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
++
++; Function Attrs: nounwind readnone
++declare %union.v3* @llvm.preserve.union.access.index.p0s_union.v3s.p0s_union.v3s(%union.v3*, i32) #2
++
++; Function Attrs: nounwind readnone
++declare i32* @llvm.preserve.array.access.index.p0i32.p0a40i32([40 x i32]*, i32, i32) #2
++
++; Function Attrs: nounwind readnone
++declare %union.v1* @llvm.preserve.union.access.index.p0s_union.v1s.p0s_union.v1s(%union.v1*, i32) #2
++
++; Function Attrs: nounwind readnone speculatable willreturn
++declare void @llvm.dbg.value(metadata, metadata, metadata) #3
++
++attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
++attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
++attributes #2 = { nounwind readnone }
++attributes #3 = { nounwind readnone speculatable willreturn }
++attributes #4 = { nounwind }
++
++!llvm.dbg.cu = !{!0}
++!llvm.module.flags = !{!15, !16, !17}
++!llvm.ident = !{!18}
++
++!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)
++!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
++!2 = !{}
++!3 = !{!4, !11}
++!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64)
++!5 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v1", file: !1, line: 2, baseType: !6)
++!6 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "v1", file: !1, line: 1, size: 32, elements: !7)
++!7 = !{!8, !10}
++!8 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !6, file: !1, line: 1, baseType: !9, size: 32)
++!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
++!10 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !6, file: !1, line: 1, baseType: !9, size: 32)
++!11 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 1280, elements: !13)
++!12 = !DIDerivedType(tag: DW_TAG_typedef, name: "__int", file: !1, line: 3, baseType: !9)
++!13 = !{!14}
++!14 = !DISubrange(count: 40)
++!15 = !{i32 2, !"Dwarf Version", i32 4}
++!16 = !{i32 2, !"Debug Info Version", i32 3}
++!17 = !{i32 1, !"wchar_size", i32 4}
++!18 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
++!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)
++!20 = !DISubroutineType(types: !21)
++!21 = !{!9, !22}
++!22 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !23, size: 64)
++!23 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v3", file: !1, line: 5, baseType: !24)
++!24 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "v3", file: !1, line: 4, size: 1280, elements: !25)
++!25 = !{!26, !28}
++!26 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !24, file: !1, line: 4, baseType: !27, size: 8)
++!27 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
++!28 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !24, file: !1, line: 4, baseType: !11, size: 1280)
++!29 = !{!30}
++!30 = !DILocalVariable(name: "arg", arg: 1, scope: !19, file: !1, line: 9, type: !22)
++!31 = !DILocation(line: 0, scope: !19)
++!32 = !DILocation(line: 10, column: 20, scope: !19)
++!33 = !DILocation(line: 10, column: 10, scope: !19)
++!34 = !DILocation(line: 10, column: 3, scope: !19)
+diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-global-1.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-global-1.ll
+new file mode 100644
+index 0000000..296e2d4
+--- /dev/null
++++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-global-1.ll
+@@ -0,0 +1,79 @@
++; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
++; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
++; Source code:
++;   typedef struct v3 { int a; int b; } __v3;
++;   #define _(x) (__builtin_preserve_access_index(x))
++;   int get_value(const int *arg);
++;   __v3 g __attribute__((section("stats")));
++;   int test() {
++;     return get_value(_(&g.b));
++;   }
++; Compilation flag:
++;   clang -target bpf -O2 -g -S -emit-llvm test.c
++
++%struct.v3 = type { i32, i32 }
++
++@g = dso_local global %struct.v3 zeroinitializer, section "stats", align 4, !dbg !0
++
++; Function Attrs: nounwind
++define dso_local i32 @test() local_unnamed_addr #0 !dbg !16 {
++entry:
++  %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
++  %call = tail call i32 @get_value(i32* %0) #3, !dbg !20
++  ret i32 %call, !dbg !21
++}
++
++; CHECK:              r2 = 4
++; CHECK:              r1 = g ll
++; CHECK:              r1 += r2
++; CHECK:              call get_value
++
++; CHECK:              .long   16                      # BTF_KIND_STRUCT(id = [[TID1:[0-9]+]])
++
++; CHECK:              .ascii  ".text"                 # string offset=10
++; CHECK:              .ascii  "v3"                    # string offset=16
++; CHECK:              .ascii  "0:1"                   # string offset=23
++
++; CHECK:              .long   12                      # OffsetReloc
++; CHECK-NEXT:         .long   10                      # Offset reloc section string offset=10
++; CHECK-NEXT:         .long   1
++; CHECK-NEXT:         .long   .Ltmp{{[0-9]+}}
++; CHECK-NEXT:         .long   [[TID1]]
++; CHECK-NEXT:         .long   23
++
++declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
++
++; Function Attrs: nounwind readnone
++declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v3s(%struct.v3*, i32, i32) #2
++
++attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
++attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
++attributes #2 = { nounwind readnone }
++attributes #3 = { nounwind }
++
++!llvm.dbg.cu = !{!2}
++!llvm.module.flags = !{!12, !13, !14}
++!llvm.ident = !{!15}
++
++!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
++!1 = distinct !DIGlobalVariable(name: "g", scope: !2, file: !3, line: 4, type: !6, isLocal: false, isDefinition: true)
++!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)
++!3 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
++!4 = !{}
++!5 = !{!0}
++!6 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v3", file: !3, line: 1, baseType: !7)
++!7 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !3, line: 1, size: 64, elements: !8)
++!8 = !{!9, !11}
++!9 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !7, file: !3, line: 1, baseType: !10, size: 32)
++!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
++!11 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !7, file: !3, line: 1, baseType: !10, size: 32, offset: 32)
++!12 = !{i32 2, !"Dwarf Version", i32 4}
++!13 = !{i32 2, !"Debug Info Version", i32 3}
++!14 = !{i32 1, !"wchar_size", i32 4}
++!15 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
++!16 = distinct !DISubprogram(name: "test", scope: !3, file: !3, line: 5, type: !17, scopeLine: 5, isDefinition: true, isOptimized: true, unit: !2, retainedNodes: !4)
++!17 = !DISubroutineType(types: !18)
++!18 = !{!10}
++!19 = !DILocation(line: 6, column: 20, scope: !16)
++!20 = !DILocation(line: 6, column: 10, scope: !16)
++!21 = !DILocation(line: 6, column: 3, scope: !16)
+diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-global-2.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-global-2.ll
+new file mode 100644
+index 0000000..721081e
+--- /dev/null
++++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-global-2.ll
+@@ -0,0 +1,95 @@
++; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
++; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
++; Source code:
++;   typedef struct v3 { int a; int b; } __v3;
++;   #define _(x) (__builtin_preserve_access_index(x))
++;   int get_value(const int *arg);
++;   __v3 g[4][5] __attribute__((section("stats")));
++;   int test() {
++;     return get_value(_(&g[1][2].b));
++;   }
++; Compilation flag:
++;   clang -target bpf -O2 -g -S -emit-llvm test.c
++
++%struct.v3 = type { i32, i32 }
++
++@g = dso_local global [4 x [5 x %struct.v3]] zeroinitializer, section "stats", align 4, !dbg !0
++
++; Function Attrs: nounwind
++define dso_local i32 @test() local_unnamed_addr #0 !dbg !23 {
++entry:
++  %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
++  %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
++  %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
++  %call = tail call i32 @get_value(i32* %2) #3, !dbg !27
++  ret i32 %call, !dbg !28
++}
++
++; CHECK:              r2 = 60
++; CHECK:              r1 = g ll
++; CHECK:              r1 += r2
++; CHECK:              call get_value
++
++; CHECK:              .long   16                      # BTF_KIND_STRUCT(id = [[TID1:[0-9]+]])
++
++; CHECK:              .ascii  ".text"                 # string offset=10
++; CHECK:              .ascii  "v3"                    # string offset=16
++; CHECK:              .ascii  "7:1"                   # string offset=23
++
++; CHECK:              .long   12                      # OffsetReloc
++; CHECK-NEXT:         .long   10                      # Offset reloc section string offset=10
++; CHECK-NEXT:         .long   1
++; CHECK-NEXT:         .long   .Ltmp{{[0-9]+}}
++; CHECK-NEXT:         .long   [[TID1]]
++; CHECK-NEXT:         .long   23
++
++
++declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
++
++; Function Attrs: nounwind readnone
++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
++
++; Function Attrs: nounwind readnone
++declare %struct.v3* @llvm.preserve.array.access.index.p0s_struct.v3s.p0a5s_struct.v3s([5 x %struct.v3]*, i32, i32) #2
++
++; Function Attrs: nounwind readnone
++declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v3s(%struct.v3*, i32, i32) #2
++
++attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
++attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
++attributes #2 = { nounwind readnone }
++attributes #3 = { nounwind }
++
++!llvm.dbg.cu = !{!2}
++!llvm.module.flags = !{!19, !20, !21}
++!llvm.ident = !{!22}
++
++!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
++!1 = distinct !DIGlobalVariable(name: "g", scope: !2, file: !3, line: 4, type: !6, isLocal: false, isDefinition: true)
++!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)
++!3 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
++!4 = !{}
++!5 = !{!6, !16}
++!6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 1280, elements: !13)
++!7 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v3", file: !3, line: 1, baseType: !8)
++!8 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !3, line: 1, size: 64, elements: !9)
++!9 = !{!10, !12}
++!10 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !8, file: !3, line: 1, baseType: !11, size: 32)
++!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
++!12 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !8, file: !3, line: 1, baseType: !11, size: 32, offset: 32)
++!13 = !{!14, !15}
++!14 = !DISubrange(count: 4)
++!15 = !DISubrange(count: 5)
++!16 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 320, elements: !17)
++!17 = !{!15}
++!18 = !{!0}
++!19 = !{i32 2, !"Dwarf Version", i32 4}
++!20 = !{i32 2, !"Debug Info Version", i32 3}
++!21 = !{i32 1, !"wchar_size", i32 4}
++!22 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
++!23 = distinct !DISubprogram(name: "test", scope: !3, file: !3, line: 5, type: !24, scopeLine: 5, isDefinition: true, isOptimized: true, unit: !2, retainedNodes: !4)
++!24 = !DISubroutineType(types: !25)
++!25 = !{!11}
++!26 = !DILocation(line: 6, column: 20, scope: !23)
++!27 = !DILocation(line: 6, column: 10, scope: !23)
++!28 = !DILocation(line: 6, column: 3, scope: !23)
+diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-global-3.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-global-3.ll
+new file mode 100644
+index 0000000..394d04f
+--- /dev/null
++++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-global-3.ll
+@@ -0,0 +1,84 @@
++; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
++; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
++; Source code:
++;   typedef struct v3 { int a; int b; } __v3;
++;   #define _(x) (__builtin_preserve_access_index(x))
++;   int get_value(const int *arg);
++;   __v3 *g __attribute__((section("stats")));
++;   int test() {
++;     return get_value(_(&g->b));
++;   }
++; Compilation flag:
++;   clang -target bpf -O2 -g -S -emit-llvm test.c
++
++%struct.v3 = type { i32, i32 }
++
++@g = dso_local local_unnamed_addr global %struct.v3* null, section "stats", align 8, !dbg !0
++
++; Function Attrs: nounwind
++define dso_local i32 @test() local_unnamed_addr #0 !dbg !17 {
++entry:
++  %0 = load %struct.v3*, %struct.v3** @g, align 8, !dbg !20, !tbaa !21
++  %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
++  %call = tail call i32 @get_value(i32* %1) #3, !dbg !25
++  ret i32 %call, !dbg !26
++}
++
++; CHECK:              r2 = 4
++; CHECK:              r1 += r2
++; CHECK:              call get_value
++
++; CHECK:              .long   16                      # BTF_KIND_STRUCT(id = [[TID1:[0-9]+]])
++
++; CHECK:              .ascii  ".text"                 # string offset=10
++; CHECK:              .ascii  "v3"                    # string offset=16
++; CHECK:              .ascii  "0:1"                   # string offset=23
++
++; CHECK:              .long   12                      # OffsetReloc
++; CHECK-NEXT:         .long   10                      # Offset reloc section string offset=10
++; CHECK-NEXT:         .long   1
++; CHECK-NEXT:         .long   .Ltmp{{[0-9]+}}
++; CHECK-NEXT:         .long   [[TID1]]
++; CHECK-NEXT:         .long   23
++
++declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
++
++; Function Attrs: nounwind readnone
++declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v3s(%struct.v3*, i32, i32) #2
++
++attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
++attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
++attributes #2 = { nounwind readnone }
++attributes #3 = { nounwind }
++
++!llvm.dbg.cu = !{!2}
++!llvm.module.flags = !{!13, !14, !15}
++!llvm.ident = !{!16}
++
++!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
++!1 = distinct !DIGlobalVariable(name: "g", scope: !2, file: !3, line: 4, type: !6, isLocal: false, isDefinition: true)
++!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)
++!3 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
++!4 = !{}
++!5 = !{!0}
++!6 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64)
++!7 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v3", file: !3, line: 1, baseType: !8)
++!8 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !3, line: 1, size: 64, elements: !9)
++!9 = !{!10, !12}
++!10 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !8, file: !3, line: 1, baseType: !11, size: 32)
++!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
++!12 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !8, file: !3, line: 1, baseType: !11, size: 32, offset: 32)
++!13 = !{i32 2, !"Dwarf Version", i32 4}
++!14 = !{i32 2, !"Debug Info Version", i32 3}
++!15 = !{i32 1, !"wchar_size", i32 4}
++!16 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
++!17 = distinct !DISubprogram(name: "test", scope: !3, file: !3, line: 5, type: !18, scopeLine: 5, isDefinition: true, isOptimized: true, unit: !2, retainedNodes: !4)
++!18 = !DISubroutineType(types: !19)
++!19 = !{!11}
++!20 = !DILocation(line: 6, column: 20, scope: !17)
++!21 = !{!22, !22, i64 0}
++!22 = !{!"any pointer", !23, i64 0}
++!23 = !{!"omnipotent char", !24, i64 0}
++!24 = !{!"Simple C/C++ TBAA"}
++!25 = !DILocation(line: 6, column: 10, scope: !17)
++!26 = !DILocation(line: 6, column: 3, scope: !17)
+diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-ignore.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-ignore.ll
+new file mode 100644
+index 0000000..2d14e71
+--- /dev/null
++++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-ignore.ll
+@@ -0,0 +1,62 @@
++; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
++; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
++; Source code:
++;   #define _(x) (__builtin_preserve_access_index(x))
++;   int get_value(const int *arg);
++;   int test(int *arg) {
++;     return get_value(_(&arg[4]));
++;   }
++; Compilation flag:
++;   clang -target bpf -O2 -g -S -emit-llvm test.c
++
++; Function Attrs: nounwind
++define dso_local i32 @test(i32* %arg) local_unnamed_addr #0 !dbg !10 {
++entry:
++  call void @llvm.dbg.value(metadata i32* %arg, metadata !14, metadata !DIExpression()), !dbg !15
++  %0 = tail call i32* @llvm.preserve.array.access.index.p0i32.p0i32(i32* %arg, i32 0, i32 4), !dbg !16, !llvm.preserve.access.index !4
++  %call = tail call i32 @get_value(i32* %0) #4, !dbg !17
++  ret i32 %call, !dbg !18
++}
++
++; CHECK:             r1 += 16
++; CHECK:             call get_value
++; CHECK:             .section        .BTF.ext,"",@progbits
++; CHECK-NOT:         .long   12                      # OffsetReloc
++
++declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
++
++; Function Attrs: nounwind readnone
++declare i32* @llvm.preserve.array.access.index.p0i32.p0i32(i32*, i32, i32) #2
++
++; Function Attrs: nounwind readnone speculatable willreturn
++declare void @llvm.dbg.value(metadata, metadata, metadata) #3
++
++attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
++attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
++attributes #2 = { nounwind readnone }
++attributes #3 = { nounwind readnone speculatable willreturn }
++attributes #4 = { nounwind }
++
++!llvm.dbg.cu = !{!0}
++!llvm.module.flags = !{!6, !7, !8}
++!llvm.ident = !{!9}
++
++!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)
++!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
++!2 = !{}
++!3 = !{!4}
++!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64)
++!5 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
++!6 = !{i32 2, !"Dwarf Version", i32 4}
++!7 = !{i32 2, !"Debug Info Version", i32 3}
++!8 = !{i32 1, !"wchar_size", i32 4}
++!9 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
++!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)
++!11 = !DISubroutineType(types: !12)
++!12 = !{!5, !4}
++!13 = !{!14}
++!14 = !DILocalVariable(name: "arg", arg: 1, scope: !10, file: !1, line: 3, type: !4)
++!15 = !DILocation(line: 0, scope: !10)
++!16 = !DILocation(line: 4, column: 20, scope: !10)
++!17 = !DILocation(line: 4, column: 10, scope: !10)
++!18 = !DILocation(line: 4, column: 3, scope: !10)
+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
+new file mode 100644
+index 0000000..7f79196f
+--- /dev/null
++++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-multi-array-1.ll
+@@ -0,0 +1,101 @@
++; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
++; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
++; Source code:
++;   typedef int __int;
++;   typedef struct v3 { int a; __int b[4][4]; } __v3;
++;   #define _(x) (__builtin_preserve_access_index(x))
++;   int get_value(const int *arg);
++;   int test(__v3 *arg) {
++;     return get_value(_(&arg[1].b[2][3]));
++;   }
++; Compilation flag:
++;   clang -target bpf -O2 -g -S -emit-llvm test.c
++
++%struct.v3 = type { i32, [4 x [4 x i32]] }
++
++; Function Attrs: nounwind
++define dso_local i32 @test(%struct.v3* %arg) local_unnamed_addr #0 !dbg !21 {
++entry:
++  call void @llvm.dbg.value(metadata %struct.v3* %arg, metadata !25, metadata !DIExpression()), !dbg !26
++  %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
++  %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
++  %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
++  %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
++  %call = tail call i32 @get_value(i32* %3) #4, !dbg !28
++  ret i32 %call, !dbg !29
++}
++
++; CHECK:              r2 = 116
++; CHECK:              r1 += r2
++; CHECK:              call get_value
++
++; CHECK:              .long   6                       # BTF_KIND_STRUCT(id = [[TID1:[0-9]+]])
++
++; CHECK:              .ascii  "v3"                    # string offset=6
++; CHECK:              .ascii  ".text"                 # string offset=52
++; CHECK:              .ascii  "1:1:2:3"               # string offset=58
++
++; CHECK:              .long   12                      # OffsetReloc
++; CHECK-NEXT:         .long   52                      # Offset reloc section string offset=52
++; CHECK-NEXT:         .long   1
++; CHECK-NEXT:         .long   .Ltmp{{[0-9]+}}
++; CHECK-NEXT:         .long   [[TID1]]
++; CHECK-NEXT:         .long   58
++
++declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
++
++; Function Attrs: nounwind readnone
++declare %struct.v3* @llvm.preserve.array.access.index.p0s_struct.v3s.p0s_struct.v3s(%struct.v3*, i32, i32) #2
++
++; Function Attrs: nounwind readnone
++declare [4 x [4 x i32]]* @llvm.preserve.struct.access.index.p0a4a4i32.p0s_struct.v3s(%struct.v3*, i32, i32) #2
++
++; Function Attrs: nounwind readnone
++declare [4 x i32]* @llvm.preserve.array.access.index.p0a4i32.p0a4a4i32([4 x [4 x i32]]*, i32, i32) #2
++
++; Function Attrs: nounwind readnone
++declare i32* @llvm.preserve.array.access.index.p0i32.p0a4i32([4 x i32]*, i32, i32) #2
++
++; Function Attrs: nounwind readnone speculatable willreturn
++declare void @llvm.dbg.value(metadata, metadata, metadata) #3
++
++attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
++attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
++attributes #2 = { nounwind readnone }
++attributes #3 = { nounwind readnone speculatable willreturn }
++attributes #4 = { nounwind }
++
++!llvm.dbg.cu = !{!0}
++!llvm.module.flags = !{!17, !18, !19}
++!llvm.ident = !{!20}
++
++!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)
++!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
++!2 = !{}
++!3 = !{!4, !11, !15}
++!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64)
++!5 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v3", file: !1, line: 2, baseType: !6)
++!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !1, line: 2, size: 544, elements: !7)
++!7 = !{!8, !10}
++!8 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !6, file: !1, line: 2, baseType: !9, size: 32)
++!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
++!10 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !6, file: !1, line: 2, baseType: !11, size: 512, offset: 32)
++!11 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 512, elements: !13)
++!12 = !DIDerivedType(tag: DW_TAG_typedef, name: "__int", file: !1, line: 1, baseType: !9)
++!13 = !{!14, !14}
++!14 = !DISubrange(count: 4)
++!15 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 128, elements: !16)
++!16 = !{!14}
++!17 = !{i32 2, !"Dwarf Version", i32 4}
++!18 = !{i32 2, !"Debug Info Version", i32 3}
++!19 = !{i32 1, !"wchar_size", i32 4}
++!20 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
++!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)
++!22 = !DISubroutineType(types: !23)
++!23 = !{!9, !4}
++!24 = !{!25}
++!25 = !DILocalVariable(name: "arg", arg: 1, scope: !21, file: !1, line: 5, type: !4)
++!26 = !DILocation(line: 0, scope: !21)
++!27 = !DILocation(line: 6, column: 20, scope: !21)
++!28 = !DILocation(line: 6, column: 10, scope: !21)
++!29 = !DILocation(line: 6, column: 3, scope: !21)
+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
+new file mode 100644
+index 0000000..a9c29aa
+--- /dev/null
++++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-multi-array-2.ll
+@@ -0,0 +1,107 @@
++; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
++; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
++; Source code:
++;   typedef int __int;
++;   typedef struct v3 { int a; __int b[4][4][4]; } __v3;
++;   #define _(x) (__builtin_preserve_access_index(x))
++;   int get_value(const int *arg);
++;   int test(__v3 *arg) {
++;     return get_value(_(&arg[1].b[2][3][2]));
++;   }
++; Compilation flag:
++;   clang -target bpf -O2 -g -S -emit-llvm test.c
++
++%struct.v3 = type { i32, [4 x [4 x [4 x i32]]] }
++
++; Function Attrs: nounwind
++define dso_local i32 @test(%struct.v3* %arg) local_unnamed_addr #0 !dbg !23 {
++entry:
++  call void @llvm.dbg.value(metadata %struct.v3* %arg, metadata !27, metadata !DIExpression()), !dbg !28
++  %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
++  %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
++  %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
++  %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
++  %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
++  %call = tail call i32 @get_value(i32* %4) #4, !dbg !30
++  ret i32 %call, !dbg !31
++}
++
++; CHECK:             r2 = 448
++; CHECK:             r1 += r2
++; CHECK:             call get_value
++
++; CHECK:             .long   6                       # BTF_KIND_STRUCT(id = [[TID1:[0-9]+]])
++
++; CHECK:             .ascii  "v3"                    # string offset=6
++; CHECK:             .ascii  ".text"                 # string offset=52
++; CHECK:             .ascii  "1:1:2:3:2"             # string offset=58
++
++; CHECK:             .long   12                      # OffsetReloc
++; CHECK-NEXT:        .long   52                      # Offset reloc section string offset=52
++; CHECK-NEXT:        .long   1
++; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
++; CHECK-NEXT:        .long   [[TID1]]
++; CHECK-NEXT:        .long   58
++
++declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
++
++; Function Attrs: nounwind readnone
++declare %struct.v3* @llvm.preserve.array.access.index.p0s_struct.v3s.p0s_struct.v3s(%struct.v3*, i32, i32) #2
++
++; Function Attrs: nounwind readnone
++declare [4 x [4 x [4 x i32]]]* @llvm.preserve.struct.access.index.p0a4a4a4i32.p0s_struct.v3s(%struct.v3*, i32, i32) #2
++
++; Function Attrs: nounwind readnone
++declare [4 x [4 x i32]]* @llvm.preserve.array.access.index.p0a4a4i32.p0a4a4a4i32([4 x [4 x [4 x i32]]]*, i32, i32) #2
++
++; Function Attrs: nounwind readnone
++declare [4 x i32]* @llvm.preserve.array.access.index.p0a4i32.p0a4a4i32([4 x [4 x i32]]*, i32, i32) #2
++
++; Function Attrs: nounwind readnone
++declare i32* @llvm.preserve.array.access.index.p0i32.p0a4i32([4 x i32]*, i32, i32) #2
++
++; Function Attrs: nounwind readnone speculatable willreturn
++declare void @llvm.dbg.value(metadata, metadata, metadata) #3
++
++attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
++attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
++attributes #2 = { nounwind readnone }
++attributes #3 = { nounwind readnone speculatable willreturn }
++attributes #4 = { nounwind }
++
++!llvm.dbg.cu = !{!0}
++!llvm.module.flags = !{!19, !20, !21}
++!llvm.ident = !{!22}
++
++!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)
++!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
++!2 = !{}
++!3 = !{!4, !11, !15, !17}
++!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64)
++!5 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v3", file: !1, line: 2, baseType: !6)
++!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !1, line: 2, size: 2080, elements: !7)
++!7 = !{!8, !10}
++!8 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !6, file: !1, line: 2, baseType: !9, size: 32)
++!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
++!10 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !6, file: !1, line: 2, baseType: !11, size: 2048, offset: 32)
++!11 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 2048, elements: !13)
++!12 = !DIDerivedType(tag: DW_TAG_typedef, name: "__int", file: !1, line: 1, baseType: !9)
++!13 = !{!14, !14, !14}
++!14 = !DISubrange(count: 4)
++!15 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 512, elements: !16)
++!16 = !{!14, !14}
++!17 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 128, elements: !18)
++!18 = !{!14}
++!19 = !{i32 2, !"Dwarf Version", i32 4}
++!20 = !{i32 2, !"Debug Info Version", i32 3}
++!21 = !{i32 1, !"wchar_size", i32 4}
++!22 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
++!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)
++!24 = !DISubroutineType(types: !25)
++!25 = !{!9, !4}
++!26 = !{!27}
++!27 = !DILocalVariable(name: "arg", arg: 1, scope: !23, file: !1, line: 5, type: !4)
++!28 = !DILocation(line: 0, scope: !23)
++!29 = !DILocation(line: 6, column: 20, scope: !23)
++!30 = !DILocation(line: 6, column: 10, scope: !23)
++!31 = !DILocation(line: 6, column: 3, scope: !23)
+diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-pointer-1.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-pointer-1.ll
+new file mode 100644
+index 0000000..e85b393
+--- /dev/null
++++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-pointer-1.ll
+@@ -0,0 +1,83 @@
++; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
++; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
++; Source code:
++;   typedef struct v3 { int a; int b; } __v3;
++;   #define _(x) (__builtin_preserve_access_index(x))
++;   int get_value(const int *arg);
++;   int test(__v3 *arg) {
++;     return get_value(_(&arg[1]));
++;   }
++; Compilation flag:
++;   clang -target bpf -O2 -g -S -emit-llvm test.c
++
++%struct.v3 = type { i32, i32 }
++
++; Function Attrs: nounwind
++define dso_local i32 @test(%struct.v3* %arg) local_unnamed_addr #0 !dbg !15 {
++entry:
++  call void @llvm.dbg.value(metadata %struct.v3* %arg, metadata !19, metadata !DIExpression()), !dbg !20
++  %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
++  %1 = getelementptr inbounds %struct.v3, %struct.v3* %0, i64 0, i32 0, !dbg !21
++  %call = tail call i32 @get_value(i32* %1) #4, !dbg !22
++  ret i32 %call, !dbg !23
++}
++
++; CHECK:              r2 = 8
++; CHECK:              r1 += r2
++; CHECK:              call get_value
++
++; CHECK:              .long   6                       # BTF_KIND_STRUCT(id = [[TID1:[0-9]+]])
++
++; CHECK:              .ascii  "v3"                    # string offset=6
++; CHECK:              .ascii  ".text"                 # string offset=26
++; CHECK:              .byte   49                      # string offset=32
++
++; CHECK:              .long   12                      # OffsetReloc
++; CHECK-NEXT:         .long   26                      # Offset reloc section string offset=26
++; CHECK-NEXT:         .long   1
++; CHECK-NEXT:         .long   .Ltmp{{[0-9]+}}
++; CHECK-NEXT:         .long   [[TID1]]
++; CHECK-NEXT:         .long   32
++
++declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
++
++; Function Attrs: nounwind readnone
++declare %struct.v3* @llvm.preserve.array.access.index.p0s_struct.v3s.p0s_struct.v3s(%struct.v3*, i32, i32) #2
++
++; Function Attrs: nounwind readnone speculatable willreturn
++declare void @llvm.dbg.value(metadata, metadata, metadata) #3
++
++attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
++attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
++attributes #2 = { nounwind readnone }
++attributes #3 = { nounwind readnone speculatable willreturn }
++attributes #4 = { nounwind }
++
++!llvm.dbg.cu = !{!0}
++!llvm.module.flags = !{!11, !12, !13}
++!llvm.ident = !{!14}
++
++!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None)
++!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
++!2 = !{}
++!3 = !{!4}
++!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64)
++!5 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v3", file: !1, line: 1, baseType: !6)
++!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !1, line: 1, size: 64, elements: !7)
++!7 = !{!8, !10}
++!8 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !6, file: !1, line: 1, baseType: !9, size: 32)
++!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
++!10 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !6, file: !1, line: 1, baseType: !9, size: 32, offset: 32)
++!11 = !{i32 2, !"Dwarf Version", i32 4}
++!12 = !{i32 2, !"Debug Info Version", i32 3}
++!13 = !{i32 1, !"wchar_size", i32 4}
++!14 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
++!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)
++!16 = !DISubroutineType(types: !17)
++!17 = !{!9, !4}
++!18 = !{!19}
++!19 = !DILocalVariable(name: "arg", arg: 1, scope: !15, file: !1, line: 4, type: !4)
++!20 = !DILocation(line: 0, scope: !15)
++!21 = !DILocation(line: 5, column: 20, scope: !15)
++!22 = !DILocation(line: 5, column: 10, scope: !15)
++!23 = !DILocation(line: 5, column: 3, scope: !15)
+diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-pointer-2.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-pointer-2.ll
+new file mode 100644
+index 0000000..1c54935
+--- /dev/null
++++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-pointer-2.ll
+@@ -0,0 +1,85 @@
++; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
++; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
++; Source code:
++;   typedef struct v3 { int a; int b; } __v3;
++;   #define _(x) (__builtin_preserve_access_index(x))
++;   int get_value(const int *arg);
++;   int test(__v3 *arg) {
++;     return get_value(_(&arg[1].b));
++;   }
++; Compilation flag:
++;   clang -target bpf -O2 -g -S -emit-llvm test.c
++
++%struct.v3 = type { i32, i32 }
++
++; Function Attrs: nounwind
++define dso_local i32 @test(%struct.v3* %arg) local_unnamed_addr #0 !dbg !15 {
++entry:
++  call void @llvm.dbg.value(metadata %struct.v3* %arg, metadata !19, metadata !DIExpression()), !dbg !20
++  %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
++  %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
++  %call = tail call i32 @get_value(i32* %1) #4, !dbg !22
++  ret i32 %call, !dbg !23
++}
++
++; CHECK:              r2 = 12
++; CHECK-NEXT:         r1 += r2
++; CHECK:              call get_value
++
++; CHECK:              .long   6                       # BTF_KIND_STRUCT(id = [[TID1:[0-9]+]])
++; CHECK:              .ascii  "v3"                    # string offset=6
++; CHECK:              .ascii  ".text"                 # string offset=26
++; CHECK:              .ascii  "1:1"                   # string offset=32
++
++; CHECK:              .long   12                      # OffsetReloc
++; CHECK-NEXT:         .long   26                      # Offset reloc section string offset=26
++; CHECK-NEXT:         .long   1
++; CHECK-NEXT:         .long   .Ltmp{{[0-9]+}}
++; CHECK-NEXT:         .long   [[TID1]]
++; CHECK-NEXT:         .long   32
++
++declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
++
++; Function Attrs: nounwind readnone
++declare %struct.v3* @llvm.preserve.array.access.index.p0s_struct.v3s.p0s_struct.v3s(%struct.v3*, i32, i32) #2
++
++; Function Attrs: nounwind readnone
++declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v3s(%struct.v3*, i32, i32) #2
++
++; Function Attrs: nounwind readnone speculatable willreturn
++declare void @llvm.dbg.value(metadata, metadata, metadata) #3
++
++attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
++attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
++attributes #2 = { nounwind readnone }
++attributes #3 = { nounwind readnone speculatable willreturn }
++attributes #4 = { nounwind }
++
++!llvm.dbg.cu = !{!0}
++!llvm.module.flags = !{!11, !12, !13}
++!llvm.ident = !{!14}
++
++!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None)
++!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
++!2 = !{}
++!3 = !{!4}
++!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64)
++!5 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v3", file: !1, line: 1, baseType: !6)
++!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !1, line: 1, size: 64, elements: !7)
++!7 = !{!8, !10}
++!8 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !6, file: !1, line: 1, baseType: !9, size: 32)
++!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
++!10 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !6, file: !1, line: 1, baseType: !9, size: 32, offset: 32)
++!11 = !{i32 2, !"Dwarf Version", i32 4}
++!12 = !{i32 2, !"Debug Info Version", i32 3}
++!13 = !{i32 1, !"wchar_size", i32 4}
++!14 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
++!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)
++!16 = !DISubroutineType(types: !17)
++!17 = !{!9, !4}
++!18 = !{!19}
++!19 = !DILocalVariable(name: "arg", arg: 1, scope: !15, file: !1, line: 4, type: !4)
++!20 = !DILocation(line: 0, scope: !15)
++!21 = !DILocation(line: 5, column: 20, scope: !15)
++!22 = !DILocation(line: 5, column: 10, scope: !15)
++!23 = !DILocation(line: 5, column: 3, scope: !15)
+diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-anonymous.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-anonymous.ll
+index 732187c..08a204f 100644
+--- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-anonymous.ll
++++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-anonymous.ll
+@@ -30,7 +30,7 @@ define dso_local i32 @bpf_prog(%struct.sk_buff*) local_unnamed_addr #0 !dbg !15
+   %3 = bitcast i32* %2 to i8*, !dbg !34
+   call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %3) #4, !dbg !34
+   %4 = tail call [10 x %struct.anon]* @llvm.preserve.struct.access.index.p0a10s_struct.anons.p0s_struct.sk_buffs(%struct.sk_buff* %0, i32 1, i32 1), !dbg !35, !llvm.preserve.access.index !19
+-  %5 = tail call %struct.anon* @llvm.preserve.array.access.index.p0s_struct.anons.p0a10s_struct.anons([10 x %struct.anon]* %4, i32 1, i32 5), !dbg !35
++  %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
+   %6 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.anons(%struct.anon* %5, i32 0, i32 0), !dbg !35, !llvm.preserve.access.index !24
+   %7 = bitcast i32* %6 to i8*, !dbg !35
+   %8 = call i32 inttoptr (i64 4 to i32 (i8*, i32, i8*)*)(i8* nonnull %3, i32 4, i8* %7) #4, !dbg !36
+diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-array.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-array.ll
+index 77d2375..b18a4ab 100644
+--- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-array.ll
++++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-array.ll
+@@ -31,7 +31,7 @@ define dso_local i32 @bpf_prog(%struct.sk_buff*) local_unnamed_addr #0 !dbg !15
+   %3 = bitcast i32* %2 to i8*, !dbg !34
+   call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %3) #4, !dbg !34
+   %4 = tail call [10 x %struct.net_device]* @llvm.preserve.struct.access.index.p0a10s_struct.net_devices.p0s_struct.sk_buffs(%struct.sk_buff* %0, i32 1, i32 1), !dbg !35, !llvm.preserve.access.index !19
+-  %5 = tail call %struct.net_device* @llvm.preserve.array.access.index.p0s_struct.net_devices.p0a10s_struct.net_devices([10 x %struct.net_device]* %4, i32 1, i32 5), !dbg !35
++  %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
+   %6 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.net_devices(%struct.net_device* %5, i32 0, i32 0), !dbg !35, !llvm.preserve.access.index !24
+   %7 = bitcast i32* %6 to i8*, !dbg !35
+   %8 = call i32 inttoptr (i64 4 to i32 (i8*, i32, i8*)*)(i8* nonnull %3, i32 4, i8* %7) #4, !dbg !36
+diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-array.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-array.ll
+index 7843c52..d63bc07 100644
+--- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-array.ll
++++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-array.ll
+@@ -21,7 +21,7 @@ define dso_local i32 @test(%struct.__s* %arg) local_unnamed_addr #0 !dbg !7 {
+ entry:
+   call void @llvm.dbg.value(metadata %struct.__s* %arg, metadata !24, metadata !DIExpression()), !dbg !25
+   %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
+-  %1 = tail call i32* @llvm.preserve.array.access.index.p0i32.p0a7i32([7 x i32]* %0, i32 1, i32 1), !dbg !26
++  %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
+   %2 = bitcast i32* %1 to i8*, !dbg !26
+   %call = tail call i32 @get_value(i8* %2) #4, !dbg !27
+   ret i32 %call, !dbg !28
+diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef.ll
+index c09d979..8281694 100644
+--- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef.ll
++++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef.ll
+@@ -24,7 +24,7 @@
+ define dso_local i32 @test([7 x %union.u]* %arg) local_unnamed_addr #0 !dbg !7 {
+ entry:
+   call void @llvm.dbg.value(metadata [7 x %union.u]* %arg, metadata !28, metadata !DIExpression()), !dbg !29
+-  %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
++  %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
+   %arraydecay = getelementptr inbounds [7 x %union.u], [7 x %union.u]* %0, i64 0, i64 0, !dbg !30
+   %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
+   %d = getelementptr inbounds %union.u, %union.u* %1, i64 0, i32 0, !dbg !30
+-- 
+1.8.3.1
+
diff --git a/SOURCES/0001-BPF-annotate-DIType-metadata-for-builtin-preseve_arr.patch b/SOURCES/0001-BPF-annotate-DIType-metadata-for-builtin-preseve_arr.patch
new file mode 100644
index 0000000..60ba6d9
--- /dev/null
+++ b/SOURCES/0001-BPF-annotate-DIType-metadata-for-builtin-preseve_arr.patch
@@ -0,0 +1,138 @@
+From f2ccdd2700174c717dc55a0f4c3f5a91ae73ff42 Mon Sep 17 00:00:00 2001
+From: Yonghong Song <yhs@fb.com>
+Date: Fri, 2 Aug 2019 21:28:28 +0000
+Subject: [PATCH] [BPF] annotate DIType metadata for builtin
+ preseve_array_access_index()
+
+Previously, debuginfo types are annotated to
+IR builtin preserve_struct_access_index() and
+preserve_union_access_index(), but not
+preserve_array_access_index(). The debug info
+is useful to identify the root type name which
+later will be used for type comparison.
+
+For user access without explicit type conversions,
+the previous scheme works as we can ignore intermediate
+compiler generated type conversions (e.g., from union types to
+union members) and still generate correct access index string.
+
+The issue comes with user explicit type conversions, e.g.,
+converting an array to a structure like below:
+  struct t { int a; char b[40]; };
+  struct p { int c; int d; };
+  struct t *var = ...;
+  ... __builtin_preserve_access_index(&(((struct p *)&(var->b[0]))->d)) ...
+Although BPF backend can derive the type of &(var->b[0]),
+explicit type annotation make checking more consistent
+and less error prone.
+
+Another benefit is for multiple dimension array handling.
+For example,
+  struct p { int c; int d; } g[8][9][10];
+  ... __builtin_preserve_access_index(&g[2][3][4].d) ...
+It would be possible to calculate the number of "struct p"'s
+before accessing its member "d" if array debug info is
+available as it contains each dimension range.
+
+This patch enables to annotate IR builtin preserve_array_access_index()
+with proper debuginfo type. The unit test case and language reference
+is updated as well.
+
+Signed-off-by: Yonghong Song <yhs@fb.com>
+
+Differential Revision: https://reviews.llvm.org/D65664
+
+llvm-svn: 367724
+(cherry picked from commit d0ea05d5eff475a27a5d3bbe4d9fd389935f9cb2)
+
+Also added back
+Value *CreatePreserveArrayAccessIndex(Value *Base, unsigned Dimension,
+                                      unsigned LastIndex);
+
+To avoid breaking the ABI.
+---
+ clang/lib/CodeGen/CGExpr.cpp                       | 12 ++++++++---
+ .../CodeGen/builtin-preserve-access-index-array.c  | 18 +++++++++++++++++
+ clang/test/CodeGen/builtin-preserve-access-index.c | 23 +++++++++++-----------
+ llvm/docs/LangRef.rst                              |  4 ++++
+ llvm/include/llvm/IR/IRBuilder.h                   | 13 ++++++++++--
+ llvm/test/CodeGen/BPF/CORE/intrinsic-array.ll      |  2 +-
+ 6 files changed, 55 insertions(+), 17 deletions(-)
+ create mode 100644 clang/test/CodeGen/builtin-preserve-access-index-array.c
+
+diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
+index 87e8a55..b63e3af 100644
+--- a/llvm/docs/LangRef.rst
++++ b/llvm/docs/LangRef.rst
+@@ -17349,6 +17349,10 @@ based on array base ``base``, array dimension ``dim`` and the last access index
+ into the array. The return type ``ret_type`` is a pointer type to the array element.
+ The array ``dim`` and ``index`` are preserved which is more robust than
+ getelementptr instruction which may be subject to compiler transformation.
++The ``llvm.preserve.access.index`` type of metadata is attached to this call instruction
++to provide array or pointer debuginfo type.
++The metadata is a ``DICompositeType`` or ``DIDerivedType`` representing the
++debuginfo version of ``type``.
+ 
+ Arguments:
+ """"""""""
+diff --git a/llvm/include/llvm/IR/IRBuilder.h b/llvm/include/llvm/IR/IRBuilder.h
+index a74364d..c2fa9a3 100644
+--- a/llvm/include/llvm/IR/IRBuilder.h
++++ b/llvm/include/llvm/IR/IRBuilder.h
+@@ -2455,6 +2455,11 @@ public:
+ 
+   Value *CreatePreserveArrayAccessIndex(Value *Base, unsigned Dimension,
+                                         unsigned LastIndex) {
++    return CreatePreserveArrayAccessIndex(Base, Dimension, LastIndex, nullptr);
++  }
++
++  Value *CreatePreserveArrayAccessIndex(Value *Base, unsigned Dimension,
++                                        unsigned LastIndex, MDNode *DbgInfo) {
+     assert(isa<PointerType>(Base->getType()) &&
+            "Invalid Base ptr type for preserve.array.access.index.");
+     auto *BaseType = Base->getType();
+@@ -2476,6 +2481,8 @@ public:
+     Value *DimV = getInt32(Dimension);
+     CallInst *Fn =
+         CreateCall(FnPreserveArrayAccessIndex, {Base, DimV, LastIndexV});
++    if (DbgInfo)
++      Fn->setMetadata(LLVMContext::MD_preserve_access_index, DbgInfo);
+ 
+     return Fn;
+   }
+@@ -2493,7 +2500,8 @@ public:
+     Value *DIIndex = getInt32(FieldIndex);
+     CallInst *Fn =
+         CreateCall(FnPreserveUnionAccessIndex, {Base, DIIndex});
+-    Fn->setMetadata(LLVMContext::MD_preserve_access_index, DbgInfo);
++    if (DbgInfo)
++      Fn->setMetadata(LLVMContext::MD_preserve_access_index, DbgInfo);
+ 
+     return Fn;
+   }
+@@ -2516,7 +2524,8 @@ public:
+     Value *DIIndex = getInt32(FieldIndex);
+     CallInst *Fn = CreateCall(FnPreserveStructAccessIndex,
+                               {Base, GEPIndex, DIIndex});
+-    Fn->setMetadata(LLVMContext::MD_preserve_access_index, DbgInfo);
++    if (DbgInfo)
++      Fn->setMetadata(LLVMContext::MD_preserve_access_index, DbgInfo);
+ 
+     return Fn;
+   }
+diff --git a/llvm/test/CodeGen/BPF/CORE/intrinsic-array.ll b/llvm/test/CodeGen/BPF/CORE/intrinsic-array.ll
+index adbcb9f..fe2c196 100644
+--- a/llvm/test/CodeGen/BPF/CORE/intrinsic-array.ll
++++ b/llvm/test/CodeGen/BPF/CORE/intrinsic-array.ll
+@@ -14,7 +14,7 @@
+ define dso_local i32 @test(%struct.s* %arg) local_unnamed_addr #0 !dbg !7 {
+ entry:
+   call void @llvm.dbg.value(metadata %struct.s* %arg, metadata !17, metadata !DIExpression()), !dbg !18
+-  %0 = tail call %struct.s* @llvm.preserve.array.access.index.p0s_struct.ss.p0s_struct.ss(%struct.s* %arg, i32 0, i32 2), !dbg !19
++  %0 = tail call %struct.s* @llvm.preserve.array.access.index.p0s_struct.ss.p0s_struct.ss(%struct.s* %arg, i32 0, i32 2), !dbg !19, !llvm.preserve.access.index !11
+   %1 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.ss(%struct.s* %0, i32 1, i32 1), !dbg !19, !llvm.preserve.access.index !12
+   %2 = bitcast i32* %1 to i8*, !dbg !19
+   %call = tail call i32 @get_value(i8* %2) #4, !dbg !20
+-- 
+1.8.3.1
+
diff --git a/SOURCES/0001-CMake-Split-static-library-exports-into-their-own-ex.patch b/SOURCES/0001-CMake-Split-static-library-exports-into-their-own-ex.patch
new file mode 100644
index 0000000..e780c34
--- /dev/null
+++ b/SOURCES/0001-CMake-Split-static-library-exports-into-their-own-ex.patch
@@ -0,0 +1,66 @@
+From 8f6917ea11bd1bfbfe07f3577756d1c4abfdb916 Mon Sep 17 00:00:00 2001
+From: Tom Stellard <tstellar@redhat.com>
+Date: Fri, 6 Sep 2019 11:03:18 -0700
+Subject: [PATCH] CMake: Split static library exports into their own export
+ file
+
+---
+ llvm/cmake/modules/AddLLVM.cmake       | 6 +++++-
+ llvm/cmake/modules/CMakeLists.txt      | 3 +++
+ llvm/cmake/modules/LLVMConfig.cmake.in | 2 ++
+ 3 files changed, 10 insertions(+), 1 deletion(-)
+
+diff --git a/llvm/cmake/modules/AddLLVM.cmake b/llvm/cmake/modules/AddLLVM.cmake
+index 619e986..200fc45 100644
+--- a/llvm/cmake/modules/AddLLVM.cmake
++++ b/llvm/cmake/modules/AddLLVM.cmake
+@@ -691,7 +691,11 @@ macro(add_llvm_library name)
+       if(${name} IN_LIST LLVM_DISTRIBUTION_COMPONENTS OR
+           (in_llvm_libs AND "llvm-libraries" IN_LIST LLVM_DISTRIBUTION_COMPONENTS) OR
+           NOT LLVM_DISTRIBUTION_COMPONENTS)
+-        set(export_to_llvmexports EXPORT LLVMExports)
++        if (ARG_SHARED)
++          set(export_to_llvmexports EXPORT LLVMExports)
++        else()
++          set(export_to_llvmexports EXPORT LLVMStaticExports)
++        endif()
+         set_property(GLOBAL PROPERTY LLVM_HAS_EXPORTS True)
+       endif()
+ 
+diff --git a/llvm/cmake/modules/CMakeLists.txt b/llvm/cmake/modules/CMakeLists.txt
+index 9cf22b4..dc982d2 100644
+--- a/llvm/cmake/modules/CMakeLists.txt
++++ b/llvm/cmake/modules/CMakeLists.txt
+@@ -105,6 +105,7 @@ set(LLVM_CONFIG_BINARY_DIR "\${LLVM_INSTALL_PREFIX}")
+ set(LLVM_CONFIG_TOOLS_BINARY_DIR "\${LLVM_INSTALL_PREFIX}/bin")
+ set(LLVM_CONFIG_EXPORTS_FILE "\${LLVM_CMAKE_DIR}/LLVMExports.cmake")
+ set(LLVM_CONFIG_EXPORTS "${LLVM_EXPORTS}")
++set(LLVM_CONFIG_STATIC_EXPORTS_FILE "\${LLVM_CMAKE_DIR}/LLVMStaticExports.cmake")
+ configure_file(
+   LLVMConfig.cmake.in
+   ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/LLVMConfig.cmake
+@@ -121,6 +122,8 @@ if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
+   if(llvm_has_exports)
+     install(EXPORT LLVMExports DESTINATION ${LLVM_INSTALL_PACKAGE_DIR}
+             COMPONENT cmake-exports)
++    install(EXPORT LLVMStaticExports DESTINATION ${LLVM_INSTALL_PACKAGE_DIR}
++            COMPONENT cmake-exports)
+   endif()
+ 
+   install(FILES
+diff --git a/llvm/cmake/modules/LLVMConfig.cmake.in b/llvm/cmake/modules/LLVMConfig.cmake.in
+index 536031f..6ef54a0 100644
+--- a/llvm/cmake/modules/LLVMConfig.cmake.in
++++ b/llvm/cmake/modules/LLVMConfig.cmake.in
+@@ -89,6 +89,8 @@ if(NOT TARGET LLVMSupport)
+   set(LLVM_EXPORTED_TARGETS "@LLVM_CONFIG_EXPORTS@")
+   include("@LLVM_CONFIG_EXPORTS_FILE@")
+   @llvm_config_include_buildtree_only_exports@
++
++  include("@LLVM_CONFIG_STATIC_EXPORTS_FILE@" OPTIONAL)
+ endif()
+ 
+ # By creating intrinsics_gen here, subprojects that depend on LLVM's
+-- 
+1.8.3.1
+
diff --git a/SOURCES/0001-CMake-Split-test-binary-exports-into-their-own-expor.patch b/SOURCES/0001-CMake-Split-test-binary-exports-into-their-own-expor.patch
new file mode 100644
index 0000000..a3801ff
--- /dev/null
+++ b/SOURCES/0001-CMake-Split-test-binary-exports-into-their-own-expor.patch
@@ -0,0 +1,65 @@
+From 9d496e978f59e153bb76e92229d5a524d92dee04 Mon Sep 17 00:00:00 2001
+From: Tom Stellard <tstellar@redhat.com>
+Date: Tue, 10 Sep 2019 13:33:48 -0700
+Subject: [PATCH] CMake: Split test binary exports into their own export file
+
+---
+ llvm/cmake/modules/AddLLVM.cmake       | 7 ++++++-
+ llvm/cmake/modules/CMakeLists.txt      | 3 +++
+ llvm/cmake/modules/LLVMConfig.cmake.in | 1 +
+ 3 files changed, 10 insertions(+), 1 deletion(-)
+
+diff --git a/llvm/cmake/modules/AddLLVM.cmake b/llvm/cmake/modules/AddLLVM.cmake
+index 200fc45..9eec7a7 100644
+--- a/llvm/cmake/modules/AddLLVM.cmake
++++ b/llvm/cmake/modules/AddLLVM.cmake
+@@ -953,7 +953,12 @@ macro(add_llvm_utility name)
+       set(export_to_llvmexports)
+       if (${name} IN_LIST LLVM_DISTRIBUTION_COMPONENTS OR
+           NOT LLVM_DISTRIBUTION_COMPONENTS)
+-        set(export_to_llvmexports EXPORT LLVMExports)
++        if (${name} STREQUAL "not" OR ${name} STREQUAL "count" OR
++            ${name} STREQUAL "yaml-bench" OR ${name} STREQUAL "lli-child-target")
++          set(export_to_llvmexports EXPORT LLVMTestExports)
++        else()
++          set(export_to_llvmexports EXPORT LLVMExports)
++        endif()
+         set_property(GLOBAL PROPERTY LLVM_HAS_EXPORTS True)
+       endif()
+ 
+diff --git a/llvm/cmake/modules/CMakeLists.txt b/llvm/cmake/modules/CMakeLists.txt
+index dc982d2..c861f45 100644
+--- a/llvm/cmake/modules/CMakeLists.txt
++++ b/llvm/cmake/modules/CMakeLists.txt
+@@ -106,6 +106,7 @@ set(LLVM_CONFIG_TOOLS_BINARY_DIR "\${LLVM_INSTALL_PREFIX}/bin")
+ set(LLVM_CONFIG_EXPORTS_FILE "\${LLVM_CMAKE_DIR}/LLVMExports.cmake")
+ set(LLVM_CONFIG_EXPORTS "${LLVM_EXPORTS}")
+ set(LLVM_CONFIG_STATIC_EXPORTS_FILE "\${LLVM_CMAKE_DIR}/LLVMStaticExports.cmake")
++set(LLVM_CONFIG_TEST_EXPORTS_FILE "\${LLVM_CMAKE_DIR}/LLVMTestExports.cmake")
+ configure_file(
+   LLVMConfig.cmake.in
+   ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/LLVMConfig.cmake
+@@ -124,6 +125,8 @@ if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
+             COMPONENT cmake-exports)
+     install(EXPORT LLVMStaticExports DESTINATION ${LLVM_INSTALL_PACKAGE_DIR}
+             COMPONENT cmake-exports)
++    install(EXPORT LLVMTestExports DESTINATION ${LLVM_INSTALL_PACKAGE_DIR}
++            COMPONENT cmake-exports)
+   endif()
+ 
+   install(FILES
+diff --git a/llvm/cmake/modules/LLVMConfig.cmake.in b/llvm/cmake/modules/LLVMConfig.cmake.in
+index 6ef54a0..d81b09a 100644
+--- a/llvm/cmake/modules/LLVMConfig.cmake.in
++++ b/llvm/cmake/modules/LLVMConfig.cmake.in
+@@ -91,6 +91,7 @@ if(NOT TARGET LLVMSupport)
+   @llvm_config_include_buildtree_only_exports@
+ 
+   include("@LLVM_CONFIG_STATIC_EXPORTS_FILE@" OPTIONAL)
++  include("@LLVM_CONFIG_TEST_EXPORTS_FILE@" OPTIONAL)
+ endif()
+ 
+ # By creating intrinsics_gen here, subprojects that depend on LLVM's
+-- 
+1.8.3.1
+
diff --git a/SOURCES/0001-Deactivate-markdown-doc.patch b/SOURCES/0001-Deactivate-markdown-doc.patch
index 87e3a46..d9e402a 100644
--- a/SOURCES/0001-Deactivate-markdown-doc.patch
+++ b/SOURCES/0001-Deactivate-markdown-doc.patch
@@ -1,14 +1,14 @@
-From eeb9da2ece9a58448c213b900090b32e6d303bff Mon Sep 17 00:00:00 2001
+From e7bc515182199764b17ab3f5e22047342f9c7514 Mon Sep 17 00:00:00 2001
 From: serge-sans-paille <sguelton@redhat.com>
 Date: Thu, 13 Jun 2019 07:58:59 +0000
-Subject: [PATCH 4/4] Deactivate markdown doc
+Subject: [PATCH] Deactivate markdown doc
 
 ---
  llvm/docs/conf.py | 4 ++--
  1 file changed, 2 insertions(+), 2 deletions(-)
 
 diff --git a/llvm/docs/conf.py b/llvm/docs/conf.py
-index 7fdcb3d2f52..501b48b540d 100644
+index 4a52df8..340cd07 100644
 --- a/llvm/docs/conf.py
 +++ b/llvm/docs/conf.py
 @@ -32,9 +32,9 @@ extensions = ['sphinx.ext.intersphinx', 'sphinx.ext.todo']
@@ -24,5 +24,5 @@ index 7fdcb3d2f52..501b48b540d 100644
  # The encoding of source files.
  #source_encoding = 'utf-8-sig'
 -- 
-2.20.1
+1.8.3.1
 
diff --git a/SOURCES/0001-Docs-llvm-strip-Add-help-text-to-llvm-strip-rst-doc.patch b/SOURCES/0001-Docs-llvm-strip-Add-help-text-to-llvm-strip-rst-doc.patch
new file mode 100644
index 0000000..0be06dd
--- /dev/null
+++ b/SOURCES/0001-Docs-llvm-strip-Add-help-text-to-llvm-strip-rst-doc.patch
@@ -0,0 +1,223 @@
+From 8987da9a2cac6c5bd39ba100ffd1aaede94dc6a0 Mon Sep 17 00:00:00 2001
+From: Michael Pozulp <pozulp.llvm@gmail.com>
+Date: Fri, 9 Aug 2019 19:10:55 +0000
+Subject: [PATCH] [Docs][llvm-strip] Add help text to llvm-strip rst doc
+
+Summary: Addresses https://bugs.llvm.org/show_bug.cgi?id=42383
+
+Reviewers: jhenderson, alexshap, rupprecht
+
+Reviewed By: jhenderson
+
+Subscribers: wolfgangp, jakehehrlich, llvm-commits
+
+Tags: #llvm
+
+Differential Revision: https://reviews.llvm.org/D65384
+
+llvm-svn: 368464
+---
+ llvm/docs/CommandGuide/llvm-strip.md  |  16 ----
+ llvm/docs/CommandGuide/llvm-strip.rst | 167 ++++++++++++++++++++++++++++++++++
+ 2 files changed, 167 insertions(+), 16 deletions(-)
+ delete mode 100644 llvm/docs/CommandGuide/llvm-strip.md
+ create mode 100644 llvm/docs/CommandGuide/llvm-strip.rst
+
+diff --git a/llvm/docs/CommandGuide/llvm-strip.md b/llvm/docs/CommandGuide/llvm-strip.md
+deleted file mode 100644
+index dd6e859..0000000
+--- a/llvm/docs/CommandGuide/llvm-strip.md
++++ /dev/null
+@@ -1,16 +0,0 @@
+-# llvm-strip - object stripping tool
+-
+-## SYNOPSIS
+-
+-**llvm-strip** [*options*]
+-
+-## DESCRIPTION
+-
+-**llvm-strip** is a tool to strip sections and symbols from object files.
+-
+-The tool is still in active development, but in most scenarios it works as a
+-drop-in replacement for GNU's **strip**.
+-
+-## SEE ALSO
+-
+-[llvm-objcopy](llvm-objcopy.html)
+diff --git a/llvm/docs/CommandGuide/llvm-strip.rst b/llvm/docs/CommandGuide/llvm-strip.rst
+new file mode 100644
+index 0000000..6e02482
+--- /dev/null
++++ b/llvm/docs/CommandGuide/llvm-strip.rst
+@@ -0,0 +1,167 @@
++llvm-strip - object stripping tool
++==================================
++
++.. program:: llvm-strip
++
++SYNOPSIS
++--------
++
++:program:`llvm-strip` [*options*] *inputs...*
++
++DESCRIPTION
++-----------
++
++:program:`llvm-strip` is a tool to strip sections and symbols from object files.
++If no other stripping or remove options are specified, :option:`--strip-all`
++will be enabled by default.
++
++The input files are modified in-place. If "-" is specified for the input file,
++the input is read from the program's standard input stream.
++
++If the input is an archive, any requested operations will be applied to each
++archive member individually.
++
++The tool is still in active development, but in most scenarios it works as a
++drop-in replacement for GNU's :program:`strip`.
++
++GENERIC AND CROSS-PLATFORM OPTIONS
++----------------------------------
++
++The following options are either agnostic of the file format, or apply to
++multiple file formats.
++
++.. option:: --disable-deterministic-archives, -U
++
++ Use real values for UIDs, GIDs and timestamps when updating archive member
++ headers.
++
++.. option:: --discard-all, -x
++
++ Remove most local symbols from the output. Different file formats may limit
++ this to a subset of the local symbols. For example, file and section symbols in
++ ELF objects will not be discarded.
++
++.. option::  --enable-deterministic-archives, -D
++
++ Enable deterministic mode when stripping archives, i.e. use 0 for archive member
++ header UIDs, GIDs and timestamp fields. On by default.
++
++.. option:: --help, -h
++
++ Print a summary of command line options.
++
++.. option::  --no-strip-all
++
++ Disable --strip-all.
++
++.. option::  -o <file>
++
++ Write output to <file>. Multiple input files cannot be used in combination
++ with -o.
++
++.. option:: --regex
++
++ If specified, symbol and section names specified by other switches are treated
++ as extended POSIX regular expression patterns.
++
++.. option:: --remove-section <section>, -R
++
++ Remove the specified section from the output. Can be specified multiple times
++ to remove multiple sections simultaneously.
++
++.. option:: --strip-all-gnu
++
++ Remove all symbols, debug sections and relocations from the output. This option
++ is equivalent to GNU :program:`strip`'s ``--strip-all`` switch.
++
++.. option:: --strip-all, -S
++
++ For ELF objects, remove from the output all symbols and non-alloc sections not
++ within segments, except for .gnu.warning sections and the section name table.
++
++ For COFF objects, remove all symbols, debug sections, and relocations from the
++ output.
++
++.. option:: --strip-debug, -g
++
++ Remove all debug sections.
++
++.. option:: --strip-sections
++
++ Remove all section headers and all sections not in segments.
++
++.. option:: --strip-symbol <symbol>, -N
++
++ Remove all symbols named ``<symbol>`` from the output. Can be specified
++ multiple times to remove multiple symbols.
++
++.. option:: --strip-unneeded
++
++ Remove all local or undefined symbols that are not required by relocations.
++
++.. option:: --version, -V
++
++  Display the version of this program.
++
++COFF-SPECIFIC OPTIONS
++---------------------
++
++The following options are implemented only for COFF objects. If used with other
++objects, :program:`llvm-strip` will either emit an error or silently ignore
++them.
++
++.. option:: --only-keep-debug
++
++ Remove the contents of non-debug sections from the output, but keep the section
++ headers.
++
++ELF-SPECIFIC OPTIONS
++--------------------
++
++The following options are implemented only for ELF objects. If used with other
++objects, :program:`llvm-strip` will either emit an error or silently ignore
++them.
++
++.. option:: --allow-broken-links
++
++ Allow llvm-strip to remove sections even if it would leave invalid section
++ references. Any invalid sh_link fields will be set to zero.
++
++.. option:: --discard-locals, -X
++
++ Remove local symbols starting with ".L" from the output.
++
++.. option:: --keep-file-symbols
++
++ Keep symbols of type `STT_FILE`, even if they would otherwise be stripped.
++
++ .. option:: --keep-section <section>
++
++ When removing sections from the output, do not remove sections named
++ ``<section>``. Can be specified multiple times to keep multiple sections.
++
++.. option:: --keep-symbol <symbol>, -K
++
++ Do not remove symbols named ``<symbol>``. Can be specified multiple times to
++ keep multiple symbols.
++
++.. option::  --preserve-dates, -p
++
++ Preserve access and modification timestamps.
++
++
++EXIT STATUS
++-----------
++
++:program:`llvm-strip` exits with a non-zero exit code if there is an error.
++Otherwise, it exits with code 0.
++
++BUGS
++----
++
++To report bugs, please visit <http://llvm.org/bugs/>.
++
++SEE ALSO
++--------
++
++:manpage:`llvm-objcopy(1)`
+-- 
+1.8.3.1
+
diff --git a/SOURCES/0001-Filter-out-cxxflags-not-supported-by-clang.patch b/SOURCES/0001-Filter-out-cxxflags-not-supported-by-clang.patch
index e2f3b26..1351d2f 100644
--- a/SOURCES/0001-Filter-out-cxxflags-not-supported-by-clang.patch
+++ b/SOURCES/0001-Filter-out-cxxflags-not-supported-by-clang.patch
@@ -1,82 +1,28 @@
-From e491bb836e530585e4d278b82725e4cefdd14abc Mon Sep 17 00:00:00 2001
-From: serge-sans-paille <sguelton@redhat.com>
-Date: Thu, 13 Jun 2019 07:55:37 +0000
-Subject: [PATCH 3/4] Filter-out-cxxflags-not-supported-by-clang
+From d15c835028bcc72a8695d047f0acaa530aa54716 Mon Sep 17 00:00:00 2001
+From: Tom Stellard <tstellar@redhat.com>
+Date: Wed, 31 Jul 2019 20:43:42 -0700
+Subject: [PATCH] Filter out cxxflags not supported by clang
 
 ---
- llvm/cmake/modules/AddLLVM.cmake       | 6 +++++-
- llvm/cmake/modules/CMakeLists.txt      | 3 +++
- llvm/cmake/modules/LLVMConfig.cmake.in | 2 ++
- llvm/tools/llvm-config/CMakeLists.txt  | 4 ++++
- 4 files changed, 14 insertions(+), 1 deletion(-)
+ llvm/tools/llvm-config/CMakeLists.txt | 4 ++++
+ 1 file changed, 4 insertions(+)
 
-diff --git a/llvm/cmake/modules/AddLLVM.cmake b/llvm/cmake/modules/AddLLVM.cmake
-index 1a417447278..bb10f20cdd6 100644
---- a/llvm/cmake/modules/AddLLVM.cmake
-+++ b/llvm/cmake/modules/AddLLVM.cmake
-@@ -664,7 +664,11 @@ macro(add_llvm_library name)
- 
-       if(${name} IN_LIST LLVM_DISTRIBUTION_COMPONENTS OR
-           NOT LLVM_DISTRIBUTION_COMPONENTS)
--        set(export_to_llvmexports EXPORT LLVMExports)
-+        if (ARG_SHARED)
-+          set(export_to_llvmexports EXPORT LLVMExports)
-+        else()
-+          set(export_to_llvmexports EXPORT LLVMStaticExports)
-+        endif()
-         set_property(GLOBAL PROPERTY LLVM_HAS_EXPORTS True)
-       endif()
- 
-diff --git a/llvm/cmake/modules/CMakeLists.txt b/llvm/cmake/modules/CMakeLists.txt
-index f5cc0006fa0..6605dc729c2 100644
---- a/llvm/cmake/modules/CMakeLists.txt
-+++ b/llvm/cmake/modules/CMakeLists.txt
-@@ -97,6 +97,7 @@ set(LLVM_CONFIG_BINARY_DIR "\${LLVM_INSTALL_PREFIX}")
- set(LLVM_CONFIG_TOOLS_BINARY_DIR "\${LLVM_INSTALL_PREFIX}/bin")
- set(LLVM_CONFIG_EXPORTS_FILE "\${LLVM_CMAKE_DIR}/LLVMExports.cmake")
- set(LLVM_CONFIG_EXPORTS "${LLVM_EXPORTS}")
-+set(LLVM_CONFIG_STATIC_EXPORTS_FILE "\${LLVM_CMAKE_DIR}/LLVMStaticExports.cmake")
- configure_file(
-   LLVMConfig.cmake.in
-   ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/LLVMConfig.cmake
-@@ -113,6 +114,8 @@ if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
-   if(llvm_has_exports)
-     install(EXPORT LLVMExports DESTINATION ${LLVM_INSTALL_PACKAGE_DIR}
-             COMPONENT cmake-exports)
-+    install(EXPORT LLVMStaticExports DESTINATION ${LLVM_INSTALL_PACKAGE_DIR}
-+            COMPONENT cmake-exports)
-   endif()
- 
-   install(FILES
-diff --git a/llvm/cmake/modules/LLVMConfig.cmake.in b/llvm/cmake/modules/LLVMConfig.cmake.in
-index 7ca06381d90..44d042c9b11 100644
---- a/llvm/cmake/modules/LLVMConfig.cmake.in
-+++ b/llvm/cmake/modules/LLVMConfig.cmake.in
-@@ -84,6 +84,8 @@ if(NOT TARGET LLVMSupport)
-   set(LLVM_EXPORTED_TARGETS "@LLVM_CONFIG_EXPORTS@")
-   include("@LLVM_CONFIG_EXPORTS_FILE@")
-   @llvm_config_include_buildtree_only_exports@
-+
-+  include("@LLVM_CONFIG_STATIC_EXPORTS_FILE@" OPTIONAL)
- endif()
- 
- # By creating intrinsics_gen here, subprojects that depend on LLVM's
 diff --git a/llvm/tools/llvm-config/CMakeLists.txt b/llvm/tools/llvm-config/CMakeLists.txt
-index a7db17386fb..8a796d03b5a 100644
+index 8e97a10..9b9b7d1 100644
 --- a/llvm/tools/llvm-config/CMakeLists.txt
 +++ b/llvm/tools/llvm-config/CMakeLists.txt
-@@ -42,7 +42,11 @@ set(LLVM_SRC_ROOT ${LLVM_MAIN_SRC_DIR})
+@@ -43,7 +43,11 @@ set(LLVM_SRC_ROOT ${LLVM_MAIN_SRC_DIR})
  set(LLVM_OBJ_ROOT ${LLVM_BINARY_DIR})
  set(LLVM_CPPFLAGS "${LLVM_DEFINITIONS}")
  set(LLVM_CFLAGS "${LLVM_C_STD_FLAG} ${LLVM_DEFINITIONS}")
 +STRING(REGEX REPLACE "-mcet" "" LLVM_CFLAGS ${LLVM_CFLAGS})
 +STRING(REGEX REPLACE "-fcf-protection" "" LLVM_CFLAGS ${LLVM_CFLAGS})
- set(LLVM_CXXFLAGS "${LLVM_CXX_STD_FLAG} ${COMPILE_FLAGS} ${LLVM_DEFINITIONS}")
+ set(LLVM_CXXFLAGS "${LLVM_CXX_STD_FLAG} ${LLVM_CXX_STDLIB_FLAG} ${COMPILE_FLAGS} ${LLVM_DEFINITIONS}")
 +STRING(REGEX REPLACE "-mcet" "" LLVM_CXXFLAGS ${LLVM_CXXFLAGS})
 +STRING(REGEX REPLACE "-fcf-protection" "" LLVM_CXXFLAGS ${LLVM_CXXFLAGS})
  set(LLVM_BUILD_SYSTEM cmake)
  set(LLVM_HAS_RTTI ${LLVM_CONFIG_HAS_RTTI})
  set(LLVM_DYLIB_VERSION "${LLVM_VERSION_MAJOR}${LLVM_VERSION_SUFFIX}")
 -- 
-2.20.1
+1.8.3.1
 
diff --git a/SOURCES/0001-Pass-target-to-gold-linker-to-avoid-faliures-on-i686.patch b/SOURCES/0001-Pass-target-to-gold-linker-to-avoid-faliures-on-i686.patch
new file mode 100644
index 0000000..e8dd323
--- /dev/null
+++ b/SOURCES/0001-Pass-target-to-gold-linker-to-avoid-faliures-on-i686.patch
@@ -0,0 +1,34 @@
+From f0762684457a883b6813b48c98a1e94e377bc06b Mon Sep 17 00:00:00 2001
+From: Tom Stellard <tstellar@redhat.com>
+Date: Wed, 28 Aug 2019 19:31:21 -0700
+Subject: [PATCH] Pass target to gold linker to avoid faliures on i686
+
+---
+ llvm/test/tools/gold/X86/linkonce_odr_unnamed_addr.ll | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/llvm/test/tools/gold/X86/linkonce_odr_unnamed_addr.ll b/llvm/test/tools/gold/X86/linkonce_odr_unnamed_addr.ll
+index 525bf2d..01291bd 100644
+--- a/llvm/test/tools/gold/X86/linkonce_odr_unnamed_addr.ll
++++ b/llvm/test/tools/gold/X86/linkonce_odr_unnamed_addr.ll
+@@ -3,7 +3,7 @@
+ 
+ ; RUN: opt -module-summary %s -o %t.o
+ ; RUN: opt -module-summary %p/Inputs/linkonce_odr_unnamed_addr.ll -o %t2.o
+-; RUN: %gold -plugin %llvmshlibdir/LLVMgold%shlibext \
++; RUN: %gold -m elf_x86_64 -plugin %llvmshlibdir/LLVMgold%shlibext \
+ ; RUN:    --plugin-opt=save-temps \
+ ; RUN:    %t.o %t2.o -o %t3.o
+ ; RUN: llvm-dis %t.o.1.promote.bc -o - | FileCheck %s
+@@ -11,7 +11,7 @@
+ ; Now test when one module is a native object. In that case we must be
+ ; conservative and not auto hide.
+ ; RUN: llc %p/Inputs/linkonce_odr_unnamed_addr.ll -o %t2native.o -filetype=obj
+-; RUN: %gold -plugin %llvmshlibdir/LLVMgold%shlibext \
++; RUN: %gold -m elf_x86_64 -plugin %llvmshlibdir/LLVMgold%shlibext \
+ ; RUN:    --plugin-opt=save-temps \
+ ; RUN:    %t.o %t2native.o -o %t3.o
+ ; RUN: llvm-dis %t.o.1.promote.bc -o - | FileCheck %s --check-prefix=NOSUMMARY
+-- 
+1.8.3.1
+
diff --git a/SOURCES/0001-Revert-SCEV-add-no-wrap-flag-for-SCEVAddExpr.patch b/SOURCES/0001-Revert-SCEV-add-no-wrap-flag-for-SCEVAddExpr.patch
new file mode 100644
index 0000000..caf774c
--- /dev/null
+++ b/SOURCES/0001-Revert-SCEV-add-no-wrap-flag-for-SCEVAddExpr.patch
@@ -0,0 +1,113 @@
+From 58e8c793d0e43150a6452e971a32d7407a8a7401 Mon Sep 17 00:00:00 2001
+From: Tim Northover <tnorthover@apple.com>
+Date: Mon, 30 Sep 2019 07:46:52 +0000
+Subject: [PATCH] Revert "[SCEV] add no wrap flag for SCEVAddExpr."
+
+This reverts r366419 because the analysis performed is within the context of
+the loop and it's only valid to add wrapping flags to "global" expressions if
+they're always correct.
+
+llvm-svn: 373184
+---
+ llvm/lib/Analysis/ScalarEvolution.cpp              | 2 +-
+ llvm/test/Analysis/ScalarEvolution/limit-depth.ll  | 2 +-
+ llvm/test/Analysis/ScalarEvolution/nsw.ll          | 2 +-
+ llvm/test/Analysis/ScalarEvolution/trip-count12.ll | 2 +-
+ llvm/test/Analysis/ScalarEvolution/trip-count9.ll  | 8 ++++----
+ 5 files changed, 8 insertions(+), 8 deletions(-)
+
+diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
+index 354ae05bb841..c29fc5dbccfb 100644
+--- a/llvm/lib/Analysis/ScalarEvolution.cpp
++++ b/llvm/lib/Analysis/ScalarEvolution.cpp
+@@ -4992,7 +4992,7 @@ const SCEV *ScalarEvolution::createSimpleAffineAddRec(PHINode *PN,
+   // overflow.
+   if (auto *BEInst = dyn_cast<Instruction>(BEValueV))
+     if (isLoopInvariant(Accum, L) && isAddRecNeverPoison(BEInst, L))
+-      (void)getAddRecExpr(getAddExpr(StartVal, Accum, Flags), Accum, L, Flags);
++      (void)getAddRecExpr(getAddExpr(StartVal, Accum), Accum, L, Flags);
+ 
+   return PHISCEV;
+ }
+diff --git a/llvm/test/Analysis/ScalarEvolution/limit-depth.ll b/llvm/test/Analysis/ScalarEvolution/limit-depth.ll
+index db68a4f84c91..6fdf8c5df974 100644
+--- a/llvm/test/Analysis/ScalarEvolution/limit-depth.ll
++++ b/llvm/test/Analysis/ScalarEvolution/limit-depth.ll
+@@ -46,7 +46,7 @@ define void @test_mul(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f) {
+ define void @test_sext(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f) {
+ ; CHECK-LABEL: @test_sext
+ ; CHECK:        %se2 = sext i64 %iv2.inc to i128
+-; CHECK-NEXT:   -->  {(1 + (sext i64 {(sext i32 (1 + %a)<nsw> to i64),+,1}<nsw><%loop> to i128))<nsw>,+,1}<nsw><%loop2>
++; CHECK-NEXT:   -->  {(1 + (sext i64 {(sext i32 (1 + %a) to i64),+,1}<nsw><%loop> to i128))<nsw>,+,1}<nsw><%loop2>
+ entry:
+   br label %loop
+ 
+diff --git a/llvm/test/Analysis/ScalarEvolution/nsw.ll b/llvm/test/Analysis/ScalarEvolution/nsw.ll
+index 69427368625d..ca24f9d4a04b 100644
+--- a/llvm/test/Analysis/ScalarEvolution/nsw.ll
++++ b/llvm/test/Analysis/ScalarEvolution/nsw.ll
+@@ -163,7 +163,7 @@ bb5:                                              ; preds = %bb2
+ declare void @f(i32)
+ 
+ ; CHECK-LABEL: nswnowrap
+-; CHECK: --> {(1 + %v)<nsw>,+,1}<nsw><%for.body>{{ U: [^ ]+ S: [^ ]+}}{{ *}}Exits: (2 + %v)
++; CHECK: --> {(1 + %v)<nsw>,+,1}<nsw><%for.body>{{ U: [^ ]+ S: [^ ]+}}{{ *}}Exits: (1 + ((1 + %v)<nsw> smax %v))
+ define void @nswnowrap(i32 %v, i32* %buf) {
+ entry:
+   %add = add nsw i32 %v, 1
+diff --git a/llvm/test/Analysis/ScalarEvolution/trip-count12.ll b/llvm/test/Analysis/ScalarEvolution/trip-count12.ll
+index 5e7d72d5e4f3..d0086ee2e6ac 100644
+--- a/llvm/test/Analysis/ScalarEvolution/trip-count12.ll
++++ b/llvm/test/Analysis/ScalarEvolution/trip-count12.ll
+@@ -1,7 +1,7 @@
+ ; RUN: opt < %s -analyze -scalar-evolution | FileCheck %s
+ 
+ ; CHECK: Determining loop execution counts for: @test
+-; CHECK: Loop %for.body: backedge-taken count is ((-2 + %len)<nsw> /u 2)
++; CHECK: Loop %for.body: backedge-taken count is ((-2 + %len) /u 2)
+ ; CHECK: Loop %for.body: max backedge-taken count is 1073741823
+ 
+ define zeroext i16 @test(i16* nocapture %p, i32 %len) nounwind readonly {
+diff --git a/llvm/test/Analysis/ScalarEvolution/trip-count9.ll b/llvm/test/Analysis/ScalarEvolution/trip-count9.ll
+index c0a1d12fa00e..9a080b34743f 100644
+--- a/llvm/test/Analysis/ScalarEvolution/trip-count9.ll
++++ b/llvm/test/Analysis/ScalarEvolution/trip-count9.ll
+@@ -179,7 +179,7 @@ exit:
+ }
+ 
+ ; CHECK: Determining loop execution counts for: @nsw_startx
+-; CHECK: Loop %loop: backedge-taken count is (-1 + (-1 * %x) + ((1 + %x)<nsw> smax %n))
++; CHECK: Loop %loop: backedge-taken count is (-1 + (-1 * %x) + ((1 + %x) smax %n))
+ ; CHECK: Loop %loop: max backedge-taken count is -1
+ define void @nsw_startx(i4 %n, i4 %x) {
+ entry:
+@@ -195,7 +195,7 @@ exit:
+ }
+ 
+ ; CHECK: Determining loop execution counts for: @nsw_startx_step2
+-; CHECK: Loop %loop: backedge-taken count is ((-1 + (-1 * %x) + ((2 + %x)<nsw> smax %n)) /u 2)
++; CHECK: Loop %loop: backedge-taken count is ((-1 + (-1 * %x) + ((2 + %x) smax %n)) /u 2)
+ ; CHECK: Loop %loop: max backedge-taken count is 7
+ define void @nsw_startx_step2(i4 %n, i4 %x) {
+ entry:
+@@ -381,7 +381,7 @@ exit:
+ }
+ 
+ ; CHECK: Determining loop execution counts for: @even_nsw_startx
+-; CHECK: Loop %loop: backedge-taken count is (-1 + (-1 * %x) + ((1 + %x)<nsw> smax (2 * %n)))
++; CHECK: Loop %loop: backedge-taken count is (-1 + (-1 * %x) + ((1 + %x) smax (2 * %n)))
+ ; CHECK: Loop %loop: max backedge-taken count is -2
+ define void @even_nsw_startx(i4 %n, i4 %x) {
+ entry:
+@@ -398,7 +398,7 @@ exit:
+ }
+ 
+ ; CHECK: Determining loop execution counts for: @even_nsw_startx_step2
+-; CHECK: Loop %loop: backedge-taken count is ((-1 + (-1 * %x) + ((2 + %x)<nsw> smax (2 * %n))) /u 2)
++; CHECK: Loop %loop: backedge-taken count is ((-1 + (-1 * %x) + ((2 + %x) smax (2 * %n))) /u 2)
+ ; CHECK: Loop %loop: max backedge-taken count is 7
+ define void @even_nsw_startx_step2(i4 %n, i4 %x) {
+ entry:
+-- 
+2.24.1
+
diff --git a/SOURCES/0001-Selectively-disable-threading-from-gold.patch b/SOURCES/0001-Selectively-disable-threading-from-gold.patch
deleted file mode 100644
index ddeadec..0000000
--- a/SOURCES/0001-Selectively-disable-threading-from-gold.patch
+++ /dev/null
@@ -1,381 +0,0 @@
-From 5fd2c900e90445c6efb7b97f8c663e588bcab81b Mon Sep 17 00:00:00 2001
-From: serge-sans-paille <sguelton@redhat.com>
-Date: Tue, 2 Jul 2019 09:25:52 +0000
-Subject: [PATCH] Selectively disable threading from gold
-
-Related: rhbz#1636479
----
- llvm/include/llvm/LTO/LTO.h            |   3 +
- llvm/include/llvm/LTO/LTOBackend.h     |   3 +
- llvm/include/llvm/Support/ThreadPool.h |   7 ++
- llvm/lib/LTO/LTO.cpp                   | 134 ++++++++++++++++++++++++-
- llvm/lib/LTO/LTOBackend.cpp            |  48 ++++++++-
- llvm/lib/Support/ThreadPool.cpp        |   6 +-
- llvm/tools/gold/gold-plugin.cpp        |   7 +-
- 7 files changed, 197 insertions(+), 11 deletions(-)
-
-diff --git a/llvm/include/llvm/LTO/LTO.h b/llvm/include/llvm/LTO/LTO.h
-index 534d9b6f3f2..9dfda126540 100644
---- a/llvm/include/llvm/LTO/LTO.h
-+++ b/llvm/include/llvm/LTO/LTO.h
-@@ -212,6 +212,7 @@ typedef std::function<std::unique_ptr<ThinBackendProc>(
- 
- /// This ThinBackend runs the individual backend jobs in-process.
- ThinBackend createInProcessThinBackend(unsigned ParallelismLevel);
-+ThinBackend createInProcessThinBackendNoThread(unsigned ParallelismLevel);
- 
- /// This ThinBackend writes individual module indexes to files, instead of
- /// running the individual backend jobs. This backend is for distributed builds
-@@ -281,6 +282,7 @@ public:
-   /// The client will receive at most one callback (via either AddStream or
-   /// Cache) for each task identifier.
-   Error run(AddStreamFn AddStream, NativeObjectCache Cache = nullptr);
-+  Error runNoThread(AddStreamFn AddStream, NativeObjectCache Cache = nullptr);
- 
- private:
-   Config Conf;
-@@ -397,6 +399,7 @@ private:
-                    const SymbolResolution *&ResI, const SymbolResolution *ResE);
- 
-   Error runRegularLTO(AddStreamFn AddStream);
-+  Error runRegularLTONoThread(AddStreamFn AddStream);
-   Error runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache);
- 
-   mutable bool CalledGetMaxTasks = false;
-diff --git a/llvm/include/llvm/LTO/LTOBackend.h b/llvm/include/llvm/LTO/LTOBackend.h
-index d4743f6940f..2d6461fa82e 100644
---- a/llvm/include/llvm/LTO/LTOBackend.h
-+++ b/llvm/include/llvm/LTO/LTOBackend.h
-@@ -39,6 +39,9 @@ namespace lto {
- Error backend(Config &C, AddStreamFn AddStream,
-               unsigned ParallelCodeGenParallelismLevel,
-               std::unique_ptr<Module> M, ModuleSummaryIndex &CombinedIndex);
-+Error backendNoThread(Config &C, AddStreamFn AddStream,
-+              unsigned ParallelCodeGenParallelismLevel,
-+              std::unique_ptr<Module> M, ModuleSummaryIndex &CombinedIndex);
- 
- /// Runs a ThinLTO backend.
- Error thinBackend(Config &C, unsigned Task, AddStreamFn AddStream, Module &M,
-diff --git a/llvm/include/llvm/Support/ThreadPool.h b/llvm/include/llvm/Support/ThreadPool.h
-index 4fdbd528b21..60ea5097114 100644
---- a/llvm/include/llvm/Support/ThreadPool.h
-+++ b/llvm/include/llvm/Support/ThreadPool.h
-@@ -98,4 +98,11 @@ private:
- };
- }
- 
-+#ifndef ThreadPool
-+#undef LLVM_SUPPORT_THREAD_POOL_H
-+#define ThreadPool SequentialThreadPool
-+#include "llvm/Support/ThreadPool.h"
-+#undef ThreadPool
-+#endif
-+
- #endif // LLVM_SUPPORT_THREAD_POOL_H
-diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp
-index 3a955060dea..a7b4f45b18c 100644
---- a/llvm/lib/LTO/LTO.cpp
-+++ b/llvm/lib/LTO/LTO.cpp
-@@ -861,6 +861,58 @@ Error LTO::run(AddStreamFn AddStream, NativeObjectCache Cache) {
-   return Result;
- }
- 
-+Error LTO::runNoThread(AddStreamFn AddStream, NativeObjectCache Cache) {
-+  // Compute "dead" symbols, we don't want to import/export these!
-+  DenseSet<GlobalValue::GUID> GUIDPreservedSymbols;
-+  DenseMap<GlobalValue::GUID, PrevailingType> GUIDPrevailingResolutions;
-+  for (auto &Res : GlobalResolutions) {
-+    // Normally resolution have IR name of symbol. We can do nothing here
-+    // otherwise. See comments in GlobalResolution struct for more details.
-+    if (Res.second.IRName.empty())
-+      continue;
-+
-+    GlobalValue::GUID GUID = GlobalValue::getGUID(
-+        GlobalValue::dropLLVMManglingEscape(Res.second.IRName));
-+
-+    if (Res.second.VisibleOutsideSummary && Res.second.Prevailing)
-+      GUIDPreservedSymbols.insert(GlobalValue::getGUID(
-+          GlobalValue::dropLLVMManglingEscape(Res.second.IRName)));
-+
-+    GUIDPrevailingResolutions[GUID] =
-+        Res.second.Prevailing ? PrevailingType::Yes : PrevailingType::No;
-+  }
-+
-+  auto isPrevailing = [&](GlobalValue::GUID G) {
-+    auto It = GUIDPrevailingResolutions.find(G);
-+    if (It == GUIDPrevailingResolutions.end())
-+      return PrevailingType::Unknown;
-+    return It->second;
-+  };
-+  computeDeadSymbolsWithConstProp(ThinLTO.CombinedIndex, GUIDPreservedSymbols,
-+                                  isPrevailing, Conf.OptLevel > 0);
-+
-+  // Setup output file to emit statistics.
-+  std::unique_ptr<ToolOutputFile> StatsFile = nullptr;
-+  if (!Conf.StatsFile.empty()) {
-+    EnableStatistics(false);
-+    std::error_code EC;
-+    StatsFile =
-+        llvm::make_unique<ToolOutputFile>(Conf.StatsFile, EC, sys::fs::F_None);
-+    if (EC)
-+      return errorCodeToError(EC);
-+    StatsFile->keep();
-+  }
-+
-+  Error Result = runRegularLTONoThread(AddStream);
-+  if (!Result)
-+    Result = runThinLTO(AddStream, Cache);
-+
-+  if (StatsFile)
-+    PrintStatisticsJSON(StatsFile->os());
-+
-+  return Result;
-+}
-+
- Error LTO::runRegularLTO(AddStreamFn AddStream) {
-   for (auto &M : RegularLTO.ModsWithSummaries)
-     if (Error Err = linkRegularLTO(std::move(M),
-@@ -928,6 +980,73 @@ Error LTO::runRegularLTO(AddStreamFn AddStream) {
-                  std::move(RegularLTO.CombinedModule), ThinLTO.CombinedIndex);
- }
- 
-+Error LTO::runRegularLTONoThread(AddStreamFn AddStream) {
-+  for (auto &M : RegularLTO.ModsWithSummaries)
-+    if (Error Err = linkRegularLTO(std::move(M),
-+                                   /*LivenessFromIndex=*/true))
-+      return Err;
-+
-+  // Make sure commons have the right size/alignment: we kept the largest from
-+  // all the prevailing when adding the inputs, and we apply it here.
-+  const DataLayout &DL = RegularLTO.CombinedModule->getDataLayout();
-+  for (auto &I : RegularLTO.Commons) {
-+    if (!I.second.Prevailing)
-+      // Don't do anything if no instance of this common was prevailing.
-+      continue;
-+    GlobalVariable *OldGV = RegularLTO.CombinedModule->getNamedGlobal(I.first);
-+    if (OldGV && DL.getTypeAllocSize(OldGV->getValueType()) == I.second.Size) {
-+      // Don't create a new global if the type is already correct, just make
-+      // sure the alignment is correct.
-+      OldGV->setAlignment(I.second.Align);
-+      continue;
-+    }
-+    ArrayType *Ty =
-+        ArrayType::get(Type::getInt8Ty(RegularLTO.Ctx), I.second.Size);
-+    auto *GV = new GlobalVariable(*RegularLTO.CombinedModule, Ty, false,
-+                                  GlobalValue::CommonLinkage,
-+                                  ConstantAggregateZero::get(Ty), "");
-+    GV->setAlignment(I.second.Align);
-+    if (OldGV) {
-+      OldGV->replaceAllUsesWith(ConstantExpr::getBitCast(GV, OldGV->getType()));
-+      GV->takeName(OldGV);
-+      OldGV->eraseFromParent();
-+    } else {
-+      GV->setName(I.first);
-+    }
-+  }
-+
-+  if (Conf.PreOptModuleHook &&
-+      !Conf.PreOptModuleHook(0, *RegularLTO.CombinedModule))
-+    return Error::success();
-+
-+  if (!Conf.CodeGenOnly) {
-+    for (const auto &R : GlobalResolutions) {
-+      if (!R.second.isPrevailingIRSymbol())
-+        continue;
-+      if (R.second.Partition != 0 &&
-+          R.second.Partition != GlobalResolution::External)
-+        continue;
-+
-+      GlobalValue *GV =
-+          RegularLTO.CombinedModule->getNamedValue(R.second.IRName);
-+      // Ignore symbols defined in other partitions.
-+      // Also skip declarations, which are not allowed to have internal linkage.
-+      if (!GV || GV->hasLocalLinkage() || GV->isDeclaration())
-+        continue;
-+      GV->setUnnamedAddr(R.second.UnnamedAddr ? GlobalValue::UnnamedAddr::Global
-+                                              : GlobalValue::UnnamedAddr::None);
-+      if (EnableLTOInternalization && R.second.Partition == 0)
-+        GV->setLinkage(GlobalValue::InternalLinkage);
-+    }
-+
-+    if (Conf.PostInternalizeModuleHook &&
-+        !Conf.PostInternalizeModuleHook(0, *RegularLTO.CombinedModule))
-+      return Error::success();
-+  }
-+  return backendNoThread(Conf, AddStream, RegularLTO.ParallelCodeGenParallelismLevel,
-+                 std::move(RegularLTO.CombinedModule), ThinLTO.CombinedIndex);
-+}
-+
- /// This class defines the interface to the ThinLTO backend.
- class lto::ThinBackendProc {
- protected:
-@@ -952,8 +1071,9 @@ public:
- };
- 
- namespace {
-+template<class ThreadEngine>
- class InProcessThinBackend : public ThinBackendProc {
--  ThreadPool BackendThreadPool;
-+  ThreadEngine BackendThreadPool;
-   AddStreamFn AddStream;
-   NativeObjectCache Cache;
-   std::set<GlobalValue::GUID> CfiFunctionDefs;
-@@ -1065,9 +1185,19 @@ ThinBackend lto::createInProcessThinBackend(unsigned ParallelismLevel) {
-   return [=](Config &Conf, ModuleSummaryIndex &CombinedIndex,
-              const StringMap<GVSummaryMapTy> &ModuleToDefinedGVSummaries,
-              AddStreamFn AddStream, NativeObjectCache Cache) {
--    return llvm::make_unique<InProcessThinBackend>(
-+    return llvm::make_unique<InProcessThinBackend<ThreadPool>>(
-+        Conf, CombinedIndex, ParallelismLevel, ModuleToDefinedGVSummaries,
-+        AddStream, Cache);
-+  };
-+}
-+ThinBackend lto::createInProcessThinBackendNoThread(unsigned ParallelismLevel) {
-+  return [=](Config &Conf, ModuleSummaryIndex &CombinedIndex,
-+             const StringMap<GVSummaryMapTy> &ModuleToDefinedGVSummaries,
-+             AddStreamFn AddStream, NativeObjectCache Cache) {
-+    ThinBackendProc* Backend = new InProcessThinBackend<SequentialThreadPool>(
-         Conf, CombinedIndex, ParallelismLevel, ModuleToDefinedGVSummaries,
-         AddStream, Cache);
-+    return std::unique_ptr<ThinBackendProc>(Backend);
-   };
- }
- 
-diff --git a/llvm/lib/LTO/LTOBackend.cpp b/llvm/lib/LTO/LTOBackend.cpp
-index 926c419e34a..2c263ed86a9 100644
---- a/llvm/lib/LTO/LTOBackend.cpp
-+++ b/llvm/lib/LTO/LTOBackend.cpp
-@@ -333,10 +333,11 @@ void codegen(Config &Conf, TargetMachine *TM, AddStreamFn AddStream,
-     DwoOut->keep();
- }
- 
--void splitCodeGen(Config &C, TargetMachine *TM, AddStreamFn AddStream,
-+template<class ThreadPoolEngine>
-+static void splitCodeGen_(Config &C, TargetMachine *TM, AddStreamFn AddStream,
-                   unsigned ParallelCodeGenParallelismLevel,
-                   std::unique_ptr<Module> Mod) {
--  ThreadPool CodegenThreadPool(ParallelCodeGenParallelismLevel);
-+  ThreadPoolEngine CodegenThreadPool(ParallelCodeGenParallelismLevel);
-   unsigned ThreadCount = 0;
-   const Target *T = &TM->getTarget();
- 
-@@ -380,6 +381,17 @@ void splitCodeGen(Config &C, TargetMachine *TM, AddStreamFn AddStream,
-   // can leave the function scope.
-   CodegenThreadPool.wait();
- }
-+void splitCodeGen(Config &C, TargetMachine *TM, AddStreamFn AddStream,
-+                  unsigned ParallelCodeGenParallelismLevel,
-+		  std::unique_ptr<Module> Mod) {
-+  splitCodeGen_<ThreadPool>(C, TM, AddStream, ParallelCodeGenParallelismLevel, std::move(Mod));
-+}
-+
-+void splitCodeGenNoThread(Config &C, TargetMachine *TM, AddStreamFn AddStream,
-+                  unsigned ParallelCodeGenParallelismLevel,
-+		  std::unique_ptr<Module> Mod) {
-+  splitCodeGen_<SequentialThreadPool>(C, TM, AddStream, ParallelCodeGenParallelismLevel, std::move(Mod));
-+}
- 
- Expected<const Target *> initAndLookupTarget(Config &C, Module &Mod) {
-   if (!C.OverrideTriple.empty())
-@@ -439,6 +451,38 @@ Error lto::backend(Config &C, AddStreamFn AddStream,
-   return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile));
- }
- 
-+Error lto::backendNoThread(Config &C, AddStreamFn AddStream,
-+                   unsigned ParallelCodeGenParallelismLevel,
-+                   std::unique_ptr<Module> Mod,
-+                   ModuleSummaryIndex &CombinedIndex) {
-+  Expected<const Target *> TOrErr = initAndLookupTarget(C, *Mod);
-+  if (!TOrErr)
-+    return TOrErr.takeError();
-+
-+  std::unique_ptr<TargetMachine> TM = createTargetMachine(C, *TOrErr, *Mod);
-+
-+  // Setup optimization remarks.
-+  auto DiagFileOrErr = lto::setupOptimizationRemarks(
-+      Mod->getContext(), C.RemarksFilename, C.RemarksWithHotness);
-+  if (!DiagFileOrErr)
-+    return DiagFileOrErr.takeError();
-+  auto DiagnosticOutputFile = std::move(*DiagFileOrErr);
-+
-+  if (!C.CodeGenOnly) {
-+    if (!opt(C, TM.get(), 0, *Mod, /*IsThinLTO=*/false,
-+             /*ExportSummary=*/&CombinedIndex, /*ImportSummary=*/nullptr))
-+      return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile));
-+  }
-+
-+  if (ParallelCodeGenParallelismLevel == 1) {
-+    codegen(C, TM.get(), AddStream, 0, *Mod);
-+  } else {
-+    splitCodeGenNoThread(C, TM.get(), AddStream, ParallelCodeGenParallelismLevel,
-+                 std::move(Mod));
-+  }
-+  return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile));
-+}
-+
- static void dropDeadSymbols(Module &Mod, const GVSummaryMapTy &DefinedGlobals,
-                             const ModuleSummaryIndex &Index) {
-   std::vector<GlobalValue*> DeadGVs;
-diff --git a/llvm/lib/Support/ThreadPool.cpp b/llvm/lib/Support/ThreadPool.cpp
-index d0212ca1346..3d760edbcb7 100644
---- a/llvm/lib/Support/ThreadPool.cpp
-+++ b/llvm/lib/Support/ThreadPool.cpp
-@@ -19,8 +19,6 @@
- 
- using namespace llvm;
- 
--#if LLVM_ENABLE_THREADS
--
- // Default to hardware_concurrency
- ThreadPool::ThreadPool() : ThreadPool(hardware_concurrency()) {}
- 
-@@ -107,7 +105,7 @@ ThreadPool::~ThreadPool() {
-     Worker.join();
- }
- 
--#else // LLVM_ENABLE_THREADS Disabled
-+#define ThreadPool SequentialThreadPool
- 
- ThreadPool::ThreadPool() : ThreadPool(0) {}
- 
-@@ -142,5 +140,3 @@ std::shared_future<void> ThreadPool::asyncImpl(TaskTy Task) {
- ThreadPool::~ThreadPool() {
-   wait();
- }
--
--#endif
-diff --git a/llvm/tools/gold/gold-plugin.cpp b/llvm/tools/gold/gold-plugin.cpp
-index 738cafa6cac..8ef75d2589c 100644
---- a/llvm/tools/gold/gold-plugin.cpp
-+++ b/llvm/tools/gold/gold-plugin.cpp
-@@ -848,7 +848,7 @@ static std::unique_ptr<LTO> createLTO(IndexWriteCallback OnIndexWrite,
-   Conf.DisableVerify = options::DisableVerify;
-   Conf.OptLevel = options::OptLevel;
-   if (options::Parallelism)
--    Backend = createInProcessThinBackend(options::Parallelism);
-+    Backend = createInProcessThinBackendNoThread(options::Parallelism);
-   if (options::thinlto_index_only) {
-     std::string OldPrefix, NewPrefix;
-     getThinLTOOldAndNewPrefix(OldPrefix, NewPrefix);
-@@ -856,6 +856,9 @@ static std::unique_ptr<LTO> createLTO(IndexWriteCallback OnIndexWrite,
-                                             options::thinlto_emit_imports_files,
-                                             LinkedObjectsFile, OnIndexWrite);
-   }
-+  if(!Backend)
-+    Backend = createInProcessThinBackendNoThread(llvm::heavyweight_hardware_concurrency());
-+
- 
-   Conf.OverrideTriple = options::triple;
-   Conf.DefaultTriple = sys::getDefaultTargetTriple();
-@@ -1039,7 +1042,7 @@ static std::vector<std::pair<SmallString<128>, bool>> runLTO() {
-   if (!options::cache_dir.empty())
-     Cache = check(localCache(options::cache_dir, AddBuffer));
- 
--  check(Lto->run(AddStream, Cache));
-+  check(Lto->runNoThread(AddStream, Cache));
- 
-   // Write empty output files that may be expected by the distributed build
-   // system.
--- 
-2.20.1
-
diff --git a/SOURCES/0001-docs-Convert-remaining-command-guide-entries-from-md.patch b/SOURCES/0001-docs-Convert-remaining-command-guide-entries-from-md.patch
new file mode 100644
index 0000000..91b27b2
--- /dev/null
+++ b/SOURCES/0001-docs-Convert-remaining-command-guide-entries-from-md.patch
@@ -0,0 +1,248 @@
+From e4e77bb8bf741f52b43b90987646f1c118914848 Mon Sep 17 00:00:00 2001
+From: Jordan Rupprecht <rupprecht@google.com>
+Date: Wed, 21 Aug 2019 18:00:17 +0000
+Subject: [PATCH] [docs] Convert remaining command guide entries from md to
+ rst.
+
+Summary:
+Linking between markdown and rst files is currently not supported very well, e.g. the current llvm-addr2line docs [1] link to "llvm-symbolizer" instead of "llvm-symbolizer.html". This is weirdly broken in different ways depending on which versions of sphinx and recommonmark are being used, so workaround the bug by using rst everywhere.
+
+[1] http://llvm.org/docs/CommandGuide/llvm-addr2line.html
+
+Reviewers: jhenderson
+
+Reviewed By: jhenderson
+
+Subscribers: lebedev.ri, llvm-commits
+
+Tags: #llvm
+
+Differential Revision: https://reviews.llvm.org/D66305
+
+llvm-svn: 369553
+---
+ llvm/docs/CommandGuide/llvm-addr2line.md  | 28 -----------------------
+ llvm/docs/CommandGuide/llvm-addr2line.rst | 38 +++++++++++++++++++++++++++++++
+ llvm/docs/CommandGuide/llvm-ranlib.md     | 17 --------------
+ llvm/docs/CommandGuide/llvm-ranlib.rst    | 23 +++++++++++++++++++
+ llvm/docs/CommandGuide/llvm-size.md       | 10 --------
+ llvm/docs/CommandGuide/llvm-size.rst      | 15 ++++++++++++
+ llvm/docs/CommandGuide/llvm-strings.md    | 10 --------
+ llvm/docs/CommandGuide/llvm-strings.rst   | 15 ++++++++++++
+ 8 files changed, 91 insertions(+), 65 deletions(-)
+ delete mode 100644 llvm/docs/CommandGuide/llvm-addr2line.md
+ create mode 100644 llvm/docs/CommandGuide/llvm-addr2line.rst
+ delete mode 100644 llvm/docs/CommandGuide/llvm-ranlib.md
+ create mode 100644 llvm/docs/CommandGuide/llvm-ranlib.rst
+ delete mode 100644 llvm/docs/CommandGuide/llvm-size.md
+ create mode 100644 llvm/docs/CommandGuide/llvm-size.rst
+ delete mode 100644 llvm/docs/CommandGuide/llvm-strings.md
+ create mode 100644 llvm/docs/CommandGuide/llvm-strings.rst
+
+diff --git a/llvm/docs/CommandGuide/llvm-addr2line.md b/llvm/docs/CommandGuide/llvm-addr2line.md
+deleted file mode 100644
+index 03224c4..0000000
+--- a/llvm/docs/CommandGuide/llvm-addr2line.md
++++ /dev/null
+@@ -1,28 +0,0 @@
+-# llvm-addr2line - a drop-in replacement for addr2line
+-
+-## SYNOPSIS
+-
+-**llvm-addr2line** [*options*]
+-
+-## DESCRIPTION
+-
+-**llvm-addr2line** is an alias for the [llvm-symbolizer](llvm-symbolizer) tool
+-with different defaults. The goal is to make it a drop-in replacement for
+-GNU's **addr2line**.
+-
+-Here are some of those differences:
+-
+-* Defaults not to print function names. Use [-f](llvm-symbolizer-opt-f)
+-  to enable that.
+-
+-* Defaults not to demangle function names. Use [-C](llvm-symbolizer-opt-C)
+-  to switch the demangling on.
+-
+-* Defaults not to print inlined frames. Use [-i](llvm-symbolizer-opt-i)
+-  to show inlined frames for a source code location in an inlined function.
+-
+-* Uses [--output-style=GNU](llvm-symbolizer-opt-output-style) by default.
+-
+-## SEE ALSO
+-
+-Refer to [llvm-symbolizer](llvm-symbolizer) for additional information.
+diff --git a/llvm/docs/CommandGuide/llvm-addr2line.rst b/llvm/docs/CommandGuide/llvm-addr2line.rst
+new file mode 100644
+index 0000000..08f1b69
+--- /dev/null
++++ b/llvm/docs/CommandGuide/llvm-addr2line.rst
+@@ -0,0 +1,38 @@
++llvm-addr2line - a drop-in replacement for addr2line
++====================================================
++
++.. program:: llvm-addr2line
++
++SYNOPSIS
++--------
++
++:program:`llvm-addr2line` [*options*]
++
++DESCRIPTION
++-----------
++
++:program:`llvm-addr2line` is an alias for the :manpage:`llvm-symbolizer(1)`
++tool with different defaults. The goal is to make it a drop-in replacement for
++GNU's :program:`addr2line`.
++
++Here are some of those differences:
++
++-  Defaults not to print function names. Use `-f`_ to enable that.
++
++-  Defaults not to demangle function names. Use `-C`_ to switch the
++   demangling on.
++
++-  Defaults not to print inlined frames. Use `-i`_ to show inlined
++   frames for a source code location in an inlined function.
++
++-  Uses `--output-style=GNU`_ by default.
++
++SEE ALSO
++--------
++
++:manpage:`llvm-symbolizer(1)`
++
++.. _-f: llvm-symbolizer.html#llvm-symbolizer-opt-f
++.. _-C: llvm-symbolizer.html#llvm-symbolizer-opt-c
++.. _-i: llvm-symbolizer.html#llvm-symbolizer-opt-i
++.. _--output-style=GNU: llvm-symbolizer.html#llvm-symbolizer-opt-output-style
+diff --git a/llvm/docs/CommandGuide/llvm-ranlib.md b/llvm/docs/CommandGuide/llvm-ranlib.md
+deleted file mode 100644
+index 4377364..0000000
+--- a/llvm/docs/CommandGuide/llvm-ranlib.md
++++ /dev/null
+@@ -1,17 +0,0 @@
+-# llvm-ranlib - generates an archive index
+-
+-## SYNOPSIS
+-
+-**llvm-ranlib** [*options*]
+-
+-## DESCRIPTION
+-
+-**llvm-ranlib** is an alias for the [llvm-ar](llvm-ar.html) tool that generates
+-an index for an archive. It can be used as a replacement for GNU's **ranlib**
+-tool.
+-
+-Running **llvm-ranlib** is equivalent to running **llvm-ar s**.
+-
+-## SEE ALSO
+-
+-Refer to [llvm-ar](llvm-ar.html) for additional information.
+diff --git a/llvm/docs/CommandGuide/llvm-ranlib.rst b/llvm/docs/CommandGuide/llvm-ranlib.rst
+new file mode 100644
+index 0000000..314a330
+--- /dev/null
++++ b/llvm/docs/CommandGuide/llvm-ranlib.rst
+@@ -0,0 +1,23 @@
++llvm-ranlib - generates an archive index
++========================================
++
++.. program:: llvm-ranlib
++
++SYNOPSIS
++--------
++
++:program:`llvm-ranlib` [*options*]
++
++DESCRIPTION
++-----------
++
++:program:`llvm-ranlib` is an alias for the :doc:`llvm-ar <llvm-ar>` tool that
++generates an index for an archive. It can be used as a replacement for GNU’s
++:program:`ranlib` tool.
++
++Running :program:`llvm-ranlib` is equivalent to running ``llvm-ar s``.
++
++SEE ALSO
++--------
++
++:manpage:`llvm-ar(1)`
+diff --git a/llvm/docs/CommandGuide/llvm-size.md b/llvm/docs/CommandGuide/llvm-size.md
+deleted file mode 100644
+index 3952708..0000000
+--- a/llvm/docs/CommandGuide/llvm-size.md
++++ /dev/null
+@@ -1,10 +0,0 @@
+-# llvm-size - print segment sizes
+-
+-## SYNOPSIS
+-
+-**llvm-size** [*options*]
+-
+-## DESCRIPTION
+-
+-**llvm-size** is a tool that prints segment sizes in object files. The goal is
+-to make it a drop-in replacement for GNU's **size**.
+diff --git a/llvm/docs/CommandGuide/llvm-size.rst b/llvm/docs/CommandGuide/llvm-size.rst
+new file mode 100644
+index 0000000..0dce15c
+--- /dev/null
++++ b/llvm/docs/CommandGuide/llvm-size.rst
+@@ -0,0 +1,15 @@
++llvm-size - print size information
++==================================
++
++.. program:: llvm-size
++
++SYNOPSIS
++--------
++
++:program:`llvm-size` [*options*]
++
++DESCRIPTION
++-----------
++
++:program:`llvm-size` is a tool that prints size information for object files.
++The goal is to make it a drop-in replacement for GNU’s :program:`size`.
+diff --git a/llvm/docs/CommandGuide/llvm-strings.md b/llvm/docs/CommandGuide/llvm-strings.md
+deleted file mode 100644
+index b5871c4..0000000
+--- a/llvm/docs/CommandGuide/llvm-strings.md
++++ /dev/null
+@@ -1,10 +0,0 @@
+-# llvm-strings - print strings
+-
+-## SYNOPSIS
+-
+-**llvm-strings** [*options*]
+-
+-## DESCRIPTION
+-
+-**llvm-strings** is a tool that prints strings in object files. The goal is to
+-make it a drop-in replacement for GNU's **size**.
+diff --git a/llvm/docs/CommandGuide/llvm-strings.rst b/llvm/docs/CommandGuide/llvm-strings.rst
+new file mode 100644
+index 0000000..d8ab9cb
+--- /dev/null
++++ b/llvm/docs/CommandGuide/llvm-strings.rst
+@@ -0,0 +1,15 @@
++llvm-strings - print strings
++============================
++
++.. program:: llvm-strings
++
++SYNOPSIS
++--------
++
++:program:`llvm-strings` [*options*]
++
++DESCRIPTION
++-----------
++
++:program:`llvm-strings` is a tool that prints strings in files. The goal is to
++make it a drop-in replacement for GNU’s :program:`strings`.
+-- 
+1.8.3.1
+
diff --git a/SOURCES/run-lit-tests b/SOURCES/run-lit-tests
index a0f27d8..aed8165 100755
--- a/SOURCES/run-lit-tests
+++ b/SOURCES/run-lit-tests
@@ -51,8 +51,14 @@ ln -s /usr/include include
 tar -xzf /usr/share/llvm/src/test.tar.gz
 ln -s $ARCH.site.cfg.py test/lit.site.cfg.py
 ln -s $ARCH.site.cfg.py test/Unit/lit.site.cfg.py
+
+# llvm_obj_root is used to determine the directory the tests will run in.
+# test/MC/MachO/gen-dwarf.s fails if llvm_obj_root is a parent directory
+# of the source file.  To workaround this, we set llvm_obj_root to a
+# different directory than the one used to store the test sources.
+# This also matches better how tests are run from the llvm source tree.
 lit -v -s $threads_arg test \
-	-Dllvm_obj_root=`pwd` \
+	-Dllvm_obj_root=$(mktemp -d) \
 	-Dllvm_test_root=`pwd`/test \
 	-Dllvm_unittest_bindir=$LIB_DIR/llvm \
 	-Dllvm_shlib_dir=$LIB_DIR
diff --git a/SPECS/llvm.spec b/SPECS/llvm.spec
index 90e93b0..2b90e1f 100644
--- a/SPECS/llvm.spec
+++ b/SPECS/llvm.spec
@@ -6,29 +6,36 @@
   %bcond_with gold
 %endif
 
-%global llvm_srcdir llvm-%{version}%{?rc_ver:rc%{rc_ver}}.src
+%bcond_with compat_build
 
-%global build_llvm_bindir %{buildroot}%{_bindir}
 %global llvm_libdir %{_libdir}/%{name}
 %global build_llvm_libdir %{buildroot}%{llvm_libdir}
-%global maj_ver 8
+%global maj_ver 9
 %global min_ver 0
 %global patch_ver 1
-#%%global rc_ver 2
-#%%global compat_version 7.0.1
+#%%global rc_ver 3
+%global baserelease 4
 
 
+%if %{with compat_build}
+%global pkg_name llvm%{maj_ver}.%{min_ver}
+%global exec_suffix -%{maj_ver}.%{min_ver}
+%global install_prefix %{_libdir}/%{name}
+%global install_bindir %{install_prefix}/bin
+%global install_includedir %{install_prefix}/include
+%global install_libdir %{install_prefix}/lib
+
+%global pkg_bindir %{install_bindir}
+%global pkg_includedir %{_includedir}/%{name}
+%global pkg_libdir %{install_libdir}
+%else
 %global pkg_name llvm
 %global install_prefix /usr
 %global install_libdir %{_libdir}
 %global pkg_libdir %{install_libdir}
+%endif
 
 %global build_install_prefix %{buildroot}%{install_prefix}
-%global build_pkgdocdir %{buildroot}%{_pkgdocdir}
-
-#%%ifnarch i686
-%global enable_test_pkg 1
-#%%endif
 
 %if !0%{?rhel}
 # libedit-devel is a buildroot-only package in RHEL8, so we can't have a
@@ -38,21 +45,36 @@
 
 Name:		%{pkg_name}
 Version:	%{maj_ver}.%{min_ver}.%{patch_ver}
-Release:	1%{?rc_ver:.rc%{rc_ver}}%{?dist}
+Release:	%{baserelease}%{?rc_ver:.rc%{rc_ver}}%{?dist}
 Summary:	The Low Level Virtual Machine
 
 License:	NCSA
 URL:		http://llvm.org
-Source0:	https://github.com/llvm/llvm-project/releases/download/llvmorg-%{version}%{?rc_ver:-%{rc_ver}}/%{llvm_srcdir}.tar.xz
+Source0:	http://%{?rc_ver:pre}releases.llvm.org/%{version}/%{?rc_ver:rc%{rc_ver}}/llvm-%{version}%{?rc_ver:rc%{rc_ver}}.src.tar.xz
+%if %{without compat_build}
 Source1:	run-lit-tests
 Source2:	lit.fedora.cfg.py
-%if %{defined compat_version}
-Source100:	http://llvm.org/releases/%{compat_version}/%{name}-%{compat_version}.src.tar.xz
 %endif
 
-Patch2:		0001-Selectively-disable-threading-from-gold.patch
-Patch3:		0001-Filter-out-cxxflags-not-supported-by-clang.patch
-Patch4:		0001-Deactivate-markdown-doc.patch
+Patch0:		0001-Filter-out-cxxflags-not-supported-by-clang.patch
+# TODO: I'm not sure why this is needed.  Could be a change in newer version
+# of gold.
+Patch1:		0001-Pass-target-to-gold-linker-to-avoid-faliures-on-i686.patch
+Patch2:		0001-CMake-Split-static-library-exports-into-their-own-ex.patch
+Patch3:		0001-CMake-Split-test-binary-exports-into-their-own-expor.patch
+
+# RHEL-specific patches.
+Patch101:	0001-Deactivate-markdown-doc.patch
+# Patches to convert md files to rst since we don't have the md parser in RHEL.
+Patch102:	0001-Docs-llvm-strip-Add-help-text-to-llvm-strip-rst-doc.patch
+Patch103:	0001-docs-Convert-remaining-command-guide-entries-from-md.patch
+
+# Fix crash in kernel bpf self-tests
+Patch5: 0001-BPF-Handling-type-conversions-correctly-for-CO-RE.patch
+Patch6: 0001-BPF-annotate-DIType-metadata-for-builtin-preseve_arr.patch
+
+# Fix Rust codegen bug, https://github.com/rust-lang/rust/issues/69225
+Patch7:	0001-Revert-SCEV-add-no-wrap-flag-for-SCEVAddExpr.patch
 
 BuildRequires:	gcc
 BuildRequires:	gcc-c++
@@ -62,7 +84,9 @@ BuildRequires:	zlib-devel
 BuildRequires:	libffi-devel
 BuildRequires:	ncurses-devel
 BuildRequires:	python3-sphinx
-#BuildRequires:	python3-recommonmark
+%if !0%{?rhel}
+BuildRequires:	python3-recommonmark
+%endif
 BuildRequires:	multilib-rpm-config
 %if %{with gold}
 BuildRequires:	binutils-devel
@@ -80,6 +104,8 @@ BuildRequires:	python3-devel
 
 Requires:	%{name}-libs%{?_isa} = %{version}-%{release}
 
+Provides:	llvm(major) = %{maj_ver}
+
 %description
 LLVM is a compiler infrastructure designed for compile-time, link-time,
 runtime, and idle-time optimization of programs from arbitrary programming
@@ -89,6 +115,7 @@ tools as well as libraries with equivalent functionality.
 %package devel
 Summary:	Libraries and header files for LLVM
 Requires:	%{name}%{?_isa} = %{version}-%{release}
+Requires:	%{name}-libs%{?_isa} = %{version}-%{release}
 # The installed LLVM cmake files will add -ledit to the linker flags for any
 # app that requires the libLLVMLineEditor, so we need to make sure
 # libedit-devel is available.
@@ -98,6 +125,8 @@ Requires:	libedit-devel
 Requires(post):	%{_sbindir}/alternatives
 Requires(postun):	%{_sbindir}/alternatives
 
+Provides:	llvm-devel(major) = %{maj_ver}
+
 %description devel
 This package contains library and header files needed to develop new native
 programs that use the LLVM infrastructure.
@@ -123,11 +152,12 @@ Conflicts:	%{name}-devel < 8
 %description static
 Static libraries for the LLVM compiler infrastructure.
 
-%if 0%{?enable_test_pkg}
+%if %{without compat_build}
 
 %package test
 Summary:	LLVM regression tests
 Requires:	%{name}%{?_isa} = %{version}-%{release}
+Requires:	%{name}-libs%{?_isa} = %{version}-%{release}
 Requires:	python3-lit
 # The regression tests need gold.
 Requires:	binutils
@@ -137,29 +167,21 @@ Requires:	%{name}-devel%{?_isa} = %{version}-%{release}
 Requires:	gcc
 Requires:	findutils
 
+Provides:	llvm-test(major) = %{maj_ver}
+
 %description test
 LLVM regression tests.
 
-%endif
-
 %package googletest
 Summary: LLVM's modified googletest sources
 
 %description googletest
 LLVM's modified googletest sources.
 
-%prep
-%if %{defined compat_version}
-%setup -T -q -b 100 -n llvm-%{compat_version}.src
-
-%setup -q -n llvm-%{version}%{?rc_ver:rc%{rc_ver}}.src
-%patch2 -p2
-%patch3 -p2
-%patch4 -p2
+%endif
 
-%else
+%prep
 %autosetup -n llvm-%{version}%{?rc_ver:rc%{rc_ver}}.src -p2
-%endif
 
 pathfix.py -i %{__python3} -pn \
 	test/BugPoint/compile-custom.ll.py \
@@ -185,15 +207,17 @@ cd _build
 	-DLLVM_PARALLEL_LINK_JOBS=1 \
 	-DCMAKE_BUILD_TYPE=RelWithDebInfo \
 	-DCMAKE_INSTALL_RPATH=";" \
-%ifarch s390 s390x %{arm} %ix86
+%ifarch s390 %{arm} %ix86
 	-DCMAKE_C_FLAGS_RELWITHDEBINFO="%{optflags} -DNDEBUG" \
 	-DCMAKE_CXX_FLAGS_RELWITHDEBINFO="%{optflags} -DNDEBUG" \
 %endif
+%if %{without compat_build}
 %if 0%{?__isa_bits} == 64
 	-DLLVM_LIBDIR_SUFFIX=64 \
 %else
 	-DLLVM_LIBDIR_SUFFIX= \
 %endif
+%endif
 	\
 	-DLLVM_TARGETS_TO_BUILD="X86;AMDGPU;PowerPC;NVPTX;SystemZ;AArch64;ARM;Mips;BPF" \
 	-DLLVM_ENABLE_LIBCXX:BOOL=OFF \
@@ -216,9 +240,13 @@ cd _build
 	-DLLVM_BUILD_EXAMPLES:BOOL=OFF \
 	\
 	-DLLVM_INCLUDE_UTILS:BOOL=ON \
+%if %{with compat_build}
+	-DLLVM_INSTALL_UTILS:BOOL=OFF \
+%else
 	-DLLVM_INSTALL_UTILS:BOOL=ON \
-	-DLLVM_UTILS_INSTALL_DIR:PATH=%{build_llvm_bindir} \
+	-DLLVM_UTILS_INSTALL_DIR:PATH=%{_bindir} \
 	-DLLVM_TOOLS_INSTALL_DIR:PATH=bin \
+%endif
 	\
 	-DLLVM_INCLUDE_DOCS:BOOL=ON \
 	-DLLVM_BUILD_DOCS:BOOL=ON \
@@ -232,54 +260,35 @@ cd _build
 	-DLLVM_INSTALL_TOOLCHAIN_ONLY:BOOL=OFF \
 	\
 	-DSPHINX_WARNINGS_AS_ERRORS=OFF \
-	-DCMAKE_INSTALL_PREFIX=%{build_install_prefix} \
-	-DLLVM_INSTALL_SPHINX_HTML_DIR=%{build_pkgdocdir}/html \
+	-DLLVM_INSTALL_SPHINX_HTML_DIR=%{_pkgdocdir}/html \
 	-DSPHINX_EXECUTABLE=%{_bindir}/sphinx-build-3
 
-ninja -v -j2
-
-%if %{defined compat_version}
-mkdir ../compat-build
-cd ../compat-build
-%cmake ../../%{name}-%{compat_version}.src \
-	-G Ninja \
-	-DBUILD_SHARED_LIBS=OFF \
-	-DCMAKE_BUILD_TYPE=Release \
-	-DLLVM_TARGETS_TO_BUILD="X86;AMDGPU;PowerPC;NVPTX;SystemZ;AArch64;ARM;Mips;BPF" \
-	-DLLVM_ENABLE_RTTI:BOOL=ON \
-	-DLLVM_ENABLE_ZLIB:BOOL=ON \
-	-DLLVM_ENABLE_FFI:BOOL=ON \
-	-DLLVM_BUILD_LLVM_DYLIB=ON
-ninja -v LLVM
-
-# Remove files we don't need to save disk space
-mv lib/libLLVM-`echo %{compat_version} | cut -f1 -d .`.so ..
-rm -Rf *
-%endif
+# Build libLLVM.so first.  This ensures that when libLLVM.so is linking, there
+# are no other compile jobs running.  This will help reduce OOM errors on the
+# builders without having to artificially limit the number of concurrent jobs.
+%ninja_build LLVM
+%ninja_build
 
 %install
-ninja -C _build -v install
+%ninja_install -C _build
 
 
+%if %{without compat_build}
 mkdir -p %{buildroot}/%{_bindir}
 mv %{buildroot}/%{_bindir}/llvm-config %{buildroot}/%{_bindir}/llvm-config-%{__isa_bits}
-ln -s llvm-config-%{__isa_bits} %{buildroot}/%{_bindir}/llvm-config
 
 # Fix some man pages
 ln -s llvm-config.1 %{buildroot}%{_mandir}/man1/llvm-config-%{__isa_bits}.1
 mv %{buildroot}%{_mandir}/man1/tblgen.1 %{buildroot}%{_mandir}/man1/llvm-tblgen.1
 
 # Install binaries needed for lit tests
-%if 0%{?enable_test_pkg}
-%global test_binaries FileCheck count lli-child-target llvm-PerfectShuffle llvm-isel-fuzzer llvm-opt-fuzzer not yaml-bench
+%global test_binaries llvm-isel-fuzzer llvm-opt-fuzzer
 
 for f in %{test_binaries}
 do
-    install -m 0755 ./_build/bin/$f %{build_llvm_bindir}
+    install -m 0755 ./_build/bin/$f %{buildroot}%{_bindir}
 done
 
-%endif
-
 
 %multilib_fix_c_header --file %{_includedir}/llvm/Config/llvm-config.h
 
@@ -302,7 +311,6 @@ install -d %{install_srcdir}
 install -d %{install_srcdir}/utils/
 cp -R utils/unittest %{install_srcdir}/utils/
 
-%if 0%{?enable_test_pkg}
 # Generate lit config files.  Strip off the last line that initiates the
 # test run, so we can customize the configuration.
 head -n -1 _build/test/lit.site.cfg.py >> %{lit_cfg}
@@ -337,81 +345,142 @@ install -m 0755 %{build_libdir}/LLVMHello.so %{buildroot}%{_libdir}
 echo "%{_datadir}/llvm/src/unittests/DebugInfo/PDB" > %{build_llvm_libdir}/unittests/DebugInfo/PDB/llvm.srcdir.txt
 mkdir -p %{buildroot}%{_datadir}/llvm/src/unittests/DebugInfo/PDB/
 cp -R unittests/DebugInfo/PDB/Inputs %{buildroot}%{_datadir}/llvm/src/unittests/DebugInfo/PDB/
-%endif
 
+%else
+
+# Add version suffix to binaries
+mkdir -p %{buildroot}/%{_bindir}
+for f in %{buildroot}/%{install_bindir}/*; do
+  filename=`basename $f`
+  ln -s %{install_bindir}/$filename %{buildroot}/%{_bindir}/$filename%{exec_suffix}
+done
+
+# Move header files
+mkdir -p %{buildroot}/%{pkg_includedir}
+ln -s ../../../%{install_includedir}/llvm %{buildroot}/%{pkg_includedir}/llvm
+ln -s ../../../%{install_includedir}/llvm-c %{buildroot}/%{pkg_includedir}/llvm-c
+
+# Fix multi-lib
+mv %{buildroot}%{_bindir}/llvm-config{%{exec_suffix},%{exec_suffix}-%{__isa_bits}}
+%multilib_fix_c_header --file %{install_includedir}/llvm/Config/llvm-config.h
+
+# Create ld.so.conf.d entry
+mkdir -p %{buildroot}%{_sysconfdir}/ld.so.conf.d
+cat >> %{buildroot}%{_sysconfdir}/ld.so.conf.d/%{name}-%{_arch}.conf << EOF
+%{pkg_libdir}
+EOF
+
+# Add version suffix to man pages and move them to mandir.
+mkdir -p %{buildroot}/%{_mandir}/man1
+for f in `ls %{build_install_prefix}/share/man/man1/*`; do
+  filename=`basename $f | cut -f 1 -d '.'`
+  mv $f %{buildroot}%{_mandir}/man1/$filename%{exec_suffix}.1
+done
+
+# Remove opt-viewer, since this is just a compatibility package.
+rm -Rf %{build_install_prefix}/share/opt-viewer
 
-%if %{defined compat_version}
-cd compat-build
-install ../libLLVM-`echo %{compat_version} | cut -f1 -d .`.so %{buildroot}%{_libdir}
 %endif
 
-%check
 
-# TODO: Fix arm
+%check
+# TODO: Fix test failures on arm
 ninja check-all -C _build || \
 %ifarch %{arm}
-   :
+  :
 %else
   false
 %endif
 
-
 %ldconfig_scriptlets libs
 
+%if %{without compat_build}
+
 %post devel
 %{_sbindir}/update-alternatives --install %{_bindir}/llvm-config llvm-config %{_bindir}/llvm-config-%{__isa_bits} %{__isa_bits}
 
 %postun devel
 if [ $1 -eq 0 ]; then
-  %{_sbindir}/update-alternatives --remove llvm-config %{_bindir}/llvm-config-%{__isa_bits}
+  %{_sbindir}/update-alternatives --remove llvm-config %{_bindir}/llvm-config
 fi
 
+%endif
 
 %files
-%exclude %{_bindir}/llvm-config*
+%exclude %{_mandir}/man1/llvm-config*
+%{_mandir}/man1/*
+%{_bindir}/*
+
+%if %{without compat_build}
+%exclude %{_bindir}/llvm-config-%{__isa_bits}
 %exclude %{_bindir}/not
 %exclude %{_bindir}/count
 %exclude %{_bindir}/yaml-bench
 %exclude %{_bindir}/lli-child-target
 %exclude %{_bindir}/llvm-isel-fuzzer
 %exclude %{_bindir}/llvm-opt-fuzzer
-%{_bindir}/*
-
-%exclude %{_mandir}/man1/llvm-config*
-%{_mandir}/man1/*
-
 %{_datadir}/opt-viewer
+%else
+%exclude %{pkg_bindir}/llvm-config
+%{pkg_bindir}
+%endif
 
 %files libs
 %{pkg_libdir}/libLLVM-%{maj_ver}.so
+%if %{without compat_build}
 %if %{with gold}
 %{_libdir}/LLVMgold.so
 %endif
 %{_libdir}/libLLVM-%{maj_ver}.%{min_ver}*.so
 %{_libdir}/libLTO.so*
-%{pkg_libdir}/libOptRemarks.so*
-%if %{defined compat_version}
-%{_libdir}/libLLVM-7.so
+%else
+%config(noreplace) %{_sysconfdir}/ld.so.conf.d/%{name}-%{_arch}.conf
+%if %{with gold}
+%{_libdir}/%{name}/lib/LLVMgold.so
+%endif
+%{pkg_libdir}/libLLVM-%{maj_ver}.%{min_ver}*.so
+%{pkg_libdir}/libLTO.so*
+%exclude %{pkg_libdir}/libLTO.so
 %endif
+%{pkg_libdir}/libRemarks.so*
 
 %files devel
-%{_bindir}/llvm-config*
+%if %{without compat_build}
+%{_bindir}/llvm-config-%{__isa_bits}
 %{_mandir}/man1/llvm-config*
 %{_includedir}/llvm
 %{_includedir}/llvm-c
 %{_libdir}/libLLVM.so
 %{_libdir}/cmake/llvm
 %exclude %{_libdir}/cmake/llvm/LLVMStaticExports.cmake
+%exclude %{_libdir}/cmake/llvm/LLVMTestExports.cmake
+%else
+%{_bindir}/llvm-config%{exec_suffix}-%{__isa_bits}
+%{pkg_bindir}/llvm-config
+%{_mandir}/man1/llvm-config%{exec_suffix}.1.gz
+%{install_includedir}/llvm
+%{install_includedir}/llvm-c
+%{pkg_includedir}/llvm
+%{pkg_includedir}/llvm-c
+%{pkg_libdir}/libLTO.so
+%{pkg_libdir}/libLLVM.so
+%{pkg_libdir}/cmake/llvm
+%endif
 
 %files doc
 %doc %{_pkgdocdir}/html
 
 %files static
+%if %{without compat_build}
 %{_libdir}/*.a
 %exclude %{_libdir}/libLLVMTestingSupport.a
 %{_libdir}/cmake/llvm/LLVMStaticExports.cmake
+%else
+%{_libdir}/%{name}/lib/*.a
+%endif
+
+%if %{without compat_build}
 
-%if 0%{?enable_test_pkg}
 %files test
 %{_libexecdir}/tests/llvm/
 %{llvm_libdir}/unittests/
@@ -426,14 +495,42 @@ fi
 %{_bindir}/llvm-opt-fuzzer
 %{_libdir}/BugpointPasses.so
 %{_libdir}/LLVMHello.so
-%endif
+%{_libdir}/cmake/llvm/LLVMTestExports.cmake
 
 %files googletest
 %{_datadir}/llvm/src/utils
 %{_libdir}/libLLVMTestingSupport.a
 
+%endif
 
 %changelog
+* Thu Feb 27 2020 Josh Stone <jistone@redhat.com> - 9.0.1-4
+- Fix a codegen bug for Rust
+
+* Fri Jan 17 2020 Tom Stellard <tstellar@redhat.com> - 9.0.1-3
+- Add explicit Requires from sub-packages to llvm-libs
+
+* Fri Jan 10 2020 Tom Stellard <tstellar@redhat.com> - 9.0.1-2
+- Fix crash with kernel bpf self-tests
+
+* Thu Dec 19 2019 tstellar@redhat.com - 9.0.1-1
+- 9.0.1 Release
+
+* Wed Oct 30 2019 Tom Stellard <tstellar@redhat.com> - 9.0.0-5
+- Remove work-around for threading issue in gold
+
+* Wed Oct 30 2019 Tom Stellard <tstellar@redhat.com> - 9.0.0-4
+- Build libLLVM.so first to avoid OOM errors
+
+* Tue Oct 01 2019 Tom Stellard <tstellar@redhat.com> - 9.0.0-3
+- Adjust run-lit-tests script to better match in tree testing
+
+* Mon Sep 30 2019 Tom Stellard <tstellar@redhat.com> - 9.0.0-2
+- Limit number of build threads using -l option for ninja
+
+* Thu Sep 26 2019 Tom Stellard <tstellar@redhat.com> - 9.0.0-1
+- 9.0.0 Release
+
 * Thu Aug 1 2019 sguelton@redhat.com - 8.0.1-1
 - 8.0.1 release