Index: lib/Target/BPF/BPF.h =================================================================== --- lib/Target/BPF/BPF.h +++ lib/Target/BPF/BPF.h @@ -15,11 +15,25 @@ namespace llvm { class BPFTargetMachine; +/// The attribute attached to globals representing a member offset +static const char *AmaAttr = "btf_ama"; +/// The section name to identify a patchable external global +static const char *PatchableExtSecName = ".BPF.patchable_externs"; +/// Kernel bpf_probe_read() call +static const int BpfProbeReadCall = 4; +static const int BpfProbeReadNumArgs = 3; +static const int BpfProbeReadSrcAddrArg = 2; + +ModulePass *createBPFAbstractMemberAccess(BPFTargetMachine *TM); + FunctionPass *createBPFISelDag(BPFTargetMachine &TM); +FunctionPass *createBPFMISimplifyPatchablePass(); FunctionPass *createBPFMIPeepholePass(); FunctionPass *createBPFMIPreEmitPeepholePass(); FunctionPass *createBPFMIPreEmitCheckingPass(); +void initializeBPFAbstractMemberAccessPass(PassRegistry&); +void initializeBPFMISimplifyPatchablePass(PassRegistry&); void initializeBPFMIPeepholePass(PassRegistry&); void initializeBPFMIPreEmitPeepholePass(PassRegistry&); void initializeBPFMIPreEmitCheckingPass(PassRegistry&); Index: lib/Target/BPF/BPF.td =================================================================== --- lib/Target/BPF/BPF.td +++ lib/Target/BPF/BPF.td @@ -32,6 +32,9 @@ def DwarfRIS: SubtargetFeature<"dwarfris", "UseDwarfRIS", "true", "Disable MCAsmInfo DwarfUsesRelocationsAcrossSections">; +def OffsetReloc: SubtargetFeature<"offsetreloc", "HasOffsetReloc", "true", + "Enable Struct/Union Member Offset Relocation">; + def BPFInstPrinter : AsmWriter { string AsmWriterClassName = "InstPrinter"; bit isMCAsmWriter = 1; Index: lib/Target/BPF/BPFAbstrctMemberAccess.cpp =================================================================== --- /dev/null +++ lib/Target/BPF/BPFAbstrctMemberAccess.cpp @@ -0,0 +1,750 @@ +//===------ BPFAbstractMemberAccess.cpp - Abstracting Member Accesses -----===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This pass abstracted struct/union member accesses in order to support +// compile-once run-everywhere (CO-RE). The CO-RE intends to compile the program +// which can run on different kernels. In particular, if bpf program tries to +// access a particular kernel data structure member, the details of the +// intermediate member access will be remembered so bpf loader can do +// necessary adjustment right before program loading. +// +// For example, +// +// struct s { +// int a; +// int b; +// }; +// struct t { +// struct s c; +// int d; +// }; +// struct t e; +// +// For the member access e.c.b, the compiler will generate code +// &e + 4 +// +// The compile-once run-everywhere instead generates the following code +// r = 4 +// &e + r +// The "4" in "r = 4" can be changed based on a particular kernel version. +// For example, on a particular kernel version, if struct s is changed to +// +// struct s { +// int new_field; +// int a; +// int b; +// } +// +// By repeating the member access on the host, the bpf loader can +// adjust "r = 4" as "r = 8". +// +// In IR, all user-level unions become structures. The current handling +// of structurized unions rather rudimentary. +// +//===----------------------------------------------------------------------===// + +#include "BPF.h" +#include "BPFTargetMachine.h" +#include "llvm/IR/DebugInfoMetadata.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" +#include "llvm/IR/User.h" +#include "llvm/IR/Value.h" +#include "llvm/Pass.h" +#include "llvm/Transforms/Utils/BasicBlockUtils.h" +using namespace llvm; + +#define DEBUG_TYPE "bpf-abstruct-member-access" + +namespace { +typedef std::map GEPCandidateSet; + +class BPFAbstractMemberAccess final : public ModulePass { + StringRef getPassName() const override { + return "BPF Abstract Member Access"; + } + + bool runOnModule(Module &M) override; + +public: + static char ID; + BPFAbstractMemberAccess() : ModulePass(ID), TM(nullptr) {} + BPFAbstractMemberAccess(BPFTargetMachine *TM) : ModulePass(ID), TM(TM) {} + +private: + BPFTargetMachine *TM; + + std::map StructDITypes; + std::map TypedefDITypes; + std::map GEPGlobals; + std::map GEPDependInsts; + std::map> + STypeToDIStruct; + std::set VisitedDITypes; + + void collectDITypes(Module &M, Function &F); + void visitDIType(const DIType *Ty); + const DICompositeType *getDIStruct(std::string TypeName); + + void collectGEPs( + Function &F, + std::map> &TmpBpfProbeCalls); + void processGEPs( + GEPCandidateSet &WorkList, + std::map> &TmpBpfProbeCalls); + void processGEP( + GetElementPtrInst *GEP, GEPCandidateSet &WorkList, + std::map> &TmpBpfProbeCalls, + std::set &VisitedGEPs); + + const DIType *stripQualifiers(const DIType *Ty); + bool isBpfProbeReadCall(CallInst *Call, Instruction *ProbeAddr); + void adjustTraverseTypes(const StructType *&SType, const ArrayType *&AType, + uint64_t Index); + + uint32_t computeDIMemberIndex(const DICompositeType *DIStruct, + const StructType *SType, uint32_t STIndex); + bool checkAndAddGEP(GetElementPtrInst *GEP, GEPCandidateSet &WorkList); + bool computeMemberAccessString(GetElementPtrInst *GEP, + const StructType *SType, + const DICompositeType *DIStruct, + std::string &GVName, std::string &Prefix, + std::vector &ArrayBounds); + void computeGEPCandidates(Module &M, GEPCandidateSet &WorkList, + std::set &BpfProbeCalls); + void checkBpfProbeCalls(Module &M, std::set &BpfProbeCalls); + void transformGEPCandidates(Module &M, GEPCandidateSet &WorkList); +}; +} // End anonymous namespace + +char BPFAbstractMemberAccess::ID = 0; +INITIALIZE_PASS(BPFAbstractMemberAccess, DEBUG_TYPE, + "abstracting struct/union member accessees", false, false) + +ModulePass *llvm::createBPFAbstractMemberAccess(BPFTargetMachine *TM) { + return new BPFAbstractMemberAccess(TM); +} + +bool BPFAbstractMemberAccess::runOnModule(Module &M) { + LLVM_DEBUG(dbgs() << "********** Abstract Member Accesses **********\n"); + + // Bail out if instructed not to do the transformation. + const BPFSubtarget *SubTarget = TM->getSubtargetImpl(); + if (!SubTarget->getHasOffsetReloc()) + return false; + + // Bail out if no debug info. + unsigned NumDebugCUs = + std::distance(M.debug_compile_units_begin(), M.debug_compile_units_end()); + if (NumDebugCUs == 0) + return false; + + // Collect target GEPs and do the transformation. + std::map WorkList; + std::set BpfProbeCalls; + computeGEPCandidates(M, WorkList, BpfProbeCalls); + checkBpfProbeCalls(M, BpfProbeCalls); + transformGEPCandidates(M, WorkList); + + return !WorkList.empty(); +} + +/// Visit DebugInfo types. Specifically Record all Struct/Union/Typedef +/// types for future lookup. +void BPFAbstractMemberAccess::visitDIType(const DIType *Ty) { + if (!Ty || VisitedDITypes.find(Ty) != VisitedDITypes.end()) + return; + VisitedDITypes.insert(Ty); + + if (const auto *CTy = dyn_cast(Ty)) { + // Remember the named struct types. + auto Tag = CTy->getTag(); + if (Tag == dwarf::DW_TAG_structure_type || + Tag == dwarf::DW_TAG_union_type) { + if (!CTy->isForwardDecl() && CTy->getName().size()) + StructDITypes[CTy->getName()] = CTy; + + const DINodeArray Elements = CTy->getElements(); + for (const auto *Element : Elements) { + visitDIType(cast(Element)); + } + } else if (Tag == dwarf::DW_TAG_array_type) { + visitDIType(CTy->getBaseType().resolve()); + } + } else if (const auto *DTy = dyn_cast(Ty)) { + if (DTy->getTag() == dwarf::DW_TAG_typedef) + TypedefDITypes[DTy->getName()] = DTy; + visitDIType(DTy->getBaseType().resolve()); + } +} + +/// Find structure type given a type name. +const DICompositeType * +BPFAbstractMemberAccess::getDIStruct(std::string TypeName) { + if (StructDITypes.find(TypeName) != StructDITypes.end()) + return StructDITypes[TypeName]; + if (TypedefDITypes.find(TypeName) != TypedefDITypes.end()) { + const DIType *Ty = stripQualifiers(TypedefDITypes[TypeName]); + return dyn_cast(Ty); + } + return nullptr; +} + +/// Collect all DebugInfo types for a function. +/// The collected types include all local variable types, +/// the types retained at compilation unit level, and +/// all global variable types. +void BPFAbstractMemberAccess::collectDITypes(Module &M, Function &F) { + DISubprogram *SP = F.getSubprogram(); + if (!SP) + return; + + StructDITypes.clear(); + VisitedDITypes.clear(); + for (const DINode *DN : SP->getRetainedNodes()) { + if (const auto *DV = dyn_cast(DN)) + visitDIType(DV->getType().resolve()); + } + + for (const auto *Ty : SP->getUnit()->getRetainedTypes()) { + if (const auto *RT = dyn_cast(Ty)) + visitDIType(RT); + } + + for (const GlobalVariable &Global : M.globals()) { + if (!Global.hasInitializer() && Global.hasExternalLinkage()) + continue; + + SmallVector GVs; + Global.getDebugInfo(GVs); + for (auto *GVE : GVs) + visitDIType(GVE->getVariable()->getType().resolve()); + } +} + +/// Check whether a call is a bpf_probe_read call or not. +bool BPFAbstractMemberAccess::isBpfProbeReadCall(CallInst *Call, + Instruction *ProbeAddr) { + if (Call->getNumArgOperands() != BpfProbeReadNumArgs) + return false; + + if (ProbeAddr && Call->getArgOperand(BpfProbeReadSrcAddrArg) != ProbeAddr) + return false; + + const Value *Operand = Call->getCalledValue(); + if (const Constant *CV = dyn_cast(Operand)) { + if (const ConstantExpr *CE = dyn_cast(CV)) { + if (CE->getNumOperands() != 1) + return false; + + if (const ConstantInt *CI = dyn_cast(CE->getOperand(0))) { + if (CI->getValue().getZExtValue() == BpfProbeReadCall) + return true; + } + } + } + + return false; +} + +/// Strip all const/volatile/typedef qualifiers. +const DIType *BPFAbstractMemberAccess::stripQualifiers(const DIType *Ty) { + while (Ty) { + const auto *DTy = dyn_cast(Ty); + if (!DTy) + break; + + unsigned Tag = DTy->getTag(); + if (Tag != dwarf::DW_TAG_const_type && Tag != dwarf::DW_TAG_volatile_type && + Tag != dwarf::DW_TAG_typedef) + break; + + Ty = DTy->getBaseType().resolve(); + } + return Ty; +} + +/// Given an IR struct type, compute debuginfo structure member index. +uint32_t +BPFAbstractMemberAccess::computeDIMemberIndex(const DICompositeType *DIStruct, + const StructType *SType, + uint32_t STIndex) { + const DINodeArray DIElements = DIStruct->getElements(); + uint32_t STIdx = 0, DIIdx = 0; + int32_t OverCountedBits = 0; + + for (auto &STElement : SType->elements()) { + if (STIdx == STIndex) + return DIIdx; + + DIDerivedType *DIMember = cast(DIElements[DIIdx]); + if (!DIMember->isBitField()) { + STIdx++; + DIIdx++; + continue; + } + + // If the struct has bitfield, Index does not represent + // the position of the field in the DIStruct. Rather, + // all adjacent bitfields are collapsed into one or more types + // in the IR struct definition. + const auto *CType = dyn_cast(STElement); + uint32_t STSize; + if (!CType) { + STSize = STElement->getPrimitiveSizeInBits(); + } else { + const auto *AType = dyn_cast(CType); + assert(AType); + STSize = AType->getNumElements() * + AType->getElementType()->getPrimitiveSizeInBits(); + } + + int32_t AccuBitSize = -OverCountedBits; + while (true) { + uint32_t MemberBits = DIMember->getSizeInBits(); + if (AccuBitSize + MemberBits > STSize) { + OverCountedBits = STSize - AccuBitSize; + break; + } + AccuBitSize += MemberBits; + DIIdx++; + + DIMember = cast(DIElements[DIIdx]); + if (!DIMember->isBitField()) { + OverCountedBits = 0; + break; + } + } + + STIdx++; + } + + llvm_unreachable("Internal error in computeDIMemberIndex\n"); +} + +void BPFAbstractMemberAccess::adjustTraverseTypes(const StructType *&SType, + const ArrayType *&AType, + uint64_t Index) { + if (SType) { + StructType *SSType = dyn_cast((SType->elements())[Index]); + if (SSType) + SType = SSType; + else { + AType = dyn_cast((SType->elements())[Index]); + SType = nullptr; + } + } else { + ArrayType *AAType = dyn_cast(AType->getElementType()); + if (AAType) + AType = AAType; + else { + SType = dyn_cast(AType->getElementType()); + AType = nullptr; + } + } +} + +// Compute struct member access string. +bool BPFAbstractMemberAccess::computeMemberAccessString( + GetElementPtrInst *GEP, const StructType *SType, + const DICompositeType *DIStruct, std::string &GVName, std::string &Prefix, + std::vector &ArrayBounds) { + // The number of initial structs and all subsequent member/array indexes + // must be constant. + // + // Unions are handled differently at IR level. Trying to do a best effort + // approximation here. + // . SType is the struct type at that level or nullptr if not struct type + // . DIStruct is the debuginfo struct type at that level or nullptr + // if not struct type + // . At the end of each iteration, next level SType and DIStruct is + // computed. + bool IsUnion = false; + std::string IntValues; + uint32_t InitialValue = 0; + int NumRemainingDim = -1; + std::string StructName = DIStruct->getName(); + const ArrayType *AType = nullptr; + for (unsigned i = 1, E = GEP->getNumOperands(); i != E; ++i) { + const Value *V = GEP->getOperand(i); + const auto *IntVal = dyn_cast(V); + + // The member access has to have const index. + if (!IntVal) + return false; + + uint64_t Index = IntVal->getValue().getLimitedValue(); + + // First index is always # of structs or array of structs. + // After that followed by array indices and struct member + // access indices. + if (i <= 1 + ArrayBounds.size()) { + uint32_t R = Index; + if (i == 1) { + for (auto Bounds : ArrayBounds) + R = R * Bounds; + } else { + for (unsigned J = i - 1, N = ArrayBounds.size(); J < N; ++J) + R = R * ArrayBounds[J]; + } + InitialValue += R; + continue; + } + + // This index is corresponding to a struct with a single member representing + // the union. + if (IsUnion) { + assert(Index == 0); + + // Find union member with largest size. + uint32_t I = 0, MaxElemSize = 0, MaxElemIndex = 0; + const DINodeArray Elements = DIStruct->getElements(); + for (auto Element : Elements) { + auto E = cast(Element); + uint64_t ElemSize = E->getSizeInBits(); + if (ElemSize > MaxElemSize) { + MaxElemSize = ElemSize; + MaxElemIndex = I; + } + I++; + } + + // Find the element with maximum size + const auto *DDTy = cast(Elements[MaxElemIndex]); + const auto *BaseTy = DDTy->getBaseType().resolve(); + const auto *CTy = dyn_cast(BaseTy); + DIStruct = CTy; + + // If the next member is a struct, add member selector + if (DIStruct) + IntValues += ":" + std::to_string(MaxElemIndex); + + IsUnion = CTy && CTy->getTag() == dwarf::DW_TAG_union_type; + adjustTraverseTypes(SType, AType, Index); + + continue; + } + + // DIStruct may be NULL here due to proceding union + if (!DIStruct) { + IntValues += ":" + std::to_string(Index); + break; + } + + auto Tag = DIStruct->getTag(); + if (Tag == dwarf::DW_TAG_structure_type) { + uint32_t DIIndex = computeDIMemberIndex(DIStruct, SType, Index); + + const DINodeArray Elements = DIStruct->getElements(); + assert(DIIndex < Elements.size()); + const auto *DDTy = cast(Elements[DIIndex]); + + const auto *BaseTy = stripQualifiers(DDTy->getBaseType().resolve()); + const auto *MemberCTy = dyn_cast(BaseTy); + DIStruct = MemberCTy; + + if (MemberCTy) { + auto CTag = MemberCTy->getTag(); + if (CTag == dwarf::DW_TAG_union_type && !MemberCTy->isForwardDecl()) + IsUnion = true; + } + IntValues += ":" + std::to_string(DIIndex); + } else if (Tag == dwarf::DW_TAG_array_type) { + if (NumRemainingDim == -1) + NumRemainingDim = DIStruct->getElements().size() - 1; + + if (NumRemainingDim == 0) { + const auto *BaseTy = stripQualifiers(DIStruct->getBaseType().resolve()); + const auto *ElementCTy = dyn_cast(BaseTy); + DIStruct = ElementCTy; + NumRemainingDim = -1; + } else { + NumRemainingDim--; + } + IntValues += ":" + std::to_string(Index); + } else { + llvm_unreachable( + "Internal error in computeMemberAccessString: unknown DIType tag\n"); + } + + adjustTraverseTypes(SType, AType, Index); + } + + // Construct the global variable name, which resembers + // GetElementPtrInst. + if (Prefix.size()) { + GVName = Prefix + std::to_string(InitialValue) + + StringRef(IntValues).str() + ":"; + } else { + GVName = "__BTF_" + std::to_string(InitialValue) + ":" + + (StructName + StringRef(IntValues)).str() + ":"; + } + + if (SType && DIStruct) + STypeToDIStruct[SType->getName()] = std::make_pair(DIStruct, GVName); + + return true; +} + +/// Check whether a GEP is a candidate and if it is adds to WorkList. +bool BPFAbstractMemberAccess::checkAndAddGEP(GetElementPtrInst *GEP, + GEPCandidateSet &WorkList) { + const Type *SrcElemType = GEP->getSourceElementType(); + + // SrcElemType could be integer or composite type to step through + // If integer type, no further transformations. + const auto *IType = dyn_cast(SrcElemType); + if (IType) + return true; + + const auto *CType = dyn_cast(SrcElemType); + if (!CType) + return false; + + // Only handle struct and array types. + std::vector ArrayBounds; + const auto *AType = dyn_cast(CType); + while (AType) { + ArrayBounds.push_back(AType->getNumElements()); + SrcElemType = AType->getElementType(); + CType = dyn_cast(SrcElemType); + if (!CType) + break; + AType = dyn_cast(CType); + } + + if (!CType) + return false; + + const auto *SType = dyn_cast(CType); + if (!SType) + return false; + + // Struct name is needed to pass info to later non-IR based passes. + // FIXME: we are not able to handle starting type as a union yet. + if (!SType->hasName() || !SType->getName().startswith("struct.")) + return false; + + // Find the corresponding DI struct type + const DICompositeType *DIStruct = getDIStruct(SType->getName().substr(7)); + std::string GVName_Prefix; + if (!DIStruct) { + if (STypeToDIStruct.find(SType->getName()) != STypeToDIStruct.end()) { + DIStruct = STypeToDIStruct[SType->getName()].first; + GVName_Prefix = STypeToDIStruct[SType->getName()].second + '$'; + } + if (!DIStruct) + return false; + } + + std::string GVName; + if (!computeMemberAccessString(GEP, SType, DIStruct, GVName, GVName_Prefix, + ArrayBounds)) + return false; + + WorkList[GEP] = GVName; + return true; +} + +void BPFAbstractMemberAccess::collectGEPs( + Function &F, + std::map> &TmpBpfProbeCalls) { + // Collect all GEPs directly feeding into the BpfProbeCall. + std::set GEPs; + for (auto &BB : F) + for (auto &I : BB) { + auto *GEP = dyn_cast(&I); + if (!GEP) + continue; + GEPs.insert(GEP); + + for (User *GU : GEP->users()) { + Instruction *Inst = dyn_cast(GU); + if (!Inst) + continue; + + if (auto *BI = dyn_cast(Inst)) { + for (User *BU : BI->users()) { + auto *Call = dyn_cast(BU); + if (!Call) + continue; + if (isBpfProbeReadCall(Call, BI)) + TmpBpfProbeCalls[GEP].insert(Call); + } + } else if (auto *Call = dyn_cast(Inst)) { + if (isBpfProbeReadCall(Call, GEP)) + TmpBpfProbeCalls[GEP].insert(Call); + } + } + } + + // Build GEP dependencies. + bool Changed = true; + while (Changed) { + Changed = false; + for (auto &GEP : GEPs) { + for (User *GU : GEP->users()) { + Instruction *Inst = dyn_cast(GU); + if (!Inst) + continue; + + // FIXME: only handle direct chaining of GetElementPtrInst insts. + // If BitCast is involved, union is involved, skip it for now. + auto *GetElemPtr = dyn_cast(Inst); + if (!GetElemPtr) + continue; + + // Already recorded. + if (GEPDependInsts.find(GetElemPtr) != GEPDependInsts.end()) + continue; + + // Not recorded for this function. + if (TmpBpfProbeCalls.find(GetElemPtr) == TmpBpfProbeCalls.end()) + continue; + + // FIXME: we only did one level recursion + // Tried complex examples, multiple levels of nested anonymous + // structs llvm seems only have one nesting level. Will fix if + // later more nesting level is discovered. + GEPDependInsts[GetElemPtr] = GEP; + Changed = true; + } + } + } +} + +/// Process one GetElementPtr inst. +void BPFAbstractMemberAccess::processGEP( + GetElementPtrInst *GEP, GEPCandidateSet &WorkList, + std::map> &TmpBpfProbeCalls, + std::set &VisitedGEPs) { + if (VisitedGEPs.find(GEP) != VisitedGEPs.end()) + return; + VisitedGEPs.insert(GEP); + + if (GEPDependInsts.find(GEP) != GEPDependInsts.end()) + processGEP(GEPDependInsts[GEP], WorkList, TmpBpfProbeCalls, VisitedGEPs); + + if (!checkAndAddGEP(GEP, WorkList)) { + TmpBpfProbeCalls.erase(GEP); + } +} + +/// Process all GetElementPtr insts. +void BPFAbstractMemberAccess::processGEPs( + GEPCandidateSet &WorkList, + std::map> &TmpBpfProbeCalls) { + // Process dependencies first + std::set VisitedGEPs; + for (auto &DEP : GEPDependInsts) { + processGEP(DEP.second, WorkList, TmpBpfProbeCalls, VisitedGEPs); + processGEP(DEP.first, WorkList, TmpBpfProbeCalls, VisitedGEPs); + } + + // Process remaining GEPs in TmpBpfProbeCalls + for (auto &BpfGEP : TmpBpfProbeCalls) + processGEP(BpfGEP.first, WorkList, TmpBpfProbeCalls, VisitedGEPs); +} + +/// Find out all GetElementPtr candidates. +void BPFAbstractMemberAccess::computeGEPCandidates( + Module &M, GEPCandidateSet &WorkList, std::set &BpfProbeCalls) { + for (Function &F : M) { + + // Collect all DITypes + collectDITypes(M, F); + + // Collect all eligible GEPs + std::map> TmpBpfProbeCalls; + collectGEPs(F, TmpBpfProbeCalls); + + // Process all GEPs + processGEPs(WorkList, TmpBpfProbeCalls); + + // Add to BpfProbeCalls list + for (auto Call : TmpBpfProbeCalls) + for (auto CallInst : Call.second) + BpfProbeCalls.insert(CallInst); + } +} + +/// Warn not-processed bpf_probe_read calls. +void BPFAbstractMemberAccess::checkBpfProbeCalls( + Module &M, std::set &BpfProbeCalls) { + for (Function &F : M) + for (auto &BB : F) + for (auto &I : BB) { + auto *Call = dyn_cast(&I); + if (!Call) + continue; + + if (!isBpfProbeReadCall(Call, nullptr)) + continue; + + if (BpfProbeCalls.find(Call) == BpfProbeCalls.end()) + errs() << "WARNING: missing one bpf probe call in func " + << F.getName() << "\n"; + } +} + +void BPFAbstractMemberAccess::transformGEPCandidates( + Module &M, GEPCandidateSet &WorkList) { + for (auto &P : WorkList) { + auto GEP = P.first; + auto GVName = P.second; + BasicBlock *BB = GEP->getParent(); + + // For any original GEP like + // %dev1 = getelementptr inbounds %struct.sk_buff, %struct.sk_buff* %2, + // i64 0, i32 0, i32 0, i32 2, i32 0 + // %4 = bitcast %struct.net_device** %dev1 to i8* + // it is transformed to: + // %6 = load __BTF_0:sk_buff:0:0:2:0: + // %7 = bitcast %struct.sk_buff* %2 to i8* + // %8 = getelementptr i8, i8* %7, %6 + // %9 = bitcast i8* %8 to %struct.net_device** + // %4 = bitcast %struct.net_device** %9 to i8* + // The original getelementptr inst is removed. + + // Construct a global variable with proper attribute so later + // passes can recognize it. + GlobalVariable *GV; + if (GEPGlobals.find(GVName) == GEPGlobals.end()) { + GV = new GlobalVariable(M, Type::getInt64Ty(BB->getContext()), false, + GlobalVariable::ExternalLinkage, NULL, GVName); + GV->addAttribute(AmaAttr); + GEPGlobals[GVName] = GV; + } else { + GV = GEPGlobals[GVName]; + } + + // Load the global variable + auto *LDInst = new LoadInst(Type::getInt64Ty(BB->getContext()), GV); + BB->getInstList().insert(GEP->getIterator(), LDInst); + + // Generae a BitCast + auto *BCInst3 = new BitCastInst(GEP->getPointerOperand(), + Type::getInt8PtrTy(BB->getContext())); + BB->getInstList().insert(GEP->getIterator(), BCInst3); + + // Generate a GetElementPtr + auto *GEP2 = GetElementPtrInst::Create(Type::getInt8Ty(BB->getContext()), + BCInst3, LDInst); + BB->getInstList().insert(GEP->getIterator(), GEP2); + + // Generae a BitCast + auto *BCInst2 = new BitCastInst(GEP2, GEP->getType()); + BB->getInstList().insert(GEP->getIterator(), BCInst2); + + GEP->replaceAllUsesWith(BCInst2); + GEP->eraseFromParent(); + } +} Index: lib/Target/BPF/BPFAsmPrinter.cpp =================================================================== --- lib/Target/BPF/BPFAsmPrinter.cpp +++ lib/Target/BPF/BPFAsmPrinter.cpp @@ -37,7 +37,7 @@ public: explicit BPFAsmPrinter(TargetMachine &TM, std::unique_ptr Streamer) - : AsmPrinter(TM, std::move(Streamer)) {} + : AsmPrinter(TM, std::move(Streamer)), BTF(nullptr) {} StringRef getPassName() const override { return "BPF Assembly Printer"; } bool doInitialization(Module &M) override; @@ -48,6 +48,9 @@ const char *ExtraCode, raw_ostream &O) override; void EmitInstruction(const MachineInstr *MI) override; + +private: + BTFDebug *BTF; }; } // namespace @@ -55,8 +58,10 @@ AsmPrinter::doInitialization(M); if (MAI->doesSupportDebugInformation()) { - Handlers.emplace_back(llvm::make_unique(this), "emit", - "Debug Info Emission", "BTF", "BTF Emission"); + BTF = new BTFDebug(this); + Handlers.push_back(HandlerInfo(std::unique_ptr(BTF), "emit", + "Debug Info Emission", "BTF", + "BTF Emission")); } return false; @@ -131,11 +136,12 @@ } void BPFAsmPrinter::EmitInstruction(const MachineInstr *MI) { - - BPFMCInstLower MCInstLowering(OutContext, *this); - MCInst TmpInst; - MCInstLowering.Lower(MI, TmpInst); + + if (!BTF || !BTF->InstLower(MI, TmpInst)) { + BPFMCInstLower MCInstLowering(OutContext, *this); + MCInstLowering.Lower(MI, TmpInst); + } EmitToStreamer(*OutStreamer, TmpInst); } Index: lib/Target/BPF/BPFMISimplifyPatchable.cpp =================================================================== --- /dev/null +++ lib/Target/BPF/BPFMISimplifyPatchable.cpp @@ -0,0 +1,161 @@ +//===----- BPFMISimplifyPatchable.cpp - MI Simplify Patchable Insts -------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This pass targets a subset of instructions like below +// ld_imm64 r1, @global +// ldd r2, r1, 0 +// add r3, struct_base_reg, r2 +// +// Here @global should either present a AMA (abstruct member access) or +// a patchable extern variable. And these two kinds of accesses +// are subject to bpf load time patching. After this pass, the +// code becomes +// ld_imm64 r1, @global +// add r3, struct_base_reg, r1 +// +// Eventually, at BTF output stage, a relocation record will be generated +// for ld_imm64 which should be replaced later by bpf loader: +// r1 = or +// add r3, struct_base_reg, r1 +// or +// ld_imm64 r1, +// add r3, struct_base_reg, r1 +// +//===----------------------------------------------------------------------===// + +#include "BPF.h" +#include "BPFInstrInfo.h" +#include "BPFTargetMachine.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" + +using namespace llvm; + +#define DEBUG_TYPE "bpf-mi-simplify-patchable" + +namespace { + +struct BPFMISimplifyPatchable : public MachineFunctionPass { + + static char ID; + const BPFInstrInfo *TII; + MachineFunction *MF; + + BPFMISimplifyPatchable() : MachineFunctionPass(ID) { + initializeBPFMISimplifyPatchablePass(*PassRegistry::getPassRegistry()); + } + +private: + // Initialize class variables. + void initialize(MachineFunction &MFParm); + + bool removeLD(void); + +public: + // Main entry point for this pass. + bool runOnMachineFunction(MachineFunction &MF) override { + if (!skipFunction(MF.getFunction())) { + initialize(MF); + } + return removeLD(); + } +}; + +// Initialize class variables. +void BPFMISimplifyPatchable::initialize(MachineFunction &MFParm) { + MF = &MFParm; + TII = MF->getSubtarget().getInstrInfo(); + LLVM_DEBUG(dbgs() << "*** BPF simplify patchable insts pass ***\n\n"); +} + +/// Remove unneeded Load instructions. +bool BPFMISimplifyPatchable::removeLD() { + MachineRegisterInfo *MRI = &MF->getRegInfo(); + MachineInstr *ToErase = nullptr; + bool Changed = false; + + for (MachineBasicBlock &MBB : *MF) { + for (MachineInstr &MI : MBB) { + if (ToErase) { + ToErase->eraseFromParent(); + ToErase = nullptr; + } + + // Ensure the register format is LOAD , , 0 + if (MI.getOpcode() != BPF::LDD && MI.getOpcode() != BPF::LDW && + MI.getOpcode() != BPF::LDH && MI.getOpcode() != BPF::LDB && + MI.getOpcode() != BPF::LDW32 && MI.getOpcode() != BPF::LDH32 && + MI.getOpcode() != BPF::LDB32) + continue; + + if (!MI.getOperand(0).isReg() || !MI.getOperand(1).isReg()) + continue; + + if (!MI.getOperand(2).isImm() || MI.getOperand(2).getImm()) + continue; + + unsigned DstReg = MI.getOperand(0).getReg(); + unsigned SrcReg = MI.getOperand(1).getReg(); + int64_t ImmVal = MI.getOperand(2).getImm(); + + MachineInstr *DefInst = MRI->getUniqueVRegDef(SrcReg); + if (!DefInst) + continue; + + bool IsCandidate = false; + if (DefInst->getOpcode() == BPF::LD_imm64) { + const MachineOperand &MO = DefInst->getOperand(1); + if (MO.isGlobal()) { + const GlobalValue *GVal = MO.getGlobal(); + auto *GVar = dyn_cast(GVal); + if (GVar) { + // Global variables representing structure offset or + // patchable extern globals. + if (GVar->hasAttribute(AmaAttr)) { + assert(ImmVal == 0); + IsCandidate = true; + } else if (!GVar->hasInitializer() && GVar->hasExternalLinkage() && + GVar->getSection() == PatchableExtSecName) { + if (ImmVal == 0) + IsCandidate = true; + else + errs() << "WARNING: unhandled patchable extern " + << GVar->getName() << " with load offset " << ImmVal + << "\n"; + } + } + } + } + + if (!IsCandidate) + continue; + + auto Begin = MRI->use_begin(DstReg), End = MRI->use_end(); + decltype(End) NextI; + for (auto I = Begin; I != End; I = NextI) { + NextI = std::next(I); + I->setReg(SrcReg); + } + + ToErase = &MI; + Changed = true; + } + } + + return Changed; +} + +} // namespace + +INITIALIZE_PASS(BPFMISimplifyPatchable, DEBUG_TYPE, + "BPF PreEmit SimplifyPatchable", false, false) + +char BPFMISimplifyPatchable::ID = 0; +FunctionPass *llvm::createBPFMISimplifyPatchablePass() { + return new BPFMISimplifyPatchable(); +} Index: lib/Target/BPF/BPFSubtarget.h =================================================================== --- lib/Target/BPF/BPFSubtarget.h +++ lib/Target/BPF/BPFSubtarget.h @@ -57,6 +57,9 @@ // whether we should enable MCAsmInfo DwarfUsesRelocationsAcrossSections bool UseDwarfRIS; + // whether struct/union member offset relocation should be generated. + bool HasOffsetReloc; + public: // This constructor initializes the data members to match that // of the specified triple. @@ -72,6 +75,7 @@ bool getHasJmp32() const { return HasJmp32; } bool getHasAlu32() const { return HasAlu32; } bool getUseDwarfRIS() const { return UseDwarfRIS; } + bool getHasOffsetReloc() const { return HasOffsetReloc; } const BPFInstrInfo *getInstrInfo() const override { return &InstrInfo; } const BPFFrameLowering *getFrameLowering() const override { Index: lib/Target/BPF/BPFSubtarget.cpp =================================================================== --- lib/Target/BPF/BPFSubtarget.cpp +++ lib/Target/BPF/BPFSubtarget.cpp @@ -38,6 +38,7 @@ HasJmp32 = false; HasAlu32 = false; UseDwarfRIS = false; + HasOffsetReloc = false; } void BPFSubtarget::initSubtargetFeatures(StringRef CPU, StringRef FS) { Index: lib/Target/BPF/BPFTargetMachine.cpp =================================================================== --- lib/Target/BPF/BPFTargetMachine.cpp +++ lib/Target/BPF/BPFTargetMachine.cpp @@ -13,6 +13,7 @@ #include "BPFTargetMachine.h" #include "BPF.h" #include "MCTargetDesc/BPFMCAsmInfo.h" +#include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" #include "llvm/CodeGen/TargetPassConfig.h" @@ -33,6 +34,7 @@ RegisterTargetMachine Z(getTheBPFTarget()); PassRegistry &PR = *PassRegistry::getPassRegistry(); + initializeBPFAbstractMemberAccessPass(PR); initializeBPFMIPeepholePass(PR); } @@ -67,6 +69,7 @@ static_cast(const_cast(AsmInfo.get())); MAI->setDwarfUsesRelocationsAcrossSections(!Subtarget.getUseDwarfRIS()); } + namespace { // BPF Code Generator Pass Configuration Options. class BPFPassConfig : public TargetPassConfig { @@ -78,6 +81,7 @@ return getTM(); } + void addIRPasses() override; bool addInstSelector() override; void addMachineSSAOptimization() override; void addPreEmitPass() override; @@ -88,6 +92,13 @@ return new BPFPassConfig(*this, PM); } +void BPFPassConfig::addIRPasses() { + + addPass(createBPFAbstractMemberAccess(&getBPFTargetMachine())); + + TargetPassConfig::addIRPasses(); +} + // Install an instruction selector pass using // the ISelDag to gen BPF code. bool BPFPassConfig::addInstSelector() { @@ -97,6 +108,8 @@ } void BPFPassConfig::addMachineSSAOptimization() { + addPass(createBPFMISimplifyPatchablePass()); + // The default implementation must be called first as we want eBPF // Peephole ran at last. TargetPassConfig::addMachineSSAOptimization(); Index: lib/Target/BPF/BTF.h =================================================================== --- lib/Target/BPF/BTF.h +++ lib/Target/BPF/BTF.h @@ -17,7 +17,7 @@ /// /// The binary layout for .BTF.ext section: /// struct ExtHeader -/// FuncInfo and LineInfo subsections +/// FuncInfo, LineInfo, OffsetReloc and ExternReloc subsections /// The FuncInfo subsection is defined as below: /// BTFFuncInfo Size /// struct SecFuncInfo for ELF section #1 @@ -32,6 +32,20 @@ /// struct SecLineInfo for ELF section #2 /// A number of struct BPFLineInfo for ELF section #2 /// ... +/// The OffsetReloc subsection is defined as below: +/// BPFOffsetReloc Size +/// struct SecOffsetReloc for ELF section #1 +/// A number of struct BPFOffsetReloc for ELF section #1 +/// struct SecOffsetReloc for ELF section #2 +/// A number of struct BPFOffsetReloc for ELF section #2 +/// ... +/// The ExternReloc subsection is defined as below: +/// BPFExternReloc Size +/// struct SecExternReloc for ELF section #1 +/// A number of struct BPFExternReloc for ELF section #1 +/// struct SecExternReloc for ELF section #2 +/// A number of struct BPFExternReloc for ELF section #2 +/// ... /// /// The section formats are also defined at /// https://github.com/torvalds/linux/blob/master/include/uapi/linux/btf.h @@ -49,7 +63,7 @@ /// Sizes in bytes of various things in the BTF format. enum { HeaderSize = 24, - ExtHeaderSize = 24, + ExtHeaderSize = 40, CommonTypeSize = 12, BTFArraySize = 12, BTFEnumSize = 8, @@ -58,8 +72,12 @@ BTFDataSecVarSize = 12, SecFuncInfoSize = 8, SecLineInfoSize = 8, + SecOffsetRelocSize = 8, + SecExternRelocSize = 8, BPFFuncInfoSize = 8, - BPFLineInfoSize = 16 + BPFLineInfoSize = 16, + BPFOffsetRelocSize = 16, + BPFExternRelocSize = 8, }; /// The .BTF section header definition. @@ -191,10 +209,14 @@ uint8_t Flags; uint32_t HdrLen; - uint32_t FuncInfoOff; ///< Offset of func info section - uint32_t FuncInfoLen; ///< Length of func info section - uint32_t LineInfoOff; ///< Offset of line info section - uint32_t LineInfoLen; ///< Length of line info section + uint32_t FuncInfoOff; ///< Offset of func info section + uint32_t FuncInfoLen; ///< Length of func info section + uint32_t LineInfoOff; ///< Offset of line info section + uint32_t LineInfoLen; ///< Length of line info section + uint32_t OffsetRelocOff; ///< Offset of offset reloc section + uint32_t OffsetRelocLen; ///< Length of offset reloc section + uint32_t ExternRelocOff; ///< Offset of extern reloc section + uint32_t ExternRelocLen; ///< Length of extern reloc section }; /// Specifying one function info. @@ -220,10 +242,36 @@ /// Specifying line info's in one section. struct SecLineInfo { - uint32_t SecNameOff; ///< Section name index in the .BTF string tble + uint32_t SecNameOff; ///< Section name index in the .BTF string table uint32_t NumLineInfo; ///< Number of line info's in this section }; +/// Specifying one offset relocation. +struct BPFOffsetReloc { + uint32_t InsnOffset; ///< Byte offset in this section + uint32_t TypeID; ///< TypeID for the relocation + uint32_t OffsetNameOff; ///< The string to traverse types + uint32_t Dependency; ///< Depending on another BPFOffsetReloc +}; + +/// Specifying offset relocation's in one section. +struct SecOffsetReloc { + uint32_t SecNameOff; ///< Section name index in the .BTF string table + uint32_t NumOffsetReloc; ///< Number of offset reloc's in this section +}; + +/// Specifying one offset relocation. +struct BPFExternReloc { + uint32_t InsnOffset; ///< Byte offset in this section + uint32_t ExternNameOff; ///< The string for external variable +}; + +/// Specifying extern relocation's in one section. +struct SecExternReloc { + uint32_t SecNameOff; ///< Section name index in the .BTF string table + uint32_t NumExternReloc; ///< Number of extern reloc's in this section +}; + } // End namespace BTF. } // End namespace llvm. Index: lib/Target/BPF/BTFDebug.h =================================================================== --- lib/Target/BPF/BTFDebug.h +++ lib/Target/BPF/BTFDebug.h @@ -17,6 +17,7 @@ #include "llvm/ADT/StringMap.h" #include "llvm/CodeGen/DebugHandlerBase.h" #include +#include #include "BTF.h" namespace llvm { @@ -32,10 +33,12 @@ class BTFTypeBase { protected: uint8_t Kind; + bool IsCompleted; uint32_t Id; struct BTF::CommonType BTFType; public: + BTFTypeBase() : IsCompleted(false) {} virtual ~BTFTypeBase() = default; void setId(uint32_t Id) { this->Id = Id; } uint32_t getId() { return Id; } @@ -54,11 +57,13 @@ /// volatile, typedef and restrict. class BTFTypeDerived : public BTFTypeBase { const DIDerivedType *DTy; + bool NeedsFixup; public: - BTFTypeDerived(const DIDerivedType *Ty, unsigned Tag); + BTFTypeDerived(const DIDerivedType *Ty, unsigned Tag, bool NeedsFixup); void completeType(BTFDebug &BDebug); void emitType(MCStreamer &OS); + void setPointeeType(uint32_t PointeeType); }; /// Handle struct or union forward declaration. @@ -100,13 +105,15 @@ /// Handle array type. class BTFTypeArray : public BTFTypeBase { + uint32_t ElemSize; struct BTF::BTFArray ArrayInfo; public: - BTFTypeArray(uint32_t ElemTypeId, uint32_t NumElems); + BTFTypeArray(uint32_t ElemTypeId, uint32_t ElemSize, 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,6 +130,9 @@ } 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. @@ -218,6 +228,22 @@ uint32_t ColumnNum; ///< the column number }; +/// Represent one offset relocation. +struct BTFOffsetReloc { + const MCSymbol *Label; ///< MCSymbol identifying insn for the reloc + std::string OrigTypeName; ///< Original type name + std::string TypeName; ///< Type name in the relocation record + uint32_t TypeID; ///< Type ID + uint32_t OffsetNameOff; ///< The string to traverse types + uint32_t Dependency; ///< Dependency +}; + +/// Represent one extern relocation. +struct BTFExternReloc { + const MCSymbol *Label; ///< MCSymbol identifying insn for the reloc + uint32_t ExternNameOff; ///< The extern variable name +}; + /// Collect and emit BTF information. class BTFDebug : public DebugHandlerBase { MCStreamer &OS; @@ -230,9 +256,15 @@ std::unordered_map DIToIdMap; std::map> FuncInfoTable; std::map> LineInfoTable; + std::map> OffsetRelocTable; + std::map> ExternRelocTable; StringMap> FileContent; - std::map> - DataSecEntries; + std::map> DataSecEntries; + std::vector StructTypes; + std::vector ArrayTypes; + std::map AccessOffsets; + std::map>> + FixupDerivedTypes; /// Add types to TypeEntries. /// @{ @@ -245,7 +277,8 @@ /// IR type visiting functions. /// @{ void visitTypeEntry(const DIType *Ty); - void visitTypeEntry(const DIType *Ty, uint32_t &TypeId); + void visitTypeEntry(const DIType *Ty, uint32_t &TypeId, bool CheckPointer, + bool SeenPointer); void visitBasicType(const DIBasicType *BTy, uint32_t &TypeId); void visitSubroutineType( const DISubroutineType *STy, bool ForSubprog, @@ -258,7 +291,8 @@ uint32_t &TypeId); void visitArrayType(const DICompositeType *ATy, uint32_t &TypeId); void visitEnumType(const DICompositeType *ETy, uint32_t &TypeId); - void visitDerivedType(const DIDerivedType *DTy, uint32_t &TypeId); + void visitDerivedType(const DIDerivedType *DTy, uint32_t &TypeId, + bool CheckPointer, bool SeenPointer); /// @} /// Get the file content for the subprogram. Certain lines of the file @@ -272,6 +306,23 @@ /// Generate types and variables for globals. void processGlobals(void); + /// Generate one offset relocation record. + void generateOffsetReloc(const MachineInstr *MI, const MCSymbol *ORSym, + std::string TypeName); + + /// Set the to-be-traversed Struct/Array Type based on TypeId. + void setTypeFromId(uint32_t TypeId, BTFTypeStruct **PrevStructType, + BTFTypeArray **PrevArrayType); + + /// Populating unprocessed struct type. + void populateStructType(const MachineInstr *MI, std::string StructName); + bool populateStructType(const DIType *Ty, std::string StructName); + bool populateStructType(const DIType *Ty, std::string StructName, + std::set &PopulatedTypes); + + /// Process LD_imm64 instructions. + void processLDimm64(const MachineInstr *MI); + /// Emit common header of .BTF and .BTF.ext sections. void emitCommonHeader(); @@ -291,6 +342,9 @@ public: BTFDebug(AsmPrinter *AP); + /// + bool InstLower(const MachineInstr *MI, MCInst &OutMI); + /// Get the special array index type id. uint32_t getArrayIndexTypeId() { assert(ArrayIndexTypeId); Index: lib/Target/BPF/BTFDebug.cpp =================================================================== --- lib/Target/BPF/BTFDebug.cpp +++ lib/Target/BPF/BTFDebug.cpp @@ -11,6 +11,8 @@ //===----------------------------------------------------------------------===// #include "BTFDebug.h" +#include "BPF.h" +#include "MCTargetDesc/BPFMCTargetDesc.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/MachineModuleInfo.h" @@ -37,8 +39,9 @@ OS.EmitIntValue(BTFType.Size, 4); } -BTFTypeDerived::BTFTypeDerived(const DIDerivedType *DTy, unsigned Tag) - : DTy(DTy) { +BTFTypeDerived::BTFTypeDerived(const DIDerivedType *DTy, unsigned Tag, + bool NeedsFixup) + : DTy(DTy), NeedsFixup(NeedsFixup) { switch (Tag) { case dwarf::DW_TAG_pointer_type: Kind = BTF::BTF_KIND_PTR; @@ -62,8 +65,15 @@ } void BTFTypeDerived::completeType(BTFDebug &BDebug) { + if (IsCompleted) + return; + IsCompleted = true; + BTFType.NameOff = BDebug.addString(DTy->getName()); + if (NeedsFixup) + return; + // The base type for PTR/CONST/VOLATILE could be void. const DIType *ResolvedType = DTy->getBaseType().resolve(); if (!ResolvedType) { @@ -78,6 +88,10 @@ void BTFTypeDerived::emitType(MCStreamer &OS) { BTFTypeBase::emitType(OS); } +void BTFTypeDerived::setPointeeType(uint32_t PointeeType) { + BTFType.Type = PointeeType; +} + /// Represent a struct/union forward declaration. BTFTypeFwd::BTFTypeFwd(StringRef Name, bool IsUnion) : Name(Name) { Kind = BTF::BTF_KIND_FWD; @@ -86,6 +100,10 @@ } void BTFTypeFwd::completeType(BTFDebug &BDebug) { + if (IsCompleted) + return; + IsCompleted = true; + BTFType.NameOff = BDebug.addString(Name); } @@ -119,6 +137,10 @@ } void BTFTypeInt::completeType(BTFDebug &BDebug) { + if (IsCompleted) + return; + IsCompleted = true; + BTFType.NameOff = BDebug.addString(Name); } @@ -135,6 +157,10 @@ } void BTFTypeEnum::completeType(BTFDebug &BDebug) { + if (IsCompleted) + return; + IsCompleted = true; + BTFType.NameOff = BDebug.addString(ETy->getName()); DINodeArray Elements = ETy->getElements(); @@ -157,7 +183,9 @@ } } -BTFTypeArray::BTFTypeArray(uint32_t ElemTypeId, uint32_t NumElems) { +BTFTypeArray::BTFTypeArray(uint32_t ElemTypeId, uint32_t ElemSize, + uint32_t NumElems) + : ElemSize(ElemSize) { Kind = BTF::BTF_KIND_ARRAY; BTFType.NameOff = 0; BTFType.Info = Kind << 24; @@ -169,6 +197,9 @@ /// Represent a BTF array. void BTFTypeArray::completeType(BTFDebug &BDebug) { + if (IsCompleted) + return; + IsCompleted = true; // The IR does not really have a type for the index. // A special type for array index should have been @@ -184,6 +215,12 @@ OS.EmitIntValue(ArrayInfo.Nelems, 4); } +void BTFTypeArray::getLocInfo(uint32_t Loc, uint32_t &LocOffset, + uint32_t &ElementTypeId) { + ElementTypeId = ArrayInfo.ElemType; + LocOffset = Loc * ElemSize; +} + /// Represent either a struct or a union. BTFTypeStruct::BTFTypeStruct(const DICompositeType *STy, bool IsStruct, bool HasBitField, uint32_t Vlen) @@ -194,6 +231,10 @@ } void BTFTypeStruct::completeType(BTFDebug &BDebug) { + if (IsCompleted) + return; + IsCompleted = true; + BTFType.NameOff = BDebug.addString(STy->getName()); // Add struct/union members. @@ -224,6 +265,17 @@ } } +std::string BTFTypeStruct::getName() { return STy->getName(); } + +void BTFTypeStruct::getMemberInfo(uint32_t Loc, uint32_t &MemberOffset, + uint32_t &MemberType) { + MemberType = Members[Loc].Type; + 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 @@ -238,6 +290,10 @@ } void BTFTypeFuncProto::completeType(BTFDebug &BDebug) { + if (IsCompleted) + return; + IsCompleted = true; + DITypeRefArray Elements = STy->getTypeArray(); auto RetType = Elements[0].resolve(); BTFType.Type = RetType ? BDebug.getTypeId(RetType) : 0; @@ -275,6 +331,10 @@ } void BTFTypeFunc::completeType(BTFDebug &BDebug) { + if (IsCompleted) + return; + IsCompleted = true; + BTFType.NameOff = BDebug.addString(Name); } @@ -417,6 +477,7 @@ auto TypeEntry = llvm::make_unique(CTy, IsStruct, HasBitField, VLen); + StructTypes.push_back(TypeEntry.get()); TypeId = addType(std::move(TypeEntry), CTy); // Visit all struct members. @@ -426,11 +487,14 @@ void BTFDebug::visitArrayType(const DICompositeType *CTy, uint32_t &TypeId) { // Visit array element type. - uint32_t ElemTypeId; - visitTypeEntry(CTy->getBaseType().resolve(), ElemTypeId); + uint32_t ElemTypeId, ElemSize; + const DIType *ElemType = CTy->getBaseType().resolve(); + visitTypeEntry(ElemType, ElemTypeId, false, false); + ElemSize = ElemType->getSizeInBits() >> 3; if (!CTy->getSizeInBits()) { - auto TypeEntry = llvm::make_unique(ElemTypeId, 0); + auto TypeEntry = llvm::make_unique(ElemTypeId, 0, 0); + ArrayTypes.push_back(TypeEntry.get()); ElemTypeId = addType(std::move(TypeEntry), CTy); } else { // Visit array dimensions. @@ -442,11 +506,14 @@ auto *CI = SR->getCount().dyn_cast(); int64_t Count = CI->getSExtValue(); - auto TypeEntry = llvm::make_unique(ElemTypeId, Count); + auto TypeEntry = + llvm::make_unique(ElemTypeId, ElemSize, Count); + ArrayTypes.push_back(TypeEntry.get()); if (I == 0) ElemTypeId = addType(std::move(TypeEntry), CTy); else ElemTypeId = addType(std::move(TypeEntry)); + ElemSize = ElemSize * Count; } } } @@ -498,13 +565,42 @@ } /// Handle pointer, typedef, const, volatile, restrict and member types. -void BTFDebug::visitDerivedType(const DIDerivedType *DTy, uint32_t &TypeId) { +void BTFDebug::visitDerivedType(const DIDerivedType *DTy, uint32_t &TypeId, + bool CheckPointer, bool SeenPointer) { unsigned Tag = DTy->getTag(); + /// Try to avoid chasing pointees, esp. structure pointees which may + /// unnecessary bring in a lot of types. + if (CheckPointer && !SeenPointer) { + SeenPointer = Tag == dwarf::DW_TAG_pointer_type; + } + + if (CheckPointer && SeenPointer) { + const DIType *Base = DTy->getBaseType().resolve(); + if (Base) { + if (const auto *CTy = dyn_cast(Base)) { + auto CTag = CTy->getTag(); + if ((CTag == dwarf::DW_TAG_structure_type || + CTag == dwarf::DW_TAG_union_type) && + !CTy->isForwardDecl()) { + /// Find a candidate, generate a fixup. Later on the struct/union + /// pointee type will be replaced with either a real type or + /// a forward declaration. + auto TypeEntry = llvm::make_unique(DTy, Tag, true); + auto &Fixup = FixupDerivedTypes[CTy->getName()]; + Fixup.first = CTag == dwarf::DW_TAG_union_type; + Fixup.second.push_back(TypeEntry.get()); + TypeId = addType(std::move(TypeEntry), DTy); + return; + } + } + } + } + if (Tag == dwarf::DW_TAG_pointer_type || Tag == dwarf::DW_TAG_typedef || Tag == dwarf::DW_TAG_const_type || Tag == dwarf::DW_TAG_volatile_type || Tag == dwarf::DW_TAG_restrict_type) { - auto TypeEntry = llvm::make_unique(DTy, Tag); + auto TypeEntry = llvm::make_unique(DTy, Tag, false); TypeId = addType(std::move(TypeEntry), DTy); } else if (Tag != dwarf::DW_TAG_member) { return; @@ -513,10 +609,15 @@ // Visit base type of pointer, typedef, const, volatile, restrict or // struct/union member. uint32_t TempTypeId = 0; - visitTypeEntry(DTy->getBaseType().resolve(), TempTypeId); + if (Tag == dwarf::DW_TAG_member) + visitTypeEntry(DTy->getBaseType().resolve(), TempTypeId, true, false); + else + visitTypeEntry(DTy->getBaseType().resolve(), TempTypeId, CheckPointer, + SeenPointer); } -void BTFDebug::visitTypeEntry(const DIType *Ty, uint32_t &TypeId) { +void BTFDebug::visitTypeEntry(const DIType *Ty, uint32_t &TypeId, + bool CheckPointer, bool SeenPointer) { if (!Ty || DIToIdMap.find(Ty) != DIToIdMap.end()) { TypeId = DIToIdMap[Ty]; return; @@ -530,14 +631,14 @@ else if (const auto *CTy = dyn_cast(Ty)) visitCompositeType(CTy, TypeId); else if (const auto *DTy = dyn_cast(Ty)) - visitDerivedType(DTy, TypeId); + visitDerivedType(DTy, TypeId, CheckPointer, SeenPointer); else llvm_unreachable("Unknown DIType"); } void BTFDebug::visitTypeEntry(const DIType *Ty) { uint32_t TypeId; - visitTypeEntry(Ty, TypeId); + visitTypeEntry(Ty, TypeId, false, false); } /// Read file contents from the actual file or from the source @@ -635,7 +736,8 @@ void BTFDebug::emitBTFExtSection() { // Do not emit section if empty FuncInfoTable and LineInfoTable. - if (!FuncInfoTable.size() && !LineInfoTable.size()) + if (!FuncInfoTable.size() && !LineInfoTable.size() && + !OffsetRelocTable.size() && !ExternRelocTable.size()) return; MCContext &Ctx = OS.getContext(); @@ -647,6 +749,8 @@ // Account for FuncInfo/LineInfo record size as well. uint32_t FuncLen = 4, LineLen = 4; + // Do not account for optional OffsetReloc/ExternReloc. + uint32_t OffsetRelocLen = 0, ExternRelocLen = 0; for (const auto &FuncSec : FuncInfoTable) { FuncLen += BTF::SecFuncInfoSize; FuncLen += FuncSec.second.size() * BTF::BPFFuncInfoSize; @@ -655,11 +759,28 @@ LineLen += BTF::SecLineInfoSize; LineLen += LineSec.second.size() * BTF::BPFLineInfoSize; } + for (const auto &OffsetRelocSec : OffsetRelocTable) { + OffsetRelocLen += BTF::SecOffsetRelocSize; + OffsetRelocLen += OffsetRelocSec.second.size() * BTF::BPFOffsetRelocSize; + } + for (const auto &ExternRelocSec : ExternRelocTable) { + ExternRelocLen += BTF::SecExternRelocSize; + ExternRelocLen += ExternRelocSec.second.size() * BTF::BPFExternRelocSize; + } + + if (OffsetRelocLen) + OffsetRelocLen += 4; + if (ExternRelocLen) + ExternRelocLen += 4; OS.EmitIntValue(0, 4); OS.EmitIntValue(FuncLen, 4); OS.EmitIntValue(FuncLen, 4); OS.EmitIntValue(LineLen, 4); + OS.EmitIntValue(FuncLen + LineLen, 4); + OS.EmitIntValue(OffsetRelocLen, 4); + OS.EmitIntValue(FuncLen + LineLen + OffsetRelocLen, 4); + OS.EmitIntValue(ExternRelocLen, 4); // Emit func_info table. OS.AddComment("FuncInfo"); @@ -692,6 +813,41 @@ OS.EmitIntValue(LineInfo.LineNum << 10 | LineInfo.ColumnNum, 4); } } + + // Emit offset reloc table. + if (OffsetRelocLen) { + OS.AddComment("OffsetReloc"); + OS.EmitIntValue(BTF::BPFOffsetRelocSize, 4); + for (const auto &OffsetRelocSec : OffsetRelocTable) { + OS.AddComment("Offset reloc section string offset=" + + std::to_string(OffsetRelocSec.first)); + OS.EmitIntValue(OffsetRelocSec.first, 4); + OS.EmitIntValue(OffsetRelocSec.second.size(), 4); + for (const auto &OffsetRelocInfo : OffsetRelocSec.second) { + Asm->EmitLabelReference(OffsetRelocInfo.Label, 4); + OS.EmitIntValue(OffsetRelocInfo.TypeID, 4); + OS.EmitIntValue(OffsetRelocInfo.OffsetNameOff, 4); + OS.AddComment("Dependency"); + OS.EmitIntValue(OffsetRelocInfo.Dependency, 4); + } + } + } + + // Emit extern reloc table. + if (ExternRelocLen) { + OS.AddComment("ExternReloc"); + OS.EmitIntValue(BTF::BPFExternRelocSize, 4); + for (const auto &ExternRelocSec : ExternRelocTable) { + OS.AddComment("Extern reloc section string offset=" + + std::to_string(ExternRelocSec.first)); + OS.EmitIntValue(ExternRelocSec.first, 4); + OS.EmitIntValue(ExternRelocSec.second.size(), 4); + for (const auto &ExternRelocInfo : ExternRelocSec.second) { + Asm->EmitLabelReference(ExternRelocInfo.Label, 4); + OS.EmitIntValue(ExternRelocInfo.ExternNameOff, 4); + } + } + } } void BTFDebug::beginFunctionImpl(const MachineFunction *MF) { @@ -728,6 +884,9 @@ llvm::make_unique(SP->getName(), ProtoTypeId); uint32_t FuncTypeId = addType(std::move(FuncTypeEntry)); + for (const auto &TypeEntry : TypeEntries) + TypeEntry->completeType(*this); + // Construct funcinfo and the first lineinfo for the function. MCSymbol *FuncLabel = Asm->getFunctionBegin(); BTFFuncInfo FuncInfo; @@ -745,11 +904,273 @@ } void BTFDebug::endFunctionImpl(const MachineFunction *MF) { + // Fixup dependencies for section relocation + if (OffsetRelocTable.find(SecNameOff) != OffsetRelocTable.end()) { + for (auto &OREntry : OffsetRelocTable[SecNameOff]) { + size_t Pos = OREntry.OrigTypeName.find_last_of('$'); + if (Pos == std::string::npos) { + OREntry.Dependency = 0; + } else { + uint32_t I = 1; + for (auto &OREntry2 : OffsetRelocTable[SecNameOff]) { + if (OREntry.OrigTypeName.substr(0, Pos) == OREntry2.OrigTypeName) + break; + I++; + } + OREntry.Dependency = I; + } + } + } + SkipInstruction = false; LineInfoGenerated = false; SecNameOff = 0; } +/// On-demand populate struct types as requested from abstract member +/// accessing. +bool BTFDebug::populateStructType(const DIType *Ty, std::string StructName, + std::set &PopulatedTypes) { + if (!Ty || PopulatedTypes.find(Ty) != PopulatedTypes.end()) + return false; + PopulatedTypes.insert(Ty); + + if (const auto *CTy = dyn_cast(Ty)) { + auto Tag = CTy->getTag(); + if ((Tag == dwarf::DW_TAG_structure_type || + Tag == dwarf::DW_TAG_union_type) && + !CTy->isForwardDecl()) { + if (CTy->getName() == StructName) { + // Visit the struct type. + visitTypeEntry(CTy); + return true; + } + + const DINodeArray Elements = CTy->getElements(); + for (const auto *Element : Elements) { + if (populateStructType(cast(Element), StructName, + PopulatedTypes)) + return true; + } + } else if (Tag == dwarf::DW_TAG_array_type) { + if (populateStructType(CTy->getBaseType().resolve(), StructName, + PopulatedTypes)) + return true; + } + } else if (const auto *DTy = dyn_cast(Ty)) { + if (populateStructType(DTy->getBaseType().resolve(), StructName, + PopulatedTypes)) + return true; + } + + return false; +} + +bool BTFDebug::populateStructType(const DIType *Ty, std::string StructName) { + std::set PopulatedTypes; + return populateStructType(Ty, StructName, PopulatedTypes); +} + +/// Populate debuginfo struct type for abstract member accesses. +void BTFDebug::populateStructType(const MachineInstr *MI, + std::string StructName) { + bool Populated = false; + auto *SP = MI->getMF()->getFunction().getSubprogram(); + + // The current subprogram local variables. + for (const DINode *DN : SP->getRetainedNodes()) { + if (const auto *DV = dyn_cast(DN)) { + if (!DV->getArg() && + populateStructType(DV->getType().resolve(), StructName)) { + Populated = true; + break; + } + } + } + + if (!Populated) { + // The compile unit retained types. + for (const auto *Ty : SP->getUnit()->getRetainedTypes()) { + if (const auto *RT = dyn_cast(Ty)) { + if (populateStructType(RT, StructName)) { + Populated = true; + break; + } + } + } + } + + if (Populated) { + for (const auto &TypeEntry : TypeEntries) + TypeEntry->completeType(*this); + } +} + +// 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, + std::string TypeName) { + BTFOffsetReloc OffsetReloc; + OffsetReloc.Label = ORSym; + OffsetReloc.OrigTypeName = TypeName; + + // To get precise type name is tricky, for anonymous union/struct, we + // may not have type names at all. + + // skip __BTF_ prefix + bool IsAnonType = true; + TypeName = TypeName.substr(6); + if (TypeName.find_last_of('$') == std::string::npos) { + OffsetReloc.TypeName = TypeName; + IsAnonType = false; + } else { + OffsetReloc.TypeName = std::string(); + } + + uint32_t Start = 0, End = 0; + uint32_t Offset = 0, InitNumTypes = 0; + BTFTypeStruct *PrevStructType = nullptr; + BTFTypeArray *PrevArrayType = nullptr; + bool StartOver = false; + for (auto C : TypeName) { + if (C == '$') { + Start++; + End = Start; + Offset = 0; + + // IsAnonType + OffsetReloc.TypeID = PrevStructType->getId(); + std::string ShortTypeName = TypeName.substr(Start); + ShortTypeName = ShortTypeName.substr(0, ShortTypeName.size() - 1); + OffsetReloc.OffsetNameOff = addString(ShortTypeName); + StartOver = true; + } else if (C != ':') { + End++; + } else { + std::string SubStr = TypeName.substr(Start, End - Start); + if (TypeName[Start] < '0' || TypeName[Start] > '9') { + std::string StructName = SubStr; + + // Find the base type + for (int I = 0; I < 2; I++) { + for (const auto &StructType : StructTypes) { + if (StructType->getName() == StructName) { + PrevStructType = StructType; + if (!IsAnonType) { + OffsetReloc.TypeID = StructType->getId(); + std::string ShortTypeName = + TypeName.substr(0, Start) + TypeName.substr(End + 1); + ShortTypeName = + ShortTypeName.substr(0, ShortTypeName.size() - 1); + OffsetReloc.OffsetNameOff = addString(ShortTypeName); + } + Offset += InitNumTypes * StructType->getStructSize(); + break; + } + } + if (PrevStructType) + break; + else if (I == 0) + populateStructType(MI, StructName); + } + assert(PrevStructType && "did not find struct type"); + } else { + int Loc = std::stoi(SubStr); + + if (StartOver) { + StartOver = false; + Offset += Loc * PrevStructType->getStructSize(); + } 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 { + InitNumTypes = Loc; + } + } + Start = End + 1; + End = Start; + } + } + AccessOffsets[TypeName] = Offset; + OffsetRelocTable[SecNameOff].push_back(OffsetReloc); +} + +void BTFDebug::processLDimm64(const MachineInstr *MI) { + // If the insn is an LD_imm64, the following two cases + // will generate an .BTF.ext record. + // + // If the insn is "r2 = LD_imm64 @__BTF_...", + // add this insn into the .BTF.ext OffsetReloc subsection. + // Relocation looks like: + // . SecName: + // . InstOffset + // . TypeID + // . OffSetNameOff + // . Dependency + // Later, the insn is replaced with "r2 = " + // where "" equals to the offset based on current + // type definitions. + // + // If the insn is "r2 = LD_imm64 @VAR" and VAR is + // a patchable external global, add this insn into the .BTF.ext + // ExternReloc subsection. + // Relocation looks like: + // . SecName: + // . InstOffset + // . ExternNameOff + // Later, the insn is replaced with "r2 = " or + // "LD_imm64 r2, " where "" = 0. + + // check whether this is a candidate or not + const MachineOperand &MO = MI->getOperand(1); + if (MO.isGlobal()) { + const GlobalValue *GVal = MO.getGlobal(); + auto *GVar = dyn_cast(GVal); + if (GVar && GVar->hasAttribute(AmaAttr)) { + MCSymbol *ORSym = OS.getContext().createTempSymbol(); + OS.EmitLabel(ORSym); + generateOffsetReloc(MI, ORSym, GVar->getName()); + } else if (GVar && !GVar->hasInitializer() && GVar->hasExternalLinkage() && + GVar->getSection() == PatchableExtSecName) { + MCSymbol *ORSym = OS.getContext().createTempSymbol(); + OS.EmitLabel(ORSym); + + BTFExternReloc ExternReloc; + ExternReloc.Label = ORSym; + ExternReloc.ExternNameOff = addString(GVar->getName()); + ExternRelocTable[SecNameOff].push_back(ExternReloc); + } + } +} + void BTFDebug::beginInstruction(const MachineInstr *MI) { DebugHandlerBase::beginInstruction(MI); @@ -770,6 +1191,9 @@ return; } + if (MI->getOpcode() == BPF::LD_imm64) + processLDimm64(MI); + // Skip this instruction if no DebugLoc or the DebugLoc // is the same as the previous instruction. const DebugLoc &DL = MI->getDebugLoc(); @@ -810,7 +1234,8 @@ Global.getDebugInfo(GVs); uint32_t GVTypeId = 0; for (auto *GVE : GVs) { - visitTypeEntry(GVE->getVariable()->getType().resolve(), GVTypeId); + visitTypeEntry(GVE->getVariable()->getType().resolve(), GVTypeId, false, + false); break; } @@ -863,10 +1288,70 @@ addType(std::move(DataSec.second)); } +/// Emit proper patchable instructions. +bool BTFDebug::InstLower(const MachineInstr *MI, MCInst &OutMI) { + if (MI->getOpcode() == BPF::LD_imm64) { + const MachineOperand &MO = MI->getOperand(1); + if (MO.isGlobal()) { + const GlobalValue *GVal = MO.getGlobal(); + auto *GVar = dyn_cast(GVal); + if (GVar && GVar->hasAttribute(AmaAttr)) { + std::string TypeName = GVar->getName().substr(6); + int64_t Imm = AccessOffsets[TypeName]; + + // Emit "mov ri, " for abstract member accesses. + OutMI.setOpcode(BPF::MOV_ri); + OutMI.addOperand(MCOperand::createReg(MI->getOperand(0).getReg())); + OutMI.addOperand(MCOperand::createImm(Imm)); + return true; + } else if (GVar && !GVar->hasInitializer() && + GVar->hasExternalLinkage() && + GVar->getSection() == PatchableExtSecName) { + const IntegerType *IntTy = dyn_cast(GVar->getValueType()); + assert(IntTy); + // For patchable externals, emit "LD_imm64, ri, 0" if the external + // variable is 64bit width, emit "mov ri, 0" otherwise. + if (IntTy->getBitWidth() == 64) + OutMI.setOpcode(BPF::LD_imm64); + else + OutMI.setOpcode(BPF::MOV_ri); + OutMI.addOperand(MCOperand::createReg(MI->getOperand(0).getReg())); + OutMI.addOperand(MCOperand::createImm(0)); + return true; + } + } + } + return false; +} + void BTFDebug::endModule() { // Collect all global types/variables. processGlobals(); + // Fixups + for (auto &Fixup : FixupDerivedTypes) { + std::string TypeName = Fixup.first; + bool IsUnion = Fixup.second.first; + + // Search through struct types + uint32_t StructTypeId = 0; + for (const auto &StructType : StructTypes) { + if (StructType->getName() == TypeName) { + StructTypeId = StructType->getId(); + break; + } + } + + if (StructTypeId == 0) { + auto FwdTypeEntry = llvm::make_unique(TypeName, IsUnion); + StructTypeId = addType(std::move(FwdTypeEntry)); + } + + for (auto &DType : Fixup.second.second) { + DType->setPointeeType(StructTypeId); + } + } + // Complete BTF type cross refereences. for (const auto &TypeEntry : TypeEntries) TypeEntry->completeType(*this); Index: lib/Target/BPF/CMakeLists.txt =================================================================== --- lib/Target/BPF/CMakeLists.txt +++ lib/Target/BPF/CMakeLists.txt @@ -13,6 +13,7 @@ add_public_tablegen_target(BPFCommonTableGen) add_llvm_target(BPFCodeGen + BPFAbstrctMemberAccess.cpp BPFAsmPrinter.cpp BPFFrameLowering.cpp BPFInstrInfo.cpp @@ -25,6 +26,7 @@ BPFTargetMachine.cpp BPFMIPeephole.cpp BPFMIChecking.cpp + BPFMISimplifyPatchable.cpp BTFDebug.cpp ) Index: test/CodeGen/BPF/BTF/binary-format.ll =================================================================== --- test/CodeGen/BPF/BTF/binary-format.ll +++ test/CodeGen/BPF/BTF/binary-format.ll @@ -15,31 +15,33 @@ ; CHECK: '.BTF' ; CHECK-EL: 0x00000000 9feb0100 18000000 00000000 30000000 -; CHECK-EL: 0x00000010 30000000 33000000 2b000000 00000001 +; CHECK-EL: 0x00000010 30000000 33000000 01000000 00000001 ; CHECK-EL: 0x00000020 04000000 20000001 00000000 0100000d -; CHECK-EL: 0x00000030 01000000 2f000000 01000000 31000000 -; CHECK-EL: 0x00000040 0000000c 02000000 002e7465 7874002f +; CHECK-EL: 0x00000030 01000000 05000000 01000000 07000000 +; CHECK-EL: 0x00000040 0000000c 02000000 00696e74 00610066 ; CHECK-EB: 0x00000000 eb9f0100 00000018 00000000 00000030 -; CHECK-EB: 0x00000010 00000030 00000033 0000002b 01000000 +; CHECK-EB: 0x00000010 00000030 00000033 00000001 01000000 ; CHECK-EB: 0x00000020 00000004 01000020 00000000 0d000001 -; CHECK-EB: 0x00000030 00000001 0000002f 00000001 00000031 -; CHECK-EB: 0x00000040 0c000000 00000002 002e7465 7874002f -; CHECK: 0x00000050 746d702f 742e6300 696e7420 6628696e -; CHECK: 0x00000060 74206129 207b2072 65747572 6e20613b -; CHECK: 0x00000070 207d0069 6e740061 006600 +; CHECK-EB: 0x00000030 00000001 00000005 00000001 00000007 +; CHECK-EB: 0x00000040 0c000000 00000002 00696e74 00610066 +; CHECK: 0x00000050 002e7465 7874002f 746d702f 742e6300 +; CHECK: 0x00000060 696e7420 6628696e 74206129 207b2072 +; CHECK: 0x00000070 65747572 6e20613b 207d00 ; CHECK: '.BTF.ext' -; CHECK-EL: 0x00000000 9feb0100 18000000 00000000 14000000 -; CHECK-EL: 0x00000010 14000000 2c000000 08000000 01000000 -; CHECK-EL: 0x00000020 01000000 00000000 03000000 10000000 -; CHECK-EL: 0x00000030 01000000 02000000 00000000 07000000 -; CHECK-EL: 0x00000040 10000000 00040000 08000000 07000000 -; CHECK-EL: 0x00000050 10000000 10040000 -; CHECK-EB: 0x00000000 eb9f0100 00000018 00000000 00000014 -; CHECK-EB: 0x00000010 00000014 0000002c 00000008 00000001 -; CHECK-EB: 0x00000020 00000001 00000000 00000003 00000010 -; CHECK-EB: 0x00000030 00000001 00000002 00000000 00000007 -; CHECK-EB: 0x00000040 00000010 00000400 00000008 00000007 -; CHECK-EB: 0x00000050 00000010 00000410 +; CHECK-EL: 0x00000000 9feb0100 28000000 00000000 14000000 +; CHECK-EL: 0x00000010 14000000 2c000000 40000000 00000000 +; CHECK-EL: 0x00000020 40000000 00000000 08000000 09000000 +; CHECK-EL: 0x00000030 01000000 00000000 03000000 10000000 +; CHECK-EL: 0x00000040 09000000 02000000 00000000 0f000000 +; CHECK-EL: 0x00000050 18000000 00040000 08000000 0f000000 +; CHECK-EL: 0x00000060 18000000 10040000 +; CHECK-EB: 0x00000000 eb9f0100 00000028 00000000 00000014 +; CHECK-EB: 0x00000010 00000014 0000002c 00000040 00000000 +; CHECK-EB: 0x00000020 00000040 00000000 00000008 00000009 +; CHECK-EB: 0x00000030 00000001 00000000 00000003 00000010 +; CHECK-EB: 0x00000040 00000009 00000002 00000000 0000000f +; CHECK-EB: 0x00000050 00000018 00000400 00000008 0000000f +; CHECK-EB: 0x00000060 00000018 00000410 ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 Index: test/CodeGen/BPF/BTF/extern-global-var.ll =================================================================== --- test/CodeGen/BPF/BTF/extern-global-var.ll +++ test/CodeGen/BPF/BTF/extern-global-var.ll @@ -28,21 +28,21 @@ ; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1) ; CHECK-NEXT: .long 218103808 # 0xd000000 ; CHECK-NEXT: .long 2 -; CHECK-NEXT: .long 44 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 2) ; CHECK-NEXT: .long 16777216 # 0x1000000 ; CHECK-NEXT: .long 4 ; CHECK-NEXT: .long 16777248 # 0x1000020 -; CHECK-NEXT: .long 48 # BTF_KIND_FUNC(id = 3) +; CHECK-NEXT: .long 5 # BTF_KIND_FUNC(id = 3) ; CHECK-NEXT: .long 201326592 # 0xc000000 ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .byte 0 # string offset=0 -; CHECK-NEXT: .ascii ".text" # string offset=1 +; CHECK-NEXT: .ascii "int" # string offset=1 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=7 +; CHECK-NEXT: .ascii "foo" # string offset=5 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "int" # string offset=44 +; CHECK-NEXT: .ascii ".text" # string offset=9 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "foo" # string offset=48 +; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=15 ; CHECK-NEXT: .byte 0 attributes #0 = { norecurse nounwind readonly "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "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" } Index: test/CodeGen/BPF/BTF/filename.ll =================================================================== --- test/CodeGen/BPF/BTF/filename.ll +++ test/CodeGen/BPF/BTF/filename.ll @@ -23,41 +23,45 @@ ; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1) ; CHECK-NEXT: .long 218103808 # 0xd000000 ; CHECK-NEXT: .long 2 -; CHECK-NEXT: .long 26 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 2) ; CHECK-NEXT: .long 16777216 # 0x1000000 ; CHECK-NEXT: .long 4 ; CHECK-NEXT: .long 16777248 # 0x1000020 -; CHECK-NEXT: .long 30 # BTF_KIND_FUNC(id = 3) +; CHECK-NEXT: .long 5 # BTF_KIND_FUNC(id = 3) ; CHECK-NEXT: .long 201326592 # 0xc000000 ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .byte 0 # string offset=0 -; CHECK-NEXT: .ascii ".text" # string offset=1 +; CHECK-NEXT: .ascii "int" # string offset=1 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "/home/yhs/ttmp/t.c" # string offset=7 +; CHECK-NEXT: .ascii "test" # string offset=5 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "int" # string offset=26 +; CHECK-NEXT: .ascii ".text" # string offset=10 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "test" # string offset=30 +; CHECK-NEXT: .ascii "/home/yhs/ttmp/t.c" # string offset=16 ; CHECK-NEXT: .byte 0 ; CHECK-NEXT: .section .BTF.ext,"",@progbits ; CHECK-NEXT: .short 60319 # 0xeb9f ; CHECK-NEXT: .byte 1 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 40 ; CHECK-NEXT: .long 0 ; CHECK-NEXT: .long 20 ; CHECK-NEXT: .long 20 ; CHECK-NEXT: .long 28 +; CHECK-NEXT: .long 48 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 48 +; CHECK-NEXT: .long 0 ; CHECK-NEXT: .long 8 # FuncInfo -; CHECK-NEXT: .long 1 # FuncInfo section string offset=1 +; CHECK-NEXT: .long 10 # FuncInfo section string offset=10 ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long .Lfunc_begin{{[0-9]+}} ; CHECK-NEXT: .long 3 ; CHECK-NEXT: .long 16 # LineInfo -; CHECK-NEXT: .long 1 # LineInfo section string offset=1 +; CHECK-NEXT: .long 10 # LineInfo section string offset=10 ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long .Ltmp{{[0-9]+}} -; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long 16 ; CHECK-NEXT: .long 0 ; CHECK-NEXT: .long 1038 # Line 1 Col 14 Index: test/CodeGen/BPF/BTF/func-func-ptr.ll =================================================================== --- test/CodeGen/BPF/BTF/func-func-ptr.ll +++ test/CodeGen/BPF/BTF/func-func-ptr.ll @@ -29,16 +29,16 @@ ; CHECK-NEXT: .long 104 ; CHECK-NEXT: .long 104 ; CHECK-NEXT: .long 32 -; CHECK-NEXT: .long 16 # BTF_KIND_INT(id = 1) +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 1) ; CHECK-NEXT: .long 16777216 # 0x1000000 ; CHECK-NEXT: .long 4 ; CHECK-NEXT: .long 16777248 # 0x1000020 ; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 2) ; CHECK-NEXT: .long 218103809 # 0xd000001 ; CHECK-NEXT: .long 0 -; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long 5 ; CHECK-NEXT: .long 1 -; CHECK-NEXT: .long 23 # BTF_KIND_FUNC(id = 3) +; CHECK-NEXT: .long 8 # BTF_KIND_FUNC(id = 3) ; CHECK-NEXT: .long 201326592 # 0xc000000 ; CHECK-NEXT: .long 2 ; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 4) @@ -54,17 +54,17 @@ ; CHECK-NEXT: .long 8 ; CHECK-NEXT: .long 29 ; CHECK-NEXT: .long 4 -; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 0 # 0x0 ; CHECK-NEXT: .byte 0 # string offset=0 -; CHECK-NEXT: .ascii ".text" # string offset=1 +; CHECK-NEXT: .ascii "int" # string offset=1 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "/tmp/t.c" # string offset=7 +; CHECK-NEXT: .ascii "p2" # string offset=5 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "int" # string offset=16 +; CHECK-NEXT: .ascii "f1" # string offset=8 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "p2" # string offset=20 +; CHECK-NEXT: .ascii ".text" # string offset=11 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "f1" # string offset=23 +; CHECK-NEXT: .ascii "/tmp/t.c" # string offset=17 ; CHECK-NEXT: .byte 0 ; CHECK-NEXT: .ascii "t1" # string offset=26 ; CHECK-NEXT: .byte 0 @@ -74,21 +74,25 @@ ; CHECK-NEXT: .short 60319 # 0xeb9f ; CHECK-NEXT: .byte 1 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 40 ; CHECK-NEXT: .long 0 ; CHECK-NEXT: .long 20 ; CHECK-NEXT: .long 20 ; CHECK-NEXT: .long 28 +; CHECK-NEXT: .long 48 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 48 +; CHECK-NEXT: .long 0 ; CHECK-NEXT: .long 8 # FuncInfo -; CHECK-NEXT: .long 1 # FuncInfo section string offset=1 +; CHECK-NEXT: .long 11 # FuncInfo section string offset=11 ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long .Lfunc_begin0 ; CHECK-NEXT: .long 3 ; CHECK-NEXT: .long 16 # LineInfo -; CHECK-NEXT: .long 1 # LineInfo section string offset=1 +; CHECK-NEXT: .long 11 # LineInfo section string offset=11 ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long .Ltmp{{[0-9]+}} -; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long 17 ; CHECK-NEXT: .long 0 ; CHECK-NEXT: .long 3091 # Line 3 Col 19 Index: test/CodeGen/BPF/BTF/func-non-void.ll =================================================================== --- test/CodeGen/BPF/BTF/func-non-void.ll +++ test/CodeGen/BPF/BTF/func-non-void.ll @@ -21,52 +21,56 @@ ; CHECK-NEXT: .long 48 ; CHECK-NEXT: .long 48 ; CHECK-NEXT: .long 26 -; CHECK-NEXT: .long 16 # BTF_KIND_INT(id = 1) +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 1) ; CHECK-NEXT: .long 16777216 # 0x1000000 ; CHECK-NEXT: .long 4 ; CHECK-NEXT: .long 16777248 # 0x1000020 ; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 2) ; CHECK-NEXT: .long 218103809 # 0xd000001 ; CHECK-NEXT: .long 1 -; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long 5 ; CHECK-NEXT: .long 1 -; CHECK-NEXT: .long 23 # BTF_KIND_FUNC(id = 3) +; CHECK-NEXT: .long 8 # BTF_KIND_FUNC(id = 3) ; CHECK-NEXT: .long 201326592 # 0xc000000 ; CHECK-NEXT: .long 2 ; CHECK-NEXT: .byte 0 # string offset=0 -; CHECK-NEXT: .ascii ".text" # string offset=1 +; CHECK-NEXT: .ascii "int" # string offset=1 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "/tmp/t.c" # string offset=7 +; CHECK-NEXT: .ascii "a1" # string offset=5 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "int" # string offset=16 +; CHECK-NEXT: .ascii "f1" # string offset=8 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "a1" # string offset=20 +; CHECK-NEXT: .ascii ".text" # string offset=11 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "f1" # string offset=23 +; CHECK-NEXT: .ascii "/tmp/t.c" # string offset=17 ; CHECK-NEXT: .byte 0 ; CHECK-NEXT: .section .BTF.ext,"",@progbits ; CHECK-NEXT: .short 60319 # 0xeb9f ; CHECK-NEXT: .byte 1 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 40 ; CHECK-NEXT: .long 0 ; CHECK-NEXT: .long 20 ; CHECK-NEXT: .long 20 ; CHECK-NEXT: .long 44 +; CHECK-NEXT: .long 64 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 64 +; CHECK-NEXT: .long 0 ; CHECK-NEXT: .long 8 # FuncInfo -; CHECK-NEXT: .long 1 # FuncInfo section string offset=1 +; CHECK-NEXT: .long 11 # FuncInfo section string offset=11 ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long .Lfunc_begin0 ; CHECK-NEXT: .long 3 ; CHECK-NEXT: .long 16 # LineInfo -; CHECK-NEXT: .long 1 # LineInfo section string offset=1 +; CHECK-NEXT: .long 11 # LineInfo section string offset=11 ; CHECK-NEXT: .long 2 ; CHECK-NEXT: .long .Lfunc_begin0 -; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long 17 ; CHECK-NEXT: .long 0 ; CHECK-NEXT: .long 1024 # Line 1 Col 0 ; CHECK-NEXT: .long .Ltmp{{[0-9]+}} -; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long 17 ; CHECK-NEXT: .long 0 ; CHECK-NEXT: .long 1042 # Line 1 Col 18 Index: test/CodeGen/BPF/BTF/func-source.ll =================================================================== --- test/CodeGen/BPF/BTF/func-source.ll +++ test/CodeGen/BPF/BTF/func-source.ll @@ -27,38 +27,42 @@ ; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1) ; CHECK-NEXT: .long 218103808 # 0xd000000 ; CHECK-NEXT: .long 0 -; CHECK-NEXT: .long 33 # BTF_KIND_FUNC(id = 2) +; CHECK-NEXT: .long 1 # BTF_KIND_FUNC(id = 2) ; CHECK-NEXT: .long 201326592 # 0xc000000 ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .byte 0 # string offset=0 -; CHECK-NEXT: .ascii ".text" # string offset=1 +; CHECK-NEXT: .byte 102 # string offset=1 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "/tmp/t.c" # string offset=7 +; CHECK-NEXT: .ascii ".text" # string offset=3 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "void f(void) { }" # string offset=16 +; CHECK-NEXT: .ascii "/tmp/t.c" # string offset=9 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .byte 102 # string offset=33 +; CHECK-NEXT: .ascii "void f(void) { }" # string offset=18 ; CHECK-NEXT: .byte 0 ; CHECK-NEXT: .section .BTF.ext,"",@progbits ; CHECK-NEXT: .short 60319 # 0xeb9f ; CHECK-NEXT: .byte 1 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 40 ; CHECK-NEXT: .long 0 ; CHECK-NEXT: .long 20 ; CHECK-NEXT: .long 20 ; CHECK-NEXT: .long 28 +; CHECK-NEXT: .long 48 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 48 +; CHECK-NEXT: .long 0 ; CHECK-NEXT: .long 8 # FuncInfo -; CHECK-NEXT: .long 1 # FuncInfo section string offset=1 +; CHECK-NEXT: .long 3 # FuncInfo section string offset=3 ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long .Lfunc_begin0 ; CHECK-NEXT: .long 2 ; CHECK-NEXT: .long 16 # LineInfo -; CHECK-NEXT: .long 1 # LineInfo section string offset=1 +; CHECK-NEXT: .long 3 # LineInfo section string offset=3 ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long .Ltmp{{[0-9]+}} -; CHECK-NEXT: .long 7 -; CHECK-NEXT: .long 16 +; CHECK-NEXT: .long 9 +; CHECK-NEXT: .long 18 ; CHECK-NEXT: .long 1040 # Line 1 Col 16 attributes #0 = { norecurse nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "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" } Index: test/CodeGen/BPF/BTF/func-typedef.ll =================================================================== --- test/CodeGen/BPF/BTF/func-typedef.ll +++ test/CodeGen/BPF/BTF/func-typedef.ll @@ -24,65 +24,70 @@ ; CHECK-NEXT: .long 72 ; CHECK-NEXT: .long 72 ; CHECK-NEXT: .long 35 -; CHECK-NEXT: .long 16 # BTF_KIND_TYPEDEF(id = 1) +; CHECK-NEXT: .long 1 # BTF_KIND_TYPEDEF(id = 1) ; CHECK-NEXT: .long 134217728 # 0x8000000 ; CHECK-NEXT: .long 2 -; CHECK-NEXT: .long 22 # BTF_KIND_TYPEDEF(id = 2) +; CHECK-NEXT: .long 7 # BTF_KIND_TYPEDEF(id = 2) ; CHECK-NEXT: .long 134217728 # 0x8000000 ; CHECK-NEXT: .long 3 -; CHECK-NEXT: .long 27 # BTF_KIND_INT(id = 3) +; CHECK-NEXT: .long 12 # BTF_KIND_INT(id = 3) ; CHECK-NEXT: .long 16777216 # 0x1000000 ; CHECK-NEXT: .long 4 ; CHECK-NEXT: .long 16777248 # 0x1000020 ; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 4) ; CHECK-NEXT: .long 218103809 # 0xd000001 ; CHECK-NEXT: .long 1 -; CHECK-NEXT: .long 31 +; CHECK-NEXT: .long 16 ; CHECK-NEXT: .long 1 -; CHECK-NEXT: .long 33 # BTF_KIND_FUNC(id = 5) +; CHECK-NEXT: .long 18 # BTF_KIND_FUNC(id = 5) ; CHECK-NEXT: .long 201326592 # 0xc000000 ; CHECK-NEXT: .long 4 ; CHECK-NEXT: .byte 0 # string offset=0 -; CHECK-NEXT: .ascii ".text" # string offset=1 +; CHECK-NEXT: .ascii "__int" # string offset=1 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "/tmp/t.c" # string offset=7 +; CHECK-NEXT: .ascii "_int" # string offset=7 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "__int" # string offset=16 +; CHECK-NEXT: .ascii "int" # string offset=12 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "_int" # string offset=22 +; CHECK-NEXT: .byte 97 # string offset=16 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "int" # string offset=27 +; CHECK-NEXT: .byte 102 # string offset=18 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .byte 97 # string offset=31 +; CHECK-NEXT: .ascii ".text" # string offset=20 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .byte 102 # string offset=33 +; CHECK-NEXT: .ascii "/tmp/t.c" # string offset=26 ; CHECK-NEXT: .byte 0 ; CHECK-NEXT: .section .BTF.ext,"",@progbits ; CHECK-NEXT: .short 60319 # 0xeb9f ; CHECK-NEXT: .byte 1 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 40 ; CHECK-NEXT: .long 0 ; CHECK-NEXT: .long 20 ; CHECK-NEXT: .long 20 ; CHECK-NEXT: .long 44 +; CHECK-NEXT: .long 64 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 64 +; CHECK-NEXT: .long 0 ; CHECK-NEXT: .long 8 # FuncInfo -; CHECK-NEXT: .long 1 # FuncInfo section string offset=1 +; CHECK-NEXT: .long 20 # FuncInfo section string offset=20 ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long .Lfunc_begin0 ; CHECK-NEXT: .long 5 ; CHECK-NEXT: .long 16 # LineInfo -; CHECK-NEXT: .long 1 # LineInfo section string offset=1 +; CHECK-NEXT: .long 20 # LineInfo section string offset=20 ; CHECK-NEXT: .long 2 ; CHECK-NEXT: .long .Lfunc_begin0 -; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long 26 ; CHECK-NEXT: .long 0 ; CHECK-NEXT: .long 3072 # Line 3 Col 0 ; CHECK-NEXT: .long .Ltmp{{[0-9]+}} -; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long 26 ; CHECK-NEXT: .long 0 ; CHECK-NEXT: .long 3092 # Line 3 Col 20 + ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 Index: test/CodeGen/BPF/BTF/func-unused-arg.ll =================================================================== --- test/CodeGen/BPF/BTF/func-unused-arg.ll +++ test/CodeGen/BPF/BTF/func-unused-arg.ll @@ -21,48 +21,52 @@ ; CHECK-NEXT: .long 48 ; CHECK-NEXT: .long 48 ; CHECK-NEXT: .long 26 -; CHECK-NEXT: .long 16 # BTF_KIND_INT(id = 1) +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 1) ; CHECK-NEXT: .long 16777216 # 0x1000000 ; CHECK-NEXT: .long 4 ; CHECK-NEXT: .long 16777248 # 0x1000020 ; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 2) ; CHECK-NEXT: .long 218103809 # 0xd000001 ; CHECK-NEXT: .long 1 -; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long 5 ; CHECK-NEXT: .long 1 -; CHECK-NEXT: .long 23 # BTF_KIND_FUNC(id = 3) +; CHECK-NEXT: .long 8 # BTF_KIND_FUNC(id = 3) ; CHECK-NEXT: .long 201326592 # 0xc000000 ; CHECK-NEXT: .long 2 ; CHECK-NEXT: .byte 0 # string offset=0 -; CHECK-NEXT: .ascii ".text" # string offset=1 +; CHECK-NEXT: .ascii "int" # string offset=1 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "/tmp/t.c" # string offset=7 +; CHECK-NEXT: .ascii "a1" # string offset=5 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "int" # string offset=16 +; CHECK-NEXT: .ascii "f1" # string offset=8 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "a1" # string offset=20 +; CHECK-NEXT: .ascii ".text" # string offset=11 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "f1" # string offset=23 +; CHECK-NEXT: .ascii "/tmp/t.c" # string offset=17 ; CHECK-NEXT: .byte 0 ; CHECK-NEXT: .section .BTF.ext,"",@progbits ; CHECK-NEXT: .short 60319 # 0xeb9f ; CHECK-NEXT: .byte 1 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 40 ; CHECK-NEXT: .long 0 ; CHECK-NEXT: .long 20 ; CHECK-NEXT: .long 20 ; CHECK-NEXT: .long 28 +; CHECK-NEXT: .long 48 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 48 +; CHECK-NEXT: .long 0 ; CHECK-NEXT: .long 8 # FuncInfo -; CHECK-NEXT: .long 1 # FuncInfo section string offset=1 +; CHECK-NEXT: .long 11 # FuncInfo section string offset=11 ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long .Lfunc_begin0 ; CHECK-NEXT: .long 3 ; CHECK-NEXT: .long 16 # LineInfo -; CHECK-NEXT: .long 1 # LineInfo section string offset=1 +; CHECK-NEXT: .long 11 # LineInfo section string offset=11 ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long .Ltmp{{[0-9]+}} -; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long 17 ; CHECK-NEXT: .long 0 ; CHECK-NEXT: .long 1042 # Line 1 Col 18 Index: test/CodeGen/BPF/BTF/func-void.ll =================================================================== --- test/CodeGen/BPF/BTF/func-void.ll +++ test/CodeGen/BPF/BTF/func-void.ll @@ -23,35 +23,39 @@ ; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1) ; CHECK-NEXT: .long 218103808 # 0xd000000 ; CHECK-NEXT: .long 0 -; CHECK-NEXT: .long 16 # BTF_KIND_FUNC(id = 2) +; CHECK-NEXT: .long 1 # BTF_KIND_FUNC(id = 2) ; CHECK-NEXT: .long 201326592 # 0xc000000 ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .byte 0 # string offset=0 -; CHECK-NEXT: .ascii ".text" # string offset=1 +; CHECK-NEXT: .ascii "f1" # string offset=1 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "/tmp/t.c" # string offset=7 +; CHECK-NEXT: .ascii ".text" # string offset=4 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "f1" # string offset=16 +; CHECK-NEXT: .ascii "/tmp/t.c" # string offset=10 ; CHECK-NEXT: .byte 0 ; CHECK-NEXT: .section .BTF.ext,"",@progbits ; CHECK-NEXT: .short 60319 # 0xeb9f ; CHECK-NEXT: .byte 1 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 40 ; CHECK-NEXT: .long 0 ; CHECK-NEXT: .long 20 ; CHECK-NEXT: .long 20 ; CHECK-NEXT: .long 28 +; CHECK-NEXT: .long 48 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 48 +; CHECK-NEXT: .long 0 ; CHECK-NEXT: .long 8 # FuncInfo -; CHECK-NEXT: .long 1 # FuncInfo section string offset=1 +; CHECK-NEXT: .long 4 # FuncInfo section string offset=4 ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long .Lfunc_begin0 ; CHECK-NEXT: .long 2 ; CHECK-NEXT: .long 16 # LineInfo -; CHECK-NEXT: .long 1 # LineInfo section string offset=1 +; CHECK-NEXT: .long 4 # LineInfo section string offset=4 ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long .Ltmp{{[0-9]+}} -; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long 10 ; CHECK-NEXT: .long 0 ; CHECK-NEXT: .long 1040 # Line 1 Col 16 Index: test/CodeGen/BPF/BTF/local-var.ll =================================================================== --- test/CodeGen/BPF/BTF/local-var.ll +++ test/CodeGen/BPF/BTF/local-var.ll @@ -29,34 +29,34 @@ ; CHECK-NEXT: .long 64 ; CHECK-NEXT: .long 64 ; CHECK-NEXT: .long 59 -; CHECK-NEXT: .long 44 # BTF_KIND_INT(id = 1) +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 1) ; CHECK-NEXT: .long 16777216 # 0x1000000 ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long 16777224 # 0x1000008 ; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 2) ; CHECK-NEXT: .long 218103809 # 0xd000001 ; CHECK-NEXT: .long 3 -; CHECK-NEXT: .long 49 +; CHECK-NEXT: .long 6 ; CHECK-NEXT: .long 1 -; CHECK-NEXT: .long 51 # BTF_KIND_INT(id = 3) +; CHECK-NEXT: .long 8 # BTF_KIND_INT(id = 3) ; CHECK-NEXT: .long 16777216 # 0x1000000 ; CHECK-NEXT: .long 4 ; CHECK-NEXT: .long 16777248 # 0x1000020 -; CHECK-NEXT: .long 55 # BTF_KIND_FUNC(id = 4) +; CHECK-NEXT: .long 12 # BTF_KIND_FUNC(id = 4) ; CHECK-NEXT: .long 201326592 # 0xc000000 ; CHECK-NEXT: .long 2 ; CHECK-NEXT: .byte 0 # string offset=0 -; CHECK-NEXT: .ascii ".text" # string offset=1 +; CHECK-NEXT: .ascii "char" # string offset=1 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=7 +; CHECK-NEXT: .byte 97 # string offset=6 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "char" # string offset=44 +; CHECK-NEXT: .ascii "int" # string offset=8 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .byte 97 # string offset=49 +; CHECK-NEXT: .ascii "foo" # string offset=12 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "int" # string offset=51 +; CHECK-NEXT: .ascii ".text" # string offset=16 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "foo" # string offset=55 +; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=22 ; CHECK-NEXT: .byte 0 ; Function Attrs: nounwind readnone speculatable Index: test/CodeGen/BPF/BTF/static-var-derived-type.ll =================================================================== --- test/CodeGen/BPF/BTF/static-var-derived-type.ll +++ test/CodeGen/BPF/BTF/static-var-derived-type.ll @@ -46,11 +46,11 @@ ; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1) ; CHECK-NEXT: .long 218103808 # 0xd000000 ; CHECK-NEXT: .long 2 -; CHECK-NEXT: .long 45 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 2) ; CHECK-NEXT: .long 16777216 # 0x1000000 ; CHECK-NEXT: .long 8 ; CHECK-NEXT: .long 16777280 # 0x1000040 -; CHECK-NEXT: .long 54 # BTF_KIND_FUNC(id = 3) +; CHECK-NEXT: .long 10 # BTF_KIND_FUNC(id = 3) ; CHECK-NEXT: .long 201326592 # 0xc000000 ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long 0 # BTF_KIND_VOLATILE(id = 4) @@ -116,13 +116,13 @@ ; CHECK-NEXT: .long v4 ; CHECK-NEXT: .long 8 ; CHECK-NEXT: .byte 0 # string offset=0 -; CHECK-NEXT: .ascii ".text" # string offset=1 +; CHECK-NEXT: .ascii "long int" # string offset=1 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bugs/test.c" # string offset=7 +; CHECK-NEXT: .ascii "foo" # string offset=10 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "long int" # string offset=45 +; CHECK-NEXT: .ascii ".text" # string offset=14 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "foo" # string offset=54 +; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bugs/test.c" # string offset=20 ; CHECK-NEXT: .byte 0 ; CHECK-NEXT: .ascii "int" # string offset=58 ; CHECK-NEXT: .byte 0 Index: test/CodeGen/BPF/BTF/static-var-inited-sec.ll =================================================================== --- test/CodeGen/BPF/BTF/static-var-inited-sec.ll +++ test/CodeGen/BPF/BTF/static-var-inited-sec.ll @@ -35,11 +35,11 @@ ; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1) ; CHECK-NEXT: .long 218103808 # 0xd000000 ; CHECK-NEXT: .long 2 -; CHECK-NEXT: .long 44 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 2) ; CHECK-NEXT: .long 16777216 # 0x1000000 ; CHECK-NEXT: .long 4 ; CHECK-NEXT: .long 16777248 # 0x1000020 -; CHECK-NEXT: .long 48 # BTF_KIND_FUNC(id = 3) +; CHECK-NEXT: .long 5 # BTF_KIND_FUNC(id = 3) ; CHECK-NEXT: .long 201326592 # 0xc000000 ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long 0 # BTF_KIND_VOLATILE(id = 4) @@ -74,13 +74,13 @@ ; CHECK-NEXT: .long a ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .byte 0 # string offset=0 -; CHECK-NEXT: .ascii ".text" # string offset=1 +; CHECK-NEXT: .ascii "int" # string offset=1 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=7 +; CHECK-NEXT: .ascii "foo" # string offset=5 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "int" # string offset=44 +; CHECK-NEXT: .ascii ".text" # string offset=9 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "foo" # string offset=48 +; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=15 ; CHECK-NEXT: .byte 0 ; CHECK-NEXT: .ascii "short" # string offset=52 ; CHECK-NEXT: .byte 0 Index: test/CodeGen/BPF/BTF/static-var-inited.ll =================================================================== --- test/CodeGen/BPF/BTF/static-var-inited.ll +++ test/CodeGen/BPF/BTF/static-var-inited.ll @@ -35,11 +35,11 @@ ; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1) ; CHECK-NEXT: .long 218103808 # 0xd000000 ; CHECK-NEXT: .long 2 -; CHECK-NEXT: .long 44 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 2) ; CHECK-NEXT: .long 16777216 # 0x1000000 ; CHECK-NEXT: .long 4 ; CHECK-NEXT: .long 16777248 # 0x1000020 -; CHECK-NEXT: .long 48 # BTF_KIND_FUNC(id = 3) +; CHECK-NEXT: .long 5 # BTF_KIND_FUNC(id = 3) ; CHECK-NEXT: .long 201326592 # 0xc000000 ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long 0 # BTF_KIND_VOLATILE(id = 4) @@ -74,13 +74,13 @@ ; CHECK-NEXT: .long a ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .byte 0 # string offset=0 -; CHECK-NEXT: .ascii ".text" # string offset=1 +; CHECK-NEXT: .ascii "int" # string offset=1 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=7 +; CHECK-NEXT: .ascii "foo" # string offset=5 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "int" # string offset=44 +; CHECK-NEXT: .ascii ".text" # string offset=9 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "foo" # string offset=48 +; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=15 ; CHECK-NEXT: .byte 0 ; CHECK-NEXT: .ascii "short" # string offset=52 ; CHECK-NEXT: .byte 0 Index: test/CodeGen/BPF/BTF/static-var-readonly-sec.ll =================================================================== --- test/CodeGen/BPF/BTF/static-var-readonly-sec.ll +++ test/CodeGen/BPF/BTF/static-var-readonly-sec.ll @@ -35,11 +35,11 @@ ; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1) ; CHECK-NEXT: .long 218103808 # 0xd000000 ; CHECK-NEXT: .long 2 -; CHECK-NEXT: .long 44 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 2) ; CHECK-NEXT: .long 16777216 # 0x1000000 ; CHECK-NEXT: .long 4 ; CHECK-NEXT: .long 16777248 # 0x1000020 -; CHECK-NEXT: .long 48 # BTF_KIND_FUNC(id = 3) +; CHECK-NEXT: .long 5 # BTF_KIND_FUNC(id = 3) ; CHECK-NEXT: .long 201326592 # 0xc000000 ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long 0 # BTF_KIND_CONST(id = 4) @@ -80,13 +80,13 @@ ; CHECK-NEXT: .long a ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .byte 0 # string offset=0 -; CHECK-NEXT: .ascii ".text" # string offset=1 +; CHECK-NEXT: .ascii "int" # string offset=1 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=7 +; CHECK-NEXT: .ascii "foo" # string offset=5 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "int" # string offset=44 +; CHECK-NEXT: .ascii ".text" # string offset=9 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "foo" # string offset=48 +; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=15 ; CHECK-NEXT: .byte 0 ; CHECK-NEXT: .ascii "short" # string offset=52 ; CHECK-NEXT: .byte 0 Index: test/CodeGen/BPF/BTF/static-var-readonly.ll =================================================================== --- test/CodeGen/BPF/BTF/static-var-readonly.ll +++ test/CodeGen/BPF/BTF/static-var-readonly.ll @@ -35,11 +35,11 @@ ; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1) ; CHECK-NEXT: .long 218103808 # 0xd000000 ; CHECK-NEXT: .long 2 -; CHECK-NEXT: .long 44 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 2) ; CHECK-NEXT: .long 16777216 # 0x1000000 ; CHECK-NEXT: .long 4 ; CHECK-NEXT: .long 16777248 # 0x1000020 -; CHECK-NEXT: .long 48 # BTF_KIND_FUNC(id = 3) +; CHECK-NEXT: .long 5 # BTF_KIND_FUNC(id = 3) ; CHECK-NEXT: .long 201326592 # 0xc000000 ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long 0 # BTF_KIND_CONST(id = 4) @@ -80,13 +80,13 @@ ; CHECK-NEXT: .long a ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .byte 0 # string offset=0 -; CHECK-NEXT: .ascii ".text" # string offset=1 +; CHECK-NEXT: .ascii "int" # string offset=1 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=7 +; CHECK-NEXT: .ascii "foo" # string offset=5 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "int" # string offset=44 +; CHECK-NEXT: .ascii ".text" # string offset=9 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "foo" # string offset=48 +; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=15 ; CHECK-NEXT: .byte 0 ; CHECK-NEXT: .ascii "short" # string offset=52 ; CHECK-NEXT: .byte 0 Index: test/CodeGen/BPF/BTF/static-var-sec.ll =================================================================== --- test/CodeGen/BPF/BTF/static-var-sec.ll +++ test/CodeGen/BPF/BTF/static-var-sec.ll @@ -35,11 +35,11 @@ ; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1) ; CHECK-NEXT: .long 218103808 # 0xd000000 ; CHECK-NEXT: .long 2 -; CHECK-NEXT: .long 44 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 2) ; CHECK-NEXT: .long 16777216 # 0x1000000 ; CHECK-NEXT: .long 4 ; CHECK-NEXT: .long 16777248 # 0x1000020 -; CHECK-NEXT: .long 48 # BTF_KIND_FUNC(id = 3) +; CHECK-NEXT: .long 5 # BTF_KIND_FUNC(id = 3) ; CHECK-NEXT: .long 201326592 # 0xc000000 ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long 0 # BTF_KIND_VOLATILE(id = 4) @@ -74,13 +74,13 @@ ; CHECK-NEXT: .long a ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .byte 0 # string offset=0 -; CHECK-NEXT: .ascii ".text" # string offset=1 +; CHECK-NEXT: .ascii "int" # string offset=1 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=7 +; CHECK-NEXT: .ascii "foo" # string offset=5 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "int" # string offset=44 +; CHECK-NEXT: .ascii ".text" # string offset=9 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "foo" # string offset=48 +; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=15 ; CHECK-NEXT: .byte 0 ; CHECK-NEXT: .ascii "short" # string offset=52 ; CHECK-NEXT: .byte 0 Index: test/CodeGen/BPF/BTF/static-var-zerolen-array.ll =================================================================== --- test/CodeGen/BPF/BTF/static-var-zerolen-array.ll +++ test/CodeGen/BPF/BTF/static-var-zerolen-array.ll @@ -32,11 +32,11 @@ ; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1) ; CHECK-NEXT: .long 218103808 # 0xd000000 ; CHECK-NEXT: .long 2 -; CHECK-NEXT: .long 44 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 2) ; CHECK-NEXT: .long 16777216 # 0x1000000 ; CHECK-NEXT: .long 4 ; CHECK-NEXT: .long 16777248 # 0x1000020 -; CHECK-NEXT: .long 48 # BTF_KIND_FUNC(id = 3) +; CHECK-NEXT: .long 5 # BTF_KIND_FUNC(id = 3) ; CHECK-NEXT: .long 201326592 # 0xc000000 ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long 0 # BTF_KIND_VOLATILE(id = 4) @@ -79,13 +79,13 @@ ; CHECK-NEXT: .long sv ; CHECK-NEXT: .long 20 ; CHECK-NEXT: .byte 0 # string offset=0 -; CHECK-NEXT: .ascii ".text" # string offset=1 +; CHECK-NEXT: .ascii "int" # string offset=1 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=7 +; CHECK-NEXT: .ascii "test" # string offset=5 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "int" # string offset=44 +; CHECK-NEXT: .ascii ".text" # string offset=10 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "test" # string offset=48 +; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=16 ; CHECK-NEXT: .byte 0 ; CHECK-NEXT: .byte 116 # string offset=53 ; CHECK-NEXT: .byte 0 Index: test/CodeGen/BPF/BTF/static-var.ll =================================================================== --- test/CodeGen/BPF/BTF/static-var.ll +++ test/CodeGen/BPF/BTF/static-var.ll @@ -35,11 +35,11 @@ ; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1) ; CHECK-NEXT: .long 218103808 # 0xd000000 ; CHECK-NEXT: .long 2 -; CHECK-NEXT: .long 44 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 2) ; CHECK-NEXT: .long 16777216 # 0x1000000 ; CHECK-NEXT: .long 4 ; CHECK-NEXT: .long 16777248 # 0x1000020 -; CHECK-NEXT: .long 48 # BTF_KIND_FUNC(id = 3) +; CHECK-NEXT: .long 5 # BTF_KIND_FUNC(id = 3) ; CHECK-NEXT: .long 201326592 # 0xc000000 ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long 0 # BTF_KIND_VOLATILE(id = 4) @@ -74,13 +74,13 @@ ; CHECK-NEXT: .long a ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .byte 0 # string offset=0 -; CHECK-NEXT: .ascii ".text" # string offset=1 +; CHECK-NEXT: .ascii "int" # string offset=1 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=7 +; CHECK-NEXT: .ascii "foo" # string offset=5 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "int" # string offset=44 +; CHECK-NEXT: .ascii ".text" # string offset=9 ; CHECK-NEXT: .byte 0 -; CHECK-NEXT: .ascii "foo" # string offset=48 +; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=15 ; CHECK-NEXT: .byte 0 ; CHECK-NEXT: .ascii "short" # string offset=52 ; CHECK-NEXT: .byte 0 Index: test/CodeGen/BPF/CORE/offset-reloc-basic.ll =================================================================== --- /dev/null +++ test/CodeGen/BPF/CORE/offset-reloc-basic.ll @@ -0,0 +1,187 @@ +; RUN: llc -march=bpfel -filetype=asm -mattr=offsetreloc -o - %s | FileCheck -check-prefixes=CHECK %s +; RUN: llc -march=bpfeb -filetype=asm -mattr=offsetreloc -o - %s | FileCheck -check-prefixes=CHECK %s +; Source code: +; struct sk_buff { +; int i; +; struct net_device *dev; +; }; +; +; static int (*bpf_probe_read)(void *dst, int size, void *unsafe_ptr) +; = (void *) 4; +; +; int bpf_prog(struct sk_buff *ctx) { +; struct net_device *dev = 0; +; bpf_probe_read(&dev, sizeof(dev), &ctx->dev); +; return dev != 0; +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm test.c + +%struct.sk_buff = type { i32, %struct.net_device* } +%struct.net_device = type opaque + +; Function Attrs: nounwind +define dso_local i32 @bpf_prog(%struct.sk_buff*) local_unnamed_addr #0 !dbg !15 { + %2 = alloca %struct.net_device*, align 8 + call void @llvm.dbg.value(metadata %struct.sk_buff* %0, metadata !26, metadata !DIExpression()), !dbg !28 + %3 = bitcast %struct.net_device** %2 to i8*, !dbg !29 + call void @llvm.lifetime.start.p0i8(i64 8, i8* nonnull %3) #3, !dbg !29 + call void @llvm.dbg.value(metadata %struct.net_device* null, metadata !27, metadata !DIExpression()), !dbg !30 + store %struct.net_device* null, %struct.net_device** %2, align 8, !dbg !30, !tbaa !31 + %4 = getelementptr inbounds %struct.sk_buff, %struct.sk_buff* %0, i64 0, i32 1, !dbg !35 +; CHECK: r1 = 8 +; CHECK-NEXT: r3 += r1 + %5 = bitcast %struct.net_device** %4 to i8*, !dbg !36 + %6 = call i32 inttoptr (i64 4 to i32 (i8*, i32, i8*)*)(i8* nonnull %3, i32 8, i8* nonnull %5) #3, !dbg !37 +; CHECK: call 4 + %7 = load %struct.net_device*, %struct.net_device** %2, align 8, !dbg !38, !tbaa !31 + call void @llvm.dbg.value(metadata %struct.net_device* %7, metadata !27, metadata !DIExpression()), !dbg !30 + %8 = icmp ne %struct.net_device* %7, null, !dbg !39 + %9 = zext i1 %8 to i32, !dbg !39 + call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %3) #3, !dbg !40 + ret i32 %9, !dbg !41 +} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 120 +; CHECK-NEXT: .long 120 +; CHECK-NEXT: .long 90 +; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 1) +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 1 # BTF_KIND_STRUCT(id = 2) +; CHECK-NEXT: .long 67108866 # 0x4000002 +; CHECK-NEXT: .long 16 +; CHECK-NEXT: .long 9 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 11 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 64 # 0x40 +; CHECK-NEXT: .long 15 # BTF_KIND_INT(id = 3) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 4) +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 19 # BTF_KIND_FWD(id = 5) +; CHECK-NEXT: .long 117440512 # 0x7000000 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 6) +; CHECK-NEXT: .long 218103809 # 0xd000001 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 30 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 34 # BTF_KIND_FUNC(id = 7) +; CHECK-NEXT: .long 201326592 # 0xc000000 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "sk_buff" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 105 # string offset=9 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "dev" # string offset=11 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "int" # string offset=15 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "net_device" # string offset=19 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "ctx" # string offset=30 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "bpf_prog" # string offset=34 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".text" # string offset=43 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "/tmp/home/yhs/work/tests/llvm/test.c" # string offset=49 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "0:1" # string offset=86 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .section .BTF.ext,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 40 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long 124 +; CHECK-NEXT: .long 144 +; CHECK-NEXT: .long 28 +; CHECK-NEXT: .long 172 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 8 # FuncInfo + +; CHECK: .long 16 # OffsetReloc +; CHECK-NEXT: .long 43 # Offset reloc section string offset=43 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 86 +; CHECK-NEXT: .long 0 + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #1 + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #1 + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #2 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "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 = { argmemonly nounwind } +attributes #2 = { nounwind readnone speculatable } +attributes #3 = { 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 8.0.20181009 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm") +!2 = !{} +!3 = !{!4} +!4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression()) +!5 = distinct !DIGlobalVariable(name: "bpf_probe_read", scope: !0, file: !1, line: 6, type: !6, isLocal: true, isDefinition: true) +!6 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64) +!7 = !DISubroutineType(types: !8) +!8 = !{!9, !10, !9, !10} +!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!10 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) +!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 8.0.20181009 "} +!15 = distinct !DISubprogram(name: "bpf_prog", scope: !1, file: !1, line: 9, type: !16, isLocal: false, isDefinition: true, scopeLine: 9, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !25) +!16 = !DISubroutineType(types: !17) +!17 = !{!9, !18} +!18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !19, size: 64) +!19 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "sk_buff", file: !1, line: 1, size: 128, elements: !20) +!20 = !{!21, !22} +!21 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !19, file: !1, line: 2, baseType: !9, size: 32) +!22 = !DIDerivedType(tag: DW_TAG_member, name: "dev", scope: !19, file: !1, line: 3, baseType: !23, size: 64, offset: 64) +!23 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !24, size: 64) +!24 = !DICompositeType(tag: DW_TAG_structure_type, name: "net_device", file: !1, line: 3, flags: DIFlagFwdDecl) +!25 = !{!26, !27} +!26 = !DILocalVariable(name: "ctx", arg: 1, scope: !15, file: !1, line: 9, type: !18) +!27 = !DILocalVariable(name: "dev", scope: !15, file: !1, line: 10, type: !23) +!28 = !DILocation(line: 9, column: 30, scope: !15) +!29 = !DILocation(line: 10, column: 3, scope: !15) +!30 = !DILocation(line: 10, column: 22, scope: !15) +!31 = !{!32, !32, i64 0} +!32 = !{!"any pointer", !33, i64 0} +!33 = !{!"omnipotent char", !34, i64 0} +!34 = !{!"Simple C/C++ TBAA"} +!35 = !DILocation(line: 11, column: 43, scope: !15) +!36 = !DILocation(line: 11, column: 37, scope: !15) +!37 = !DILocation(line: 11, column: 3, scope: !15) +!38 = !DILocation(line: 12, column: 10, scope: !15) +!39 = !DILocation(line: 12, column: 14, scope: !15) +!40 = !DILocation(line: 13, column: 1, scope: !15) +!41 = !DILocation(line: 12, column: 3, scope: !15) Index: test/CodeGen/BPF/CORE/offset-reloc-multilevel.ll =================================================================== --- /dev/null +++ test/CodeGen/BPF/CORE/offset-reloc-multilevel.ll @@ -0,0 +1,195 @@ +; RUN: llc -march=bpfel -filetype=asm -mattr=offsetreloc -o - %s | FileCheck -check-prefixes=CHECK %s +; RUN: llc -march=bpfeb -filetype=asm -mattr=offsetreloc -o - %s | FileCheck -check-prefixes=CHECK %s +; Source code: +; struct net_device { +; int dev_id; +; int others; +; }; +; struct sk_buff { +; int i; +; struct net_device dev; +; }; +; +; static int (*bpf_probe_read)(void *dst, int size, void *unsafe_ptr) +; = (void *) 4; +; +; int bpf_prog(struct sk_buff *ctx) { +; int dev_id; +; bpf_probe_read(&dev_id, sizeof(int), &ctx->dev.dev_id); +; return dev_id; +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm test.c + +%struct.sk_buff = type { i32, %struct.net_device } +%struct.net_device = type { i32, i32 } + +; Function Attrs: nounwind +define dso_local i32 @bpf_prog(%struct.sk_buff*) local_unnamed_addr #0 !dbg !15 { + %2 = alloca i32, align 4 + call void @llvm.dbg.value(metadata %struct.sk_buff* %0, metadata !28, metadata !DIExpression()), !dbg !30 + %3 = bitcast i32* %2 to i8*, !dbg !31 + call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %3) #3, !dbg !31 + %4 = getelementptr inbounds %struct.sk_buff, %struct.sk_buff* %0, i64 0, i32 1, i32 0, !dbg !32 +; CHECK: r1 = 4 +; CHECK-NEXT: r3 += r1 + %5 = bitcast i32* %4 to i8*, !dbg !33 + %6 = call i32 inttoptr (i64 4 to i32 (i8*, i32, i8*)*)(i8* nonnull %3, i32 4, i8* nonnull %5) #3, !dbg !34 +; CHECK: call 4 + %7 = load i32, i32* %2, align 4, !dbg !35, !tbaa !36 + call void @llvm.dbg.value(metadata i32 %7, metadata !29, metadata !DIExpression()), !dbg !40 + call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %3) #3, !dbg !41 + ret i32 %7, !dbg !42 +} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 132 +; CHECK-NEXT: .long 132 +; CHECK-NEXT: .long 106 +; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 1) +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 1 # BTF_KIND_STRUCT(id = 2) +; CHECK-NEXT: .long 67108866 # 0x4000002 +; CHECK-NEXT: .long 12 +; CHECK-NEXT: .long 9 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 11 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 32 # 0x20 +; CHECK-NEXT: .long 15 # BTF_KIND_INT(id = 3) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 19 # BTF_KIND_STRUCT(id = 4) +; CHECK-NEXT: .long 67108866 # 0x4000002 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 30 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 37 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 32 # 0x20 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 5) +; CHECK-NEXT: .long 218103809 # 0xd000001 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 44 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 48 # BTF_KIND_FUNC(id = 6) +; CHECK-NEXT: .long 201326592 # 0xc000000 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "sk_buff" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 105 # string offset=9 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "dev" # string offset=11 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "int" # string offset=15 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "net_device" # string offset=19 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "dev_id" # string offset=30 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "others" # string offset=37 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "ctx" # string offset=44 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "bpf_prog" # string offset=48 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".text" # string offset=57 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "/tmp/home/yhs/work/tests/llvm/test.c" # string offset=63 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "0:1:0" # string offset=100 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .section .BTF.ext,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 40 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long 76 +; CHECK-NEXT: .long 96 +; CHECK-NEXT: .long 28 +; CHECK-NEXT: .long 124 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 8 # FuncInfo + +; CHECK: .long 16 # OffsetReloc +; CHECK-NEXT: .long 57 # Offset reloc section string offset=57 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 100 +; CHECK-NEXT: .long 0 # Dependency + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #1 + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #1 + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #2 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "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 = { argmemonly nounwind } +attributes #2 = { nounwind readnone speculatable } +attributes #3 = { 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 8.0.20181009 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm") +!2 = !{} +!3 = !{!4} +!4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression()) +!5 = distinct !DIGlobalVariable(name: "bpf_probe_read", scope: !0, file: !1, line: 10, type: !6, isLocal: true, isDefinition: true) +!6 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64) +!7 = !DISubroutineType(types: !8) +!8 = !{!9, !10, !9, !10} +!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!10 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) +!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 8.0.20181009 "} +!15 = distinct !DISubprogram(name: "bpf_prog", scope: !1, file: !1, line: 13, type: !16, isLocal: false, isDefinition: true, scopeLine: 13, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !27) +!16 = !DISubroutineType(types: !17) +!17 = !{!9, !18} +!18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !19, size: 64) +!19 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "sk_buff", file: !1, line: 5, size: 96, elements: !20) +!20 = !{!21, !22} +!21 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !19, file: !1, line: 6, baseType: !9, size: 32) +!22 = !DIDerivedType(tag: DW_TAG_member, name: "dev", scope: !19, file: !1, line: 7, baseType: !23, size: 64, offset: 32) +!23 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "net_device", file: !1, line: 1, size: 64, elements: !24) +!24 = !{!25, !26} +!25 = !DIDerivedType(tag: DW_TAG_member, name: "dev_id", scope: !23, file: !1, line: 2, baseType: !9, size: 32) +!26 = !DIDerivedType(tag: DW_TAG_member, name: "others", scope: !23, file: !1, line: 3, baseType: !9, size: 32, offset: 32) +!27 = !{!28, !29} +!28 = !DILocalVariable(name: "ctx", arg: 1, scope: !15, file: !1, line: 13, type: !18) +!29 = !DILocalVariable(name: "dev_id", scope: !15, file: !1, line: 14, type: !9) +!30 = !DILocation(line: 13, column: 30, scope: !15) +!31 = !DILocation(line: 14, column: 3, scope: !15) +!32 = !DILocation(line: 15, column: 50, scope: !15) +!33 = !DILocation(line: 15, column: 40, scope: !15) +!34 = !DILocation(line: 15, column: 3, scope: !15) +!35 = !DILocation(line: 16, column: 10, scope: !15) +!36 = !{!37, !37, i64 0} +!37 = !{!"int", !38, i64 0} +!38 = !{!"omnipotent char", !39, i64 0} +!39 = !{!"Simple C/C++ TBAA"} +!40 = !DILocation(line: 14, column: 7, scope: !15) +!41 = !DILocation(line: 17, column: 1, scope: !15) +!42 = !DILocation(line: 16, column: 3, scope: !15) Index: test/CodeGen/BPF/CORE/offset-reloc-struct-anonymous.ll =================================================================== --- /dev/null +++ test/CodeGen/BPF/CORE/offset-reloc-struct-anonymous.ll @@ -0,0 +1,207 @@ +; RUN: llc -march=bpfel -filetype=asm -mattr=offsetreloc -o - %s | FileCheck -check-prefixes=CHECK %s +; RUN: llc -march=bpfeb -filetype=asm -mattr=offsetreloc -o - %s | FileCheck -check-prefixes=CHECK %s +; Source code: +; struct sk_buff { +; int i; +; struct { +; int dev_id; +; int others; +; } dev[10]; +; }; +; +; static int (*bpf_probe_read)(void *dst, int size, void *unsafe_ptr) +; = (void *) 4; +; +; int bpf_prog(struct sk_buff *ctx) { +; int dev_id; +; bpf_probe_read(&dev_id, sizeof(int), &ctx->dev[5].dev_id); +; return dev_id; +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm test.c + +%struct.sk_buff = type { i32, [10 x %struct.anon] } +%struct.anon = type { i32, i32 } + +; Function Attrs: nounwind +define dso_local i32 @bpf_prog(%struct.sk_buff*) local_unnamed_addr #0 !dbg !15 { + %2 = alloca i32, align 4 + call void @llvm.dbg.value(metadata %struct.sk_buff* %0, metadata !31, metadata !DIExpression()), !dbg !33 + %3 = bitcast i32* %2 to i8*, !dbg !34 + call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %3) #3, !dbg !34 + %4 = getelementptr inbounds %struct.sk_buff, %struct.sk_buff* %0, i64 0, i32 1, i64 5, i32 0, !dbg !35 +; CHECK: r1 = 44 +; CHECK-NEXT: r3 += r1 + %5 = bitcast i32* %4 to i8*, !dbg !36 + %6 = call i32 inttoptr (i64 4 to i32 (i8*, i32, i8*)*)(i8* nonnull %3, i32 4, i8* nonnull %5) #3, !dbg !37 +; CHECK: call 4 + %7 = load i32, i32* %2, align 4, !dbg !38, !tbaa !39 + call void @llvm.dbg.value(metadata i32 %7, metadata !32, metadata !DIExpression()), !dbg !43 + call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %3) #3, !dbg !44 + ret i32 %7, !dbg !45 +} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 172 +; CHECK-NEXT: .long 172 +; CHECK-NEXT: .long 117 +; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 1) +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 1 # BTF_KIND_STRUCT(id = 2) +; CHECK-NEXT: .long 67108866 # 0x4000002 +; CHECK-NEXT: .long 84 +; CHECK-NEXT: .long 9 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 11 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 32 # 0x20 +; CHECK-NEXT: .long 15 # BTF_KIND_INT(id = 3) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 0 # BTF_KIND_STRUCT(id = 4) +; CHECK-NEXT: .long 67108866 # 0x4000002 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 19 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 26 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 32 # 0x20 +; CHECK-NEXT: .long 0 # BTF_KIND_ARRAY(id = 5) +; CHECK-NEXT: .long 50331648 # 0x3000000 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .long 10 +; CHECK-NEXT: .long 33 # BTF_KIND_INT(id = 6) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 32 # 0x20 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 7) +; CHECK-NEXT: .long 218103809 # 0xd000001 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 53 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 57 # BTF_KIND_FUNC(id = 8) +; CHECK-NEXT: .long 201326592 # 0xc000000 +; CHECK-NEXT: .long 7 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "sk_buff" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 105 # string offset=9 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "dev" # string offset=11 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "int" # string offset=15 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "dev_id" # string offset=19 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "others" # string offset=26 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "__ARRAY_SIZE_TYPE__" # string offset=33 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "ctx" # string offset=53 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "bpf_prog" # string offset=57 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".text" # string offset=66 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "/tmp/home/yhs/work/tests/llvm/test.c" # string offset=72 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "0:1:5:0" # string offset=109 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .section .BTF.ext,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 40 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long 76 +; CHECK-NEXT: .long 96 +; CHECK-NEXT: .long 28 +; CHECK-NEXT: .long 124 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 8 # FuncInfo + +; CHECK: .long 16 # OffsetReloc +; CHECK-NEXT: .long 66 # Offset reloc section string offset=66 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 109 +; CHECK-NEXT: .long 0 + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #1 + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #1 + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #2 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "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 = { argmemonly nounwind } +attributes #2 = { nounwind readnone speculatable } +attributes #3 = { 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 8.0.20181009 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm") +!2 = !{} +!3 = !{!4} +!4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression()) +!5 = distinct !DIGlobalVariable(name: "bpf_probe_read", scope: !0, file: !1, line: 9, type: !6, isLocal: true, isDefinition: true) +!6 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64) +!7 = !DISubroutineType(types: !8) +!8 = !{!9, !10, !9, !10} +!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!10 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) +!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 8.0.20181009 "} +!15 = distinct !DISubprogram(name: "bpf_prog", scope: !1, file: !1, line: 12, type: !16, isLocal: false, isDefinition: true, scopeLine: 12, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !30) +!16 = !DISubroutineType(types: !17) +!17 = !{!9, !18} +!18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !19, size: 64) +!19 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "sk_buff", file: !1, line: 1, size: 672, elements: !20) +!20 = !{!21, !22} +!21 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !19, file: !1, line: 2, baseType: !9, size: 32) +!22 = !DIDerivedType(tag: DW_TAG_member, name: "dev", scope: !19, file: !1, line: 6, baseType: !23, size: 640, offset: 32) +!23 = !DICompositeType(tag: DW_TAG_array_type, baseType: !24, size: 640, elements: !28) +!24 = distinct !DICompositeType(tag: DW_TAG_structure_type, scope: !19, file: !1, line: 3, size: 64, elements: !25) +!25 = !{!26, !27} +!26 = !DIDerivedType(tag: DW_TAG_member, name: "dev_id", scope: !24, file: !1, line: 4, baseType: !9, size: 32) +!27 = !DIDerivedType(tag: DW_TAG_member, name: "others", scope: !24, file: !1, line: 5, baseType: !9, size: 32, offset: 32) +!28 = !{!29} +!29 = !DISubrange(count: 10) +!30 = !{!31, !32} +!31 = !DILocalVariable(name: "ctx", arg: 1, scope: !15, file: !1, line: 12, type: !18) +!32 = !DILocalVariable(name: "dev_id", scope: !15, file: !1, line: 13, type: !9) +!33 = !DILocation(line: 12, column: 30, scope: !15) +!34 = !DILocation(line: 13, column: 3, scope: !15) +!35 = !DILocation(line: 14, column: 53, scope: !15) +!36 = !DILocation(line: 14, column: 40, scope: !15) +!37 = !DILocation(line: 14, column: 3, scope: !15) +!38 = !DILocation(line: 15, column: 10, scope: !15) +!39 = !{!40, !40, i64 0} +!40 = !{!"int", !41, i64 0} +!41 = !{!"omnipotent char", !42, i64 0} +!42 = !{!"Simple C/C++ TBAA"} +!43 = !DILocation(line: 13, column: 7, scope: !15) +!44 = !DILocation(line: 16, column: 1, scope: !15) +!45 = !DILocation(line: 15, column: 3, scope: !15) Index: test/CodeGen/BPF/CORE/offset-reloc-struct-array.ll =================================================================== --- /dev/null +++ test/CodeGen/BPF/CORE/offset-reloc-struct-array.ll @@ -0,0 +1,210 @@ +; RUN: llc -march=bpfel -filetype=asm -mattr=offsetreloc -o - %s | FileCheck -check-prefixes=CHECK %s +; RUN: llc -march=bpfeb -filetype=asm -mattr=offsetreloc -o - %s | FileCheck -check-prefixes=CHECK %s +; Source code: +; struct net_device { +; int dev_id; +; int others; +; }; +; struct sk_buff { +; int i; +; struct net_device dev[10]; +; }; +; +; static int (*bpf_probe_read)(void *dst, int size, void *unsafe_ptr) +; = (void *) 4; +; +; int bpf_prog(struct sk_buff *ctx) { +; int dev_id; +; bpf_probe_read(&dev_id, sizeof(int), &ctx->dev[5].dev_id); +; return dev_id; +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm test.c + +%struct.sk_buff = type { i32, [10 x %struct.net_device] } +%struct.net_device = type { i32, i32 } + +; Function Attrs: nounwind +define dso_local i32 @bpf_prog(%struct.sk_buff*) local_unnamed_addr #0 !dbg !15 { + %2 = alloca i32, align 4 + call void @llvm.dbg.value(metadata %struct.sk_buff* %0, metadata !31, metadata !DIExpression()), !dbg !33 + %3 = bitcast i32* %2 to i8*, !dbg !34 + call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %3) #3, !dbg !34 + %4 = getelementptr inbounds %struct.sk_buff, %struct.sk_buff* %0, i64 0, i32 1, i64 5, i32 0, !dbg !35 +; CHECK: r1 = 44 +; CHECK-NEXT: r3 += r1 + %5 = bitcast i32* %4 to i8*, !dbg !36 + %6 = call i32 inttoptr (i64 4 to i32 (i8*, i32, i8*)*)(i8* nonnull %3, i32 4, i8* nonnull %5) #3, !dbg !37 +; CHECK: call 4 + %7 = load i32, i32* %2, align 4, !dbg !38, !tbaa !39 + call void @llvm.dbg.value(metadata i32 %7, metadata !32, metadata !DIExpression()), !dbg !43 + call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %3) #3, !dbg !44 + ret i32 %7, !dbg !45 +} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 172 +; CHECK-NEXT: .long 172 +; CHECK-NEXT: .long 128 +; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 1) +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 1 # BTF_KIND_STRUCT(id = 2) +; CHECK-NEXT: .long 67108866 # 0x4000002 +; CHECK-NEXT: .long 84 +; CHECK-NEXT: .long 9 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 11 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 32 # 0x20 +; CHECK-NEXT: .long 15 # BTF_KIND_INT(id = 3) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 19 # BTF_KIND_STRUCT(id = 4) +; CHECK-NEXT: .long 67108866 # 0x4000002 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 30 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 37 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 32 # 0x20 +; CHECK-NEXT: .long 0 # BTF_KIND_ARRAY(id = 5) +; CHECK-NEXT: .long 50331648 # 0x3000000 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .long 10 +; CHECK-NEXT: .long 44 # BTF_KIND_INT(id = 6) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 32 # 0x20 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 7) +; CHECK-NEXT: .long 218103809 # 0xd000001 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 64 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 68 # BTF_KIND_FUNC(id = 8) +; CHECK-NEXT: .long 201326592 # 0xc000000 +; CHECK-NEXT: .long 7 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "sk_buff" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 105 # string offset=9 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "dev" # string offset=11 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "int" # string offset=15 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "net_device" # string offset=19 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "dev_id" # string offset=30 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "others" # string offset=37 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "__ARRAY_SIZE_TYPE__" # string offset=44 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "ctx" # string offset=64 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "bpf_prog" # string offset=68 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".text" # string offset=77 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "/tmp/home/yhs/work/tests/llvm/test.c" # string offset=83 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "0:1:5:0" # string offset=120 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .section .BTF.ext,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 40 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long 76 +; CHECK-NEXT: .long 96 +; CHECK-NEXT: .long 28 +; CHECK-NEXT: .long 124 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 8 # FuncInfo + +; CHECK: .long 16 # OffsetReloc +; CHECK-NEXT: .long 77 # Offset reloc section string offset=77 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 120 +; CHECK-NEXT: .long 0 # Dependency + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #1 + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #1 + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #2 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "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 = { argmemonly nounwind } +attributes #2 = { nounwind readnone speculatable } +attributes #3 = { 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 8.0.20181009 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm") +!2 = !{} +!3 = !{!4} +!4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression()) +!5 = distinct !DIGlobalVariable(name: "bpf_probe_read", scope: !0, file: !1, line: 10, type: !6, isLocal: true, isDefinition: true) +!6 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64) +!7 = !DISubroutineType(types: !8) +!8 = !{!9, !10, !9, !10} +!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!10 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) +!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 8.0.20181009 "} +!15 = distinct !DISubprogram(name: "bpf_prog", scope: !1, file: !1, line: 13, type: !16, isLocal: false, isDefinition: true, scopeLine: 13, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !30) +!16 = !DISubroutineType(types: !17) +!17 = !{!9, !18} +!18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !19, size: 64) +!19 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "sk_buff", file: !1, line: 5, size: 672, elements: !20) +!20 = !{!21, !22} +!21 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !19, file: !1, line: 6, baseType: !9, size: 32) +!22 = !DIDerivedType(tag: DW_TAG_member, name: "dev", scope: !19, file: !1, line: 7, baseType: !23, size: 640, offset: 32) +!23 = !DICompositeType(tag: DW_TAG_array_type, baseType: !24, size: 640, elements: !28) +!24 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "net_device", file: !1, line: 1, size: 64, elements: !25) +!25 = !{!26, !27} +!26 = !DIDerivedType(tag: DW_TAG_member, name: "dev_id", scope: !24, file: !1, line: 2, baseType: !9, size: 32) +!27 = !DIDerivedType(tag: DW_TAG_member, name: "others", scope: !24, file: !1, line: 3, baseType: !9, size: 32, offset: 32) +!28 = !{!29} +!29 = !DISubrange(count: 10) +!30 = !{!31, !32} +!31 = !DILocalVariable(name: "ctx", arg: 1, scope: !15, file: !1, line: 13, type: !18) +!32 = !DILocalVariable(name: "dev_id", scope: !15, file: !1, line: 14, type: !9) +!33 = !DILocation(line: 13, column: 30, scope: !15) +!34 = !DILocation(line: 14, column: 3, scope: !15) +!35 = !DILocation(line: 15, column: 53, scope: !15) +!36 = !DILocation(line: 15, column: 40, scope: !15) +!37 = !DILocation(line: 15, column: 3, scope: !15) +!38 = !DILocation(line: 16, column: 10, scope: !15) +!39 = !{!40, !40, i64 0} +!40 = !{!"int", !41, i64 0} +!41 = !{!"omnipotent char", !42, i64 0} +!42 = !{!"Simple C/C++ TBAA"} +!43 = !DILocation(line: 14, column: 7, scope: !15) +!44 = !DILocation(line: 17, column: 1, scope: !15) +!45 = !DILocation(line: 16, column: 3, scope: !15) Index: test/CodeGen/BPF/CORE/offset-reloc-union.ll =================================================================== --- /dev/null +++ test/CodeGen/BPF/CORE/offset-reloc-union.ll @@ -0,0 +1,213 @@ +; RUN: llc -march=bpfel -filetype=asm -mattr=offsetreloc -o - %s | FileCheck -check-prefixes=CHECK %s +; RUN: llc -march=bpfeb -filetype=asm -mattr=offsetreloc -o - %s | FileCheck -check-prefixes=CHECK %s +; Source code: +; struct sk_buff { +; int i; +; union { +; struct { +; int dev_id; +; int others; +; } dev; +; int netid; +; } u; +; }; +; +; static int (*bpf_probe_read)(void *dst, int size, void *unsafe_ptr) +; = (void *) 4; +; +; int bpf_prog(struct sk_buff *ctx) { +; int dev_id; +; bpf_probe_read(&dev_id, sizeof(int), &ctx->u.dev.dev_id); +; return dev_id; +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm test.c + +%struct.sk_buff = type { i32, %union.anon } +%union.anon = type { %struct.anon } +%struct.anon = type { i32, i32 } + +; Function Attrs: nounwind +define dso_local i32 @bpf_prog(%struct.sk_buff*) local_unnamed_addr #0 !dbg !15 { + %2 = alloca i32, align 4 + call void @llvm.dbg.value(metadata %struct.sk_buff* %0, metadata !32, metadata !DIExpression()), !dbg !34 + %3 = bitcast i32* %2 to i8*, !dbg !35 + call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %3) #3, !dbg !35 + %4 = getelementptr inbounds %struct.sk_buff, %struct.sk_buff* %0, i64 0, i32 1, i32 0, i32 0, !dbg !36 +; CHECK: r1 = 4 +; CHECK-NEXT: r3 += r1 + %5 = bitcast i32* %4 to i8*, !dbg !37 + %6 = call i32 inttoptr (i64 4 to i32 (i8*, i32, i8*)*)(i8* nonnull %3, i32 4, i8* nonnull %5) #3, !dbg !38 +; CHECK: call 4 + %7 = load i32, i32* %2, align 4, !dbg !39, !tbaa !40 + call void @llvm.dbg.value(metadata i32 %7, metadata !33, metadata !DIExpression()), !dbg !44 + call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %3) #3, !dbg !45 + ret i32 %7, !dbg !46 +} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 168 +; CHECK-NEXT: .long 168 +; CHECK-NEXT: .long 105 +; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 1) +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 1 # BTF_KIND_STRUCT(id = 2) +; CHECK-NEXT: .long 67108866 # 0x4000002 +; CHECK-NEXT: .long 12 +; CHECK-NEXT: .long 9 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 11 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 32 # 0x20 +; CHECK-NEXT: .long 13 # BTF_KIND_INT(id = 3) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 0 # BTF_KIND_UNION(id = 4) +; CHECK-NEXT: .long 83886082 # 0x5000002 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 17 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 21 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 0 # BTF_KIND_STRUCT(id = 5) +; CHECK-NEXT: .long 67108866 # 0x4000002 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 27 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 34 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 32 # 0x20 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 6) +; CHECK-NEXT: .long 218103809 # 0xd000001 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 41 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 45 # BTF_KIND_FUNC(id = 7) +; CHECK-NEXT: .long 201326592 # 0xc000000 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "sk_buff" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 105 # string offset=9 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 117 # string offset=11 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "int" # string offset=13 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "dev" # string offset=17 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "netid" # string offset=21 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "dev_id" # string offset=27 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "others" # string offset=34 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "ctx" # string offset=41 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "bpf_prog" # string offset=45 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".text" # string offset=54 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "/tmp/home/yhs/work/tests/llvm/test.c" # string offset=60 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "0:1:0:0" # string offset=97 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .section .BTF.ext,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 40 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long 76 +; CHECK-NEXT: .long 96 +; CHECK-NEXT: .long 28 +; CHECK-NEXT: .long 124 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 8 # FuncInfo + +; CHECK: .long 16 # OffsetReloc +; CHECK-NEXT: .long 54 # Offset reloc section string offset=54 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 97 +; CHECK-NEXT: .long 0 # Dependency + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #1 + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #1 + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #2 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "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 = { argmemonly nounwind } +attributes #2 = { nounwind readnone speculatable } +attributes #3 = { 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 8.0.20181009 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm") +!2 = !{} +!3 = !{!4} +!4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression()) +!5 = distinct !DIGlobalVariable(name: "bpf_probe_read", scope: !0, file: !1, line: 12, type: !6, isLocal: true, isDefinition: true) +!6 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64) +!7 = !DISubroutineType(types: !8) +!8 = !{!9, !10, !9, !10} +!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!10 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) +!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 8.0.20181009 "} +!15 = distinct !DISubprogram(name: "bpf_prog", scope: !1, file: !1, line: 15, type: !16, isLocal: false, isDefinition: true, scopeLine: 15, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !31) +!16 = !DISubroutineType(types: !17) +!17 = !{!9, !18} +!18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !19, size: 64) +!19 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "sk_buff", file: !1, line: 1, size: 96, elements: !20) +!20 = !{!21, !22} +!21 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !19, file: !1, line: 2, baseType: !9, size: 32) +!22 = !DIDerivedType(tag: DW_TAG_member, name: "u", scope: !19, file: !1, line: 9, baseType: !23, size: 64, offset: 32) +!23 = distinct !DICompositeType(tag: DW_TAG_union_type, scope: !19, file: !1, line: 3, size: 64, elements: !24) +!24 = !{!25, !30} +!25 = !DIDerivedType(tag: DW_TAG_member, name: "dev", scope: !23, file: !1, line: 7, baseType: !26, size: 64) +!26 = distinct !DICompositeType(tag: DW_TAG_structure_type, scope: !23, file: !1, line: 4, size: 64, elements: !27) +!27 = !{!28, !29} +!28 = !DIDerivedType(tag: DW_TAG_member, name: "dev_id", scope: !26, file: !1, line: 5, baseType: !9, size: 32) +!29 = !DIDerivedType(tag: DW_TAG_member, name: "others", scope: !26, file: !1, line: 6, baseType: !9, size: 32, offset: 32) +!30 = !DIDerivedType(tag: DW_TAG_member, name: "netid", scope: !23, file: !1, line: 8, baseType: !9, size: 32) +!31 = !{!32, !33} +!32 = !DILocalVariable(name: "ctx", arg: 1, scope: !15, file: !1, line: 15, type: !18) +!33 = !DILocalVariable(name: "dev_id", scope: !15, file: !1, line: 16, type: !9) +!34 = !DILocation(line: 15, column: 30, scope: !15) +!35 = !DILocation(line: 16, column: 3, scope: !15) +!36 = !DILocation(line: 17, column: 52, scope: !15) +!37 = !DILocation(line: 17, column: 40, scope: !15) +!38 = !DILocation(line: 17, column: 3, scope: !15) +!39 = !DILocation(line: 18, column: 10, scope: !15) +!40 = !{!41, !41, i64 0} +!41 = !{!"int", !42, i64 0} +!42 = !{!"omnipotent char", !43, i64 0} +!43 = !{!"Simple C/C++ TBAA"} +!44 = !DILocation(line: 16, column: 7, scope: !15) +!45 = !DILocation(line: 19, column: 1, scope: !15) +!46 = !DILocation(line: 18, column: 3, scope: !15) Index: test/CodeGen/BPF/CORE/patchable-extern-char.ll =================================================================== --- /dev/null +++ test/CodeGen/BPF/CORE/patchable-extern-char.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: +; extern __attribute__((section(".BPF.patchable_externs"))) char a; +; int foo() { return a; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm test.c + +@a = external dso_local local_unnamed_addr global i8, section ".BPF.patchable_externs", align 1 + +; Function Attrs: norecurse nounwind readonly +define dso_local i32 @foo() local_unnamed_addr #0 !dbg !7 { + %1 = load i8, i8* @a, align 1, !dbg !11, !tbaa !12 + %2 = sext i8 %1 to i32, !dbg !11 +; CHECK: r0 = 0 +; CHECK-NEXT: r0 <<= 56 +; CHECK-NEXT: r0 s>>= 56 + ret i32 %2, !dbg !15 +} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 40 +; CHECK-NEXT: .long 40 +; CHECK-NEXT: .long 54 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1) +; CHECK-NEXT: .long 218103808 # 0xd000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 5 # BTF_KIND_FUNC(id = 3) +; CHECK-NEXT: .long 201326592 # 0xc000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "int" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "foo" # string offset=5 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".text" # string offset=9 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 97 # string offset=15 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "/tmp/home/yhs/work/tests/llvm/test.c" # string offset=17 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .section .BTF.ext,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 40 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long 44 +; CHECK-NEXT: .long 64 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 64 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long 8 # FuncInfo +; CHECK-NEXT: .long 9 # FuncInfo section string offset=9 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Lfunc_begin0 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 16 # LineInfo +; CHECK-NEXT: .long 9 # LineInfo section string offset=9 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 17 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 2068 # Line 2 Col 20 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 17 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 2061 # Line 2 Col 13 +; CHECK-NEXT: .long 8 # ExternReloc +; CHECK-NEXT: .long 9 # Extern reloc section string offset=9 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 15 + +attributes #0 = { norecurse nounwind readonly "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "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" } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 8.0.20181009 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 8.0.20181009 "} +!7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 2, type: !8, isLocal: false, isDefinition: true, scopeLine: 2, isOptimized: true, unit: !0, retainedNodes: !2) +!8 = !DISubroutineType(types: !9) +!9 = !{!10} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !DILocation(line: 2, column: 20, scope: !7) +!12 = !{!13, !13, i64 0} +!13 = !{!"omnipotent char", !14, i64 0} +!14 = !{!"Simple C/C++ TBAA"} +!15 = !DILocation(line: 2, column: 13, scope: !7) Index: test/CodeGen/BPF/CORE/patchable-extern-uint.ll =================================================================== --- /dev/null +++ test/CodeGen/BPF/CORE/patchable-extern-uint.ll @@ -0,0 +1,102 @@ +; 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: +; extern __attribute__((section(".BPF.patchable_externs"))) unsigned a; +; int foo() { return a; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm test.c + +@a = external dso_local local_unnamed_addr global i32, section ".BPF.patchable_externs", align 4 + +; Function Attrs: norecurse nounwind readonly +define dso_local i32 @foo() local_unnamed_addr #0 !dbg !7 { + %1 = load i32, i32* @a, align 4, !dbg !11, !tbaa !12 +; CHECK: r0 = 0 +; CHECK-NEXT: exit + ret i32 %1, !dbg !16 +} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 40 +; CHECK-NEXT: .long 40 +; CHECK-NEXT: .long 49 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1) +; CHECK-NEXT: .long 218103808 # 0xd000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 5 # BTF_KIND_FUNC(id = 3) +; CHECK-NEXT: .long 201326592 # 0xc000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "int" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "foo" # string offset=5 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".text" # string offset=9 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 97 # string offset=15 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "/tmp/yhs/work/tests/llvm/test.c" # string offset=17 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .section .BTF.ext,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 40 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long 28 +; CHECK-NEXT: .long 48 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 48 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long 8 # FuncInfo +; CHECK-NEXT: .long 9 # FuncInfo section string offset=9 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Lfunc_begin0 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 16 # LineInfo +; CHECK-NEXT: .long 9 # LineInfo section string offset=9 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 17 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 2061 # Line 2 Col 13 +; CHECK-NEXT: .long 8 # ExternReloc +; CHECK-NEXT: .long 9 # Extern reloc section string offset=9 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 15 + +attributes #0 = { norecurse nounwind readonly "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "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" } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 8.0.20181009 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/yhs/work/tests/llvm") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 8.0.20181009 "} +!7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 2, type: !8, isLocal: false, isDefinition: true, scopeLine: 2, isOptimized: true, unit: !0, retainedNodes: !2) +!8 = !DISubroutineType(types: !9) +!9 = !{!10} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !DILocation(line: 2, column: 20, scope: !7) +!12 = !{!13, !13, i64 0} +!13 = !{!"int", !14, i64 0} +!14 = !{!"omnipotent char", !15, i64 0} +!15 = !{!"Simple C/C++ TBAA"} +!16 = !DILocation(line: 2, column: 13, scope: !7) Index: test/CodeGen/BPF/CORE/patchable-extern-ulonglong.ll =================================================================== --- /dev/null +++ test/CodeGen/BPF/CORE/patchable-extern-ulonglong.ll @@ -0,0 +1,103 @@ +; 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: +; extern __attribute__((section(".BPF.patchable_externs"))) unsigned long long a; +; int foo() { return a; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm test.c + +@a = external dso_local local_unnamed_addr global i64, section ".BPF.patchable_externs", align 8 + +; Function Attrs: norecurse nounwind readonly +define dso_local i32 @foo() local_unnamed_addr #0 !dbg !7 { + %1 = load i64, i64* @a, align 8, !dbg !11, !tbaa !12 + %2 = trunc i64 %1 to i32, !dbg !11 +; CHECK: r0 = 0 ll +; CHECK-NEXT: exit + ret i32 %2, !dbg !16 +} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 40 +; CHECK-NEXT: .long 40 +; CHECK-NEXT: .long 54 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1) +; CHECK-NEXT: .long 218103808 # 0xd000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 5 # BTF_KIND_FUNC(id = 3) +; CHECK-NEXT: .long 201326592 # 0xc000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "int" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "foo" # string offset=5 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".text" # string offset=9 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 97 # string offset=15 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "/tmp/home/yhs/work/tests/llvm/test.c" # string offset=17 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .section .BTF.ext,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 40 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long 28 +; CHECK-NEXT: .long 48 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 48 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long 8 # FuncInfo +; CHECK-NEXT: .long 9 # FuncInfo section string offset=9 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Lfunc_begin0 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 16 # LineInfo +; CHECK-NEXT: .long 9 # LineInfo section string offset=9 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 17 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 2061 # Line 2 Col 13 +; CHECK-NEXT: .long 8 # ExternReloc +; CHECK-NEXT: .long 9 # Extern reloc section string offset=9 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 15 + +attributes #0 = { norecurse nounwind readonly "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "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" } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 8.0.20181009 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 8.0.20181009 "} +!7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 2, type: !8, isLocal: false, isDefinition: true, scopeLine: 2, isOptimized: true, unit: !0, retainedNodes: !2) +!8 = !DISubroutineType(types: !9) +!9 = !{!10} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !DILocation(line: 2, column: 20, scope: !7) +!12 = !{!13, !13, i64 0} +!13 = !{!"long long", !14, i64 0} +!14 = !{!"omnipotent char", !15, i64 0} +!15 = !{!"Simple C/C++ TBAA"} +!16 = !DILocation(line: 2, column: 13, scope: !7)