Index: include/clang/Basic/TargetInfo.h =================================================================== --- include/clang/Basic/TargetInfo.h +++ include/clang/Basic/TargetInfo.h @@ -1368,6 +1368,8 @@ virtual void setAuxTarget(const TargetInfo *Aux) {} + virtual bool isPreserveDIAccessIndexNeeded() const { return false; } + protected: /// Copy type and layout related info. void copyAuxTarget(const TargetInfo *Aux); Index: lib/Basic/Targets/BPF.h =================================================================== --- lib/Basic/Targets/BPF.h +++ lib/Basic/Targets/BPF.h @@ -22,9 +22,12 @@ namespace targets { class LLVM_LIBRARY_VISIBILITY BPFTargetInfo : public TargetInfo { +private: + const TargetOptions &TargetOpts; + public: - BPFTargetInfo(const llvm::Triple &Triple, const TargetOptions &) - : TargetInfo(Triple) { + BPFTargetInfo(const llvm::Triple &Triple, const TargetOptions &Options) + : TargetInfo(Triple), TargetOpts(Options) { LongWidth = LongAlign = PointerWidth = PointerAlign = 64; SizeType = UnsignedLong; PtrDiffType = SignedLong; @@ -46,7 +49,8 @@ MacroBuilder &Builder) const override; bool hasFeature(StringRef Feature) const override { - return Feature == "bpf" || Feature == "alu32" || Feature == "dwarfris"; + return Feature == "bpf" || Feature == "alu32" || Feature == "dwarfris" || + Feature == "offsetreloc"; } void setFeatureEnabled(llvm::StringMap &Features, StringRef Name, @@ -92,6 +96,16 @@ StringRef CPUName(Name); return isValidCPUName(CPUName); } + + bool isPreserveDIAccessIndexNeeded() const override { + const std::vector &Features = TargetOpts.Features; + for (auto &Feature : Features) { + if (Feature == "+offsetreloc") + return true; + } + + return false; + } }; } // namespace targets } // namespace clang Index: lib/CodeGen/CGBuilder.h =================================================================== --- lib/CodeGen/CGBuilder.h +++ lib/CodeGen/CGBuilder.h @@ -298,6 +298,22 @@ return CreateMemSet(Dest.getPointer(), Value, Size, Dest.getAlignment().getQuantity(), IsVolatile); } + + using CGBuilderBaseTy::CreatePreserveStructAccessIndex; + Address CreatePreserveStructAccessIndex(Address Addr, + llvm::StringRef StructName, + unsigned Index, + unsigned FieldIndex) { + llvm::StructType *ElTy = cast(Addr.getElementType()); + const llvm::DataLayout &DL = BB->getParent()->getParent()->getDataLayout(); + const llvm::StructLayout *Layout = DL.getStructLayout(ElTy); + auto Offset = CharUnits::fromQuantity(Layout->getElementOffset(Index)); + + return Address(CreatePreserveStructAccessIndex(Addr.getPointer(), + StructName, + Index, FieldIndex), + Addr.getAlignment().alignmentAtOffset(Offset)); + } }; } // end namespace CodeGen Index: lib/CodeGen/CGExpr.cpp =================================================================== --- lib/CodeGen/CGExpr.cpp +++ lib/CodeGen/CGExpr.cpp @@ -3350,8 +3350,19 @@ CharUnits eltAlign = getArrayElementAlign(addr.getAlignment(), indices.back(), eltSize); - llvm::Value *eltPtr = emitArraySubscriptGEP( - CGF, addr.getPointer(), indices, inbounds, signedIndices, loc, name); + llvm::Value *eltPtr; + auto LastIndex = dyn_cast(indices.back()); + if (!CGF.getTarget().isPreserveDIAccessIndexNeeded() || !LastIndex) { + eltPtr = emitArraySubscriptGEP( + CGF, addr.getPointer(), indices, inbounds, signedIndices, loc, name); + } else { + // Remember the original array subscript for bpf target + unsigned idx = LastIndex->getZExtValue(); + eltPtr = CGF.Builder.CreatePreserveArrayAccessIndex(addr.getPointer(), + indices.size() - 1, + idx); + } + return Address(eltPtr, eltAlign); } @@ -3825,6 +3836,17 @@ return CGF.Builder.CreateStructGEP(base, idx, field->getName()); } +static Address emitPreserveStructAccess(CodeGenFunction &CGF, Address base, + const FieldDecl *field) { + const RecordDecl *rec = field->getParent(); + + unsigned idx = + CGF.CGM.getTypes().getCGRecordLayout(rec).getLLVMFieldNo(field); + + return CGF.Builder.CreatePreserveStructAccessIndex( + base, rec->getName(), idx, field->getFieldIndex()); +} + static bool hasAnyVptr(const QualType Type, const ASTContext &Context) { const auto *RD = Type.getTypePtr()->getAsCXXRecordDecl(); if (!RD) @@ -3932,9 +3954,21 @@ // a barrier every time CXXRecord field with vptr is referenced. addr = Address(Builder.CreateLaunderInvariantGroup(addr.getPointer()), addr.getAlignment()); + + if (getTarget().isPreserveDIAccessIndexNeeded()) + // Remember the original union field index + addr = Address( + Builder.CreatePreserveUnionAccessIndex( + addr.getPointer(), rec->getName(), field->getFieldIndex()), + addr.getAlignment()); } else { - // For structs, we GEP to the field that the record layout suggests. - addr = emitAddrOfFieldStorage(*this, addr, field); + + if (!getTarget().isPreserveDIAccessIndexNeeded()) + // For structs, we GEP to the field that the record layout suggests. + addr = emitAddrOfFieldStorage(*this, addr, field); + else + // Remember the original struct field index + addr = emitPreserveStructAccess(*this, addr, field); // If this is a reference field, load the reference right now. if (FieldType->isReferenceType()) { Index: test/CodeGen/bpf-offsetreloc.c =================================================================== --- /dev/null +++ test/CodeGen/bpf-offsetreloc.c @@ -0,0 +1,17 @@ +// RUN: %clang -target bpf -emit-llvm -S -Xclang -target-feature -Xclang +offsetreloc -o - %s > %t1 +// RUN: grep "llvm.preserve.struct.access.index" %t1 +// RUN: grep "llvm.preserve.array.access.index" %t1 +// RUN: grep "llvm.preserve.union.access.index" %t1 + +struct t { + int i:1; + int j:2; + union { + int a; + int b; + } c[4]; +}; + +void *test(struct t *arg) { + return &arg->c[3].b; +}