Index: lib/Target/BPF/BPFAbstractMemberAccess.cpp =================================================================== --- lib/Target/BPF/BPFAbstractMemberAccess.cpp +++ 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 @@ 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 @@ 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,26 @@ return false; if (GV->getName().startswith("llvm.preserve.array.access.index")) { Kind = BPFPreserveArrayAI; + TypeMeta = Call->getMetadata(LLVMContext::MD_preserve_access_index); + assert(TypeMeta); + 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); + assert(TypeMeta); + 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); + assert(TypeMeta); + AccessIndex = cast(Call->getArgOperand(2)) + ->getZExtValue(); return true; } @@ -200,7 +263,9 @@ 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 +297,79 @@ 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 +377,30 @@ } 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 +408,29 @@ } 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 +444,14 @@ 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 +474,131 @@ 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 +608,7 @@ 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 +618,7 @@ // 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 +631,7 @@ 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]; Index: lib/Target/BPF/BTFDebug.h =================================================================== --- lib/Target/BPF/BTFDebug.h +++ lib/Target/BPF/BTFDebug.h @@ -104,18 +104,13 @@ /// 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 @@ const DICompositeType *STy; bool HasBitField; std::vector Members; - std::vector MemberTypeNoQual; public: BTFTypeStruct(const DICompositeType *STy, bool IsStruct, bool HasBitField, @@ -134,8 +128,6 @@ 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 @@ StringMap> FileContent; std::map> DataSecEntries; std::vector StructTypes; - std::vector ArrayTypes; std::map AccessOffsets; std::map>> FixupDerivedTypes; @@ -312,10 +303,6 @@ 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); Index: lib/Target/BPF/BTFDebug.cpp =================================================================== --- lib/Target/BPF/BTFDebug.cpp +++ lib/Target/BPF/BTFDebug.cpp @@ -30,18 +30,6 @@ #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 @@ } } -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 @@ // 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 @@ 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 @@ } 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 @@ 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 @@ 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 @@ 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 @@ 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); } Index: test/CodeGen/BPF/CORE/offset-reloc-cast-array-1.ll =================================================================== --- /dev/null +++ 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) Index: test/CodeGen/BPF/CORE/offset-reloc-cast-array-2.ll =================================================================== --- /dev/null +++ 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) Index: test/CodeGen/BPF/CORE/offset-reloc-cast-struct-1.ll =================================================================== --- /dev/null +++ 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) Index: test/CodeGen/BPF/CORE/offset-reloc-cast-struct-2.ll =================================================================== --- /dev/null +++ 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) Index: test/CodeGen/BPF/CORE/offset-reloc-cast-struct-3.ll =================================================================== --- /dev/null +++ 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) Index: test/CodeGen/BPF/CORE/offset-reloc-cast-union-1.ll =================================================================== --- /dev/null +++ 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) Index: test/CodeGen/BPF/CORE/offset-reloc-cast-union-2.ll =================================================================== --- /dev/null +++ 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) Index: test/CodeGen/BPF/CORE/offset-reloc-global-1.ll =================================================================== --- /dev/null +++ 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) Index: test/CodeGen/BPF/CORE/offset-reloc-global-2.ll =================================================================== --- /dev/null +++ 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) Index: test/CodeGen/BPF/CORE/offset-reloc-global-3.ll =================================================================== --- /dev/null +++ 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) Index: test/CodeGen/BPF/CORE/offset-reloc-ignore.ll =================================================================== --- /dev/null +++ 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) Index: test/CodeGen/BPF/CORE/offset-reloc-multi-array-1.ll =================================================================== --- /dev/null +++ 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) Index: test/CodeGen/BPF/CORE/offset-reloc-multi-array-2.ll =================================================================== --- /dev/null +++ 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) Index: test/CodeGen/BPF/CORE/offset-reloc-pointer-1.ll =================================================================== --- /dev/null +++ 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) Index: test/CodeGen/BPF/CORE/offset-reloc-pointer-2.ll =================================================================== --- /dev/null +++ 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) Index: test/CodeGen/BPF/CORE/offset-reloc-struct-anonymous.ll =================================================================== --- test/CodeGen/BPF/CORE/offset-reloc-struct-anonymous.ll +++ test/CodeGen/BPF/CORE/offset-reloc-struct-anonymous.ll @@ -30,7 +30,7 @@ %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 Index: test/CodeGen/BPF/CORE/offset-reloc-struct-array.ll =================================================================== --- test/CodeGen/BPF/CORE/offset-reloc-struct-array.ll +++ test/CodeGen/BPF/CORE/offset-reloc-struct-array.ll @@ -31,7 +31,7 @@ %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 Index: test/CodeGen/BPF/CORE/offset-reloc-typedef-array.ll =================================================================== --- test/CodeGen/BPF/CORE/offset-reloc-typedef-array.ll +++ test/CodeGen/BPF/CORE/offset-reloc-typedef-array.ll @@ -21,7 +21,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 Index: test/CodeGen/BPF/CORE/offset-reloc-typedef.ll =================================================================== --- test/CodeGen/BPF/CORE/offset-reloc-typedef.ll +++ 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