diff options
Diffstat (limited to 'llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp')
-rw-r--r-- | llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp | 86 |
1 files changed, 46 insertions, 40 deletions
diff --git a/llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp b/llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp index 400701c4e5c2..a28816cc87b7 100644 --- a/llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp +++ b/llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp @@ -117,6 +117,7 @@ public: struct CallInfo { uint32_t Kind; uint32_t AccessIndex; + uint32_t RecordAlignment; MDNode *Metadata; Value *Base; }; @@ -130,6 +131,8 @@ private: BPFPreserveFieldInfoAI = 4, }; + const DataLayout *DL = nullptr; + std::map<std::string, GlobalVariable *> GEPGlobals; // A map to link preserve_*_access_index instrinsic calls. std::map<CallInst *, std::pair<CallInst *, CallInfo>> AIChain; @@ -154,11 +157,11 @@ private: void replaceWithGEP(std::vector<CallInst *> &CallList, uint32_t NumOfZerosIndex, uint32_t DIIndex); bool HasPreserveFieldInfoCall(CallInfoStack &CallStack); - void GetStorageBitRange(DICompositeType *CTy, DIDerivedType *MemberTy, - uint32_t AccessIndex, uint32_t &StartBitOffset, - uint32_t &EndBitOffset); + void GetStorageBitRange(DIDerivedType *MemberTy, uint32_t RecordAlignment, + uint32_t &StartBitOffset, uint32_t &EndBitOffset); uint32_t GetFieldInfo(uint32_t InfoKind, DICompositeType *CTy, - uint32_t AccessIndex, uint32_t PatchImm); + uint32_t AccessIndex, uint32_t PatchImm, + uint32_t RecordAlignment); Value *computeBaseAndAccessKey(CallInst *Call, CallInfo &CInfo, std::string &AccessKey, MDNode *&BaseMeta); @@ -182,6 +185,7 @@ bool BPFAbstractMemberAccess::runOnModule(Module &M) { if (M.debug_compile_units().empty()) return false; + DL = &M.getDataLayout(); return doTransformation(M); } @@ -243,6 +247,8 @@ bool BPFAbstractMemberAccess::IsPreserveDIAccessIndexCall(const CallInst *Call, report_fatal_error("Missing metadata for llvm.preserve.array.access.index intrinsic"); CInfo.AccessIndex = getConstant(Call->getArgOperand(2)); CInfo.Base = Call->getArgOperand(0); + CInfo.RecordAlignment = + DL->getABITypeAlignment(CInfo.Base->getType()->getPointerElementType()); return true; } if (GV->getName().startswith("llvm.preserve.union.access.index")) { @@ -252,6 +258,8 @@ bool BPFAbstractMemberAccess::IsPreserveDIAccessIndexCall(const CallInst *Call, report_fatal_error("Missing metadata for llvm.preserve.union.access.index intrinsic"); CInfo.AccessIndex = getConstant(Call->getArgOperand(1)); CInfo.Base = Call->getArgOperand(0); + CInfo.RecordAlignment = + DL->getABITypeAlignment(CInfo.Base->getType()->getPointerElementType()); return true; } if (GV->getName().startswith("llvm.preserve.struct.access.index")) { @@ -261,6 +269,8 @@ bool BPFAbstractMemberAccess::IsPreserveDIAccessIndexCall(const CallInst *Call, report_fatal_error("Missing metadata for llvm.preserve.struct.access.index intrinsic"); CInfo.AccessIndex = getConstant(Call->getArgOperand(2)); CInfo.Base = Call->getArgOperand(0); + CInfo.RecordAlignment = + DL->getABITypeAlignment(CInfo.Base->getType()->getPointerElementType()); return true; } if (GV->getName().startswith("llvm.bpf.preserve.field.info")) { @@ -509,40 +519,29 @@ uint64_t BPFAbstractMemberAccess::getConstant(const Value *IndexValue) { } /// Get the start and the end of storage offset for \p MemberTy. -/// The storage bits are corresponding to the LLVM internal types, -/// and the storage bits for the member determines what load width -/// to use in order to extract the bitfield value. -void BPFAbstractMemberAccess::GetStorageBitRange(DICompositeType *CTy, - DIDerivedType *MemberTy, - uint32_t AccessIndex, +void BPFAbstractMemberAccess::GetStorageBitRange(DIDerivedType *MemberTy, + uint32_t RecordAlignment, uint32_t &StartBitOffset, uint32_t &EndBitOffset) { - auto SOff = dyn_cast<ConstantInt>(MemberTy->getStorageOffsetInBits()); - assert(SOff); - StartBitOffset = SOff->getZExtValue(); - - EndBitOffset = CTy->getSizeInBits(); - uint32_t Index = AccessIndex + 1; - for (; Index < CTy->getElements().size(); ++Index) { - auto Member = cast<DIDerivedType>(CTy->getElements()[Index]); - if (!Member->getStorageOffsetInBits()) { - EndBitOffset = Member->getOffsetInBits(); - break; - } - SOff = dyn_cast<ConstantInt>(Member->getStorageOffsetInBits()); - assert(SOff); - unsigned BitOffset = SOff->getZExtValue(); - if (BitOffset != StartBitOffset) { - EndBitOffset = BitOffset; - break; - } - } + uint32_t MemberBitSize = MemberTy->getSizeInBits(); + uint32_t MemberBitOffset = MemberTy->getOffsetInBits(); + uint32_t AlignBits = RecordAlignment * 8; + if (RecordAlignment > 8 || MemberBitSize > AlignBits) + report_fatal_error("Unsupported field expression for llvm.bpf.preserve.field.info, " + "requiring too big alignment"); + + StartBitOffset = MemberBitOffset & ~(AlignBits - 1); + if ((StartBitOffset + AlignBits) < (MemberBitOffset + MemberBitSize)) + report_fatal_error("Unsupported field expression for llvm.bpf.preserve.field.info, " + "cross alignment boundary"); + EndBitOffset = StartBitOffset + AlignBits; } uint32_t BPFAbstractMemberAccess::GetFieldInfo(uint32_t InfoKind, DICompositeType *CTy, uint32_t AccessIndex, - uint32_t PatchImm) { + uint32_t PatchImm, + uint32_t RecordAlignment) { if (InfoKind == BPFCoreSharedInfo::FIELD_EXISTENCE) return 1; @@ -557,9 +556,10 @@ uint32_t BPFAbstractMemberAccess::GetFieldInfo(uint32_t InfoKind, if (!MemberTy->isBitField()) { PatchImm += MemberTy->getOffsetInBits() >> 3; } else { - auto SOffset = dyn_cast<ConstantInt>(MemberTy->getStorageOffsetInBits()); - assert(SOffset); - PatchImm += SOffset->getZExtValue() >> 3; + unsigned SBitOffset, NextSBitOffset; + GetStorageBitRange(MemberTy, RecordAlignment, SBitOffset, + NextSBitOffset); + PatchImm += SBitOffset >> 3; } } return PatchImm; @@ -576,7 +576,7 @@ uint32_t BPFAbstractMemberAccess::GetFieldInfo(uint32_t InfoKind, return SizeInBits >> 3; unsigned SBitOffset, NextSBitOffset; - GetStorageBitRange(CTy, MemberTy, AccessIndex, SBitOffset, NextSBitOffset); + GetStorageBitRange(MemberTy, RecordAlignment, SBitOffset, NextSBitOffset); SizeInBits = NextSBitOffset - SBitOffset; if (SizeInBits & (SizeInBits - 1)) report_fatal_error("Unsupported field expression for llvm.bpf.preserve.field.info"); @@ -636,7 +636,7 @@ uint32_t BPFAbstractMemberAccess::GetFieldInfo(uint32_t InfoKind, } unsigned SBitOffset, NextSBitOffset; - GetStorageBitRange(CTy, MemberTy, AccessIndex, SBitOffset, NextSBitOffset); + GetStorageBitRange(MemberTy, RecordAlignment, SBitOffset, NextSBitOffset); if (NextSBitOffset - SBitOffset > 64) report_fatal_error("too big field size for llvm.bpf.preserve.field.info"); @@ -667,7 +667,7 @@ uint32_t BPFAbstractMemberAccess::GetFieldInfo(uint32_t InfoKind, } unsigned SBitOffset, NextSBitOffset; - GetStorageBitRange(CTy, MemberTy, AccessIndex, SBitOffset, NextSBitOffset); + GetStorageBitRange(MemberTy, RecordAlignment, SBitOffset, NextSBitOffset); if (NextSBitOffset - SBitOffset > 64) report_fatal_error("too big field size for llvm.bpf.preserve.field.info"); @@ -822,14 +822,20 @@ Value *BPFAbstractMemberAccess::computeBaseAndAccessKey(CallInst *Call, AccessKey += ":" + std::to_string(AccessIndex); MDNode *MDN = CInfo.Metadata; + uint32_t RecordAlignment = CInfo.RecordAlignment; // At this stage, it cannot be pointer type. auto *CTy = cast<DICompositeType>(stripQualifiers(cast<DIType>(MDN))); - PatchImm = GetFieldInfo(InfoKind, CTy, AccessIndex, PatchImm); + PatchImm = GetFieldInfo(InfoKind, CTy, AccessIndex, PatchImm, + RecordAlignment); } - // Access key is the type name + reloc type + patched imm + access string, + // Access key is the + // "llvm." + type name + ":" + reloc type + ":" + patched imm + "$" + + // access string, // uniquely identifying one relocation. - AccessKey = TypeName + ":" + std::to_string(InfoKind) + ":" + + // The prefix "llvm." indicates this is a temporary global, which should + // not be emitted to ELF file. + AccessKey = "llvm." + TypeName + ":" + std::to_string(InfoKind) + ":" + std::to_string(PatchImm) + "$" + AccessKey; return Base; |