From d7b5dc38f6f69f92653a87434b14a094c5a96bff Mon Sep 17 00:00:00 2001 From: Tom Stellard Date: Jan 11 2020 04:16:47 +0000 Subject: Fix crash with kernel bpf self-tests --- diff --git a/0001-BPF-Handling-type-conversions-correctly-for-CO-RE.patch b/0001-BPF-Handling-type-conversions-correctly-for-CO-RE.patch new file mode 100644 index 0000000..bfde9bc --- /dev/null +++ b/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 +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 + + #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 &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(Ty)) { ++ if (!SkipDIDerivedTag(DTy->getTag())) ++ break; ++ Ty = DTy->getBaseType(); ++ } ++ return Ty; ++} ++ ++static const DIType * stripQualifiers(const DIType *Ty) { ++ while (auto *DTy = dyn_cast(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(Elements[I])) ++ if (Element->getTag() == dwarf::DW_TAG_subrange_type) { ++ const DISubrange *SR = cast(Element); ++ auto *CI = SR->getCount().dyn_cast(); ++ 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(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(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(Call->getArgOperand(2)) ++ ->getZExtValue(); + return true; + } + +@@ -200,7 +266,9 @@ bool BPFAbstractMemberAccess::removePreserveAccessIndexIntrinsic(Module &M) { + for (auto &I : BB) { + auto *Call = dyn_cast(&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(ParentType)); ++ const DIType *CType = stripQualifiers(cast(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(CType)) ++ return false; ++ ++ // Parent is a pointer type. ++ if (const auto *PtrTy = dyn_cast(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(PType); ++ const auto *CTy = dyn_cast(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(PTy->getElements()[ParentAI]); ++ ++ return dyn_cast(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(U); + if (!Inst) + continue; + + if (auto *BI = dyn_cast(Inst)) { +- traceBitCast(BI, Call, Kind); ++ traceBitCast(BI, Call, Kind, ParentMeta, ParentAI); + } else if (auto *CI = dyn_cast(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(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(U); + if (!Inst) + continue; + + if (auto *BI = dyn_cast(Inst)) { +- traceBitCast(BI, Parent, Kind); ++ traceBitCast(BI, Parent, Kind, ParentMeta, ParentAI); + } else if (auto *CI = dyn_cast(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(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(U); + if (!Inst) + continue; + + if (auto *BI = dyn_cast(Inst)) { +- traceBitCast(BI, Parent, Kind); ++ traceBitCast(BI, Parent, Kind, ParentMeta, ParentAI); + } else if (auto *CI = dyn_cast(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(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(&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 AccessIndices; +- uint64_t TypeNameIndex = 0; +- std::string LastTypeName; ++ std::string TypeName; ++ std::stack> 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(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(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(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(Ty); ++ assert(DTy->getTag() == dwarf::DW_TAG_pointer_type); ++ ++ BaseTy = stripQualifiers(DTy->getBaseType()); ++ CTy = dyn_cast(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(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(stripQualifiers(cast(MDN))); ++ uint32_t Tag = CTy->getTag(); ++ if (Tag == dwarf::DW_TAG_structure_type) { ++ auto *MemberTy = cast(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(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(ElemType, ElemTypeId, 0, 0); +- ArrayTypes.push_back(TypeEntry.get()); ++ auto TypeEntry = llvm::make_unique(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(Element); + auto *CI = SR->getCount().dyn_cast(); + int64_t Count = CI->getSExtValue(); +- const DIType *ArrayElemTy = (I == 0) ? ElemType : nullptr; + + auto TypeEntry = +- llvm::make_unique(ArrayElemTy, ElemTypeId, +- ElemSize, Count); +- ArrayTypes.push_back(TypeEntry.get()); ++ llvm::make_unique(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 Members; +- std::vector 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> FileContent; + std::map> DataSecEntries; + std::vector StructTypes; +- std::vector ArrayTypes; + std::map AccessOffsets; + std::map>> + 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/0001-BPF-annotate-DIType-metadata-for-builtin-preseve_arr.patch b/0001-BPF-annotate-DIType-metadata-for-builtin-preseve_arr.patch new file mode 100644 index 0000000..60ba6d9 --- /dev/null +++ b/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 +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 + +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(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/llvm.spec b/llvm.spec index ef5fc55..79da708 100644 --- a/llvm.spec +++ b/llvm.spec @@ -14,7 +14,7 @@ %global min_ver 0 %global patch_ver 1 #%%global rc_ver 3 -%global baserelease 1 +%global baserelease 2 %if %{with compat_build} @@ -58,6 +58,10 @@ Patch2: 0001-CMake-Split-static-library-exports-into-their-own-ex.patch Patch3: 0001-CMake-Split-test-binary-exports-into-their-own-expor.patch Patch4: 0001-AVR-Fix-endianness-handling-in-AVR-MC.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 + BuildRequires: gcc BuildRequires: gcc-c++ BuildRequires: cmake @@ -479,6 +483,9 @@ fi %endif %changelog +* Fri Jan 10 2020 Tom Stellard - 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