diff --git a/llvm/include/llvm/Analysis/MemoryBuiltins.h b/llvm/include/llvm/Analysis/MemoryBuiltins.h index 827b5081b2ce7..d080a5956a4d8 100644 --- a/llvm/include/llvm/Analysis/MemoryBuiltins.h +++ b/llvm/include/llvm/Analysis/MemoryBuiltins.h @@ -187,80 +187,125 @@ Value *lowerObjectSizeCall( const TargetLibraryInfo *TLI, AAResults *AA, bool MustSucceed, SmallVectorImpl *InsertedInstructions = nullptr); -using SizeOffsetType = std::pair; +/// SizeOffsetType - A base template class for the object size visitors. Used +/// here as a self-documenting way to handle the values rather than using a +/// \p std::pair. +template class SizeOffsetType { +public: + T Size; + T Offset; + + SizeOffsetType() = default; + SizeOffsetType(T Size, T Offset) : Size(Size), Offset(Offset) {} + + bool knownSize() const { return C::known(Size); } + bool knownOffset() const { return C::known(Offset); } + bool anyKnown() const { return knownSize() || knownOffset(); } + bool bothKnown() const { return knownSize() && knownOffset(); } + + bool operator==(const SizeOffsetType &RHS) const { + return Size == RHS.Size && Offset == RHS.Offset; + } + bool operator!=(const SizeOffsetType &RHS) const { + return !(*this == RHS); + } +}; + +/// SizeOffsetAPInt - Used by \p ObjectSizeOffsetVisitor, which works with +/// \p APInts. +class SizeOffsetAPInt : public SizeOffsetType { + friend class SizeOffsetType; + static bool known(APInt V) { return V.getBitWidth() > 1; } + +public: + SizeOffsetAPInt() = default; + SizeOffsetAPInt(APInt Size, APInt Offset) : SizeOffsetType(Size, Offset) {} +}; /// Evaluate the size and offset of an object pointed to by a Value* /// statically. Fails if size or offset are not known at compile time. class ObjectSizeOffsetVisitor - : public InstVisitor { + : public InstVisitor { const DataLayout &DL; const TargetLibraryInfo *TLI; ObjectSizeOpts Options; unsigned IntTyBits; APInt Zero; - SmallDenseMap SeenInsts; + SmallDenseMap SeenInsts; unsigned InstructionsVisited; APInt align(APInt Size, MaybeAlign Align); - SizeOffsetType unknown() { - return std::make_pair(APInt(), APInt()); - } + static SizeOffsetAPInt unknown() { return SizeOffsetAPInt(); } public: ObjectSizeOffsetVisitor(const DataLayout &DL, const TargetLibraryInfo *TLI, LLVMContext &Context, ObjectSizeOpts Options = {}); - SizeOffsetType compute(Value *V); - - static bool knownSize(const SizeOffsetType &SizeOffset) { - return SizeOffset.first.getBitWidth() > 1; - } - - static bool knownOffset(const SizeOffsetType &SizeOffset) { - return SizeOffset.second.getBitWidth() > 1; - } - - static bool bothKnown(const SizeOffsetType &SizeOffset) { - return knownSize(SizeOffset) && knownOffset(SizeOffset); - } + SizeOffsetAPInt compute(Value *V); // These are "private", except they can't actually be made private. Only // compute() should be used by external users. - SizeOffsetType visitAllocaInst(AllocaInst &I); - SizeOffsetType visitArgument(Argument &A); - SizeOffsetType visitCallBase(CallBase &CB); - SizeOffsetType visitConstantPointerNull(ConstantPointerNull&); - SizeOffsetType visitExtractElementInst(ExtractElementInst &I); - SizeOffsetType visitExtractValueInst(ExtractValueInst &I); - SizeOffsetType visitGlobalAlias(GlobalAlias &GA); - SizeOffsetType visitGlobalVariable(GlobalVariable &GV); - SizeOffsetType visitIntToPtrInst(IntToPtrInst&); - SizeOffsetType visitLoadInst(LoadInst &I); - SizeOffsetType visitPHINode(PHINode&); - SizeOffsetType visitSelectInst(SelectInst &I); - SizeOffsetType visitUndefValue(UndefValue&); - SizeOffsetType visitInstruction(Instruction &I); + SizeOffsetAPInt visitAllocaInst(AllocaInst &I); + SizeOffsetAPInt visitArgument(Argument &A); + SizeOffsetAPInt visitCallBase(CallBase &CB); + SizeOffsetAPInt visitConstantPointerNull(ConstantPointerNull &); + SizeOffsetAPInt visitExtractElementInst(ExtractElementInst &I); + SizeOffsetAPInt visitExtractValueInst(ExtractValueInst &I); + SizeOffsetAPInt visitGlobalAlias(GlobalAlias &GA); + SizeOffsetAPInt visitGlobalVariable(GlobalVariable &GV); + SizeOffsetAPInt visitIntToPtrInst(IntToPtrInst &); + SizeOffsetAPInt visitLoadInst(LoadInst &I); + SizeOffsetAPInt visitPHINode(PHINode &); + SizeOffsetAPInt visitSelectInst(SelectInst &I); + SizeOffsetAPInt visitUndefValue(UndefValue &); + SizeOffsetAPInt visitInstruction(Instruction &I); private: - SizeOffsetType findLoadSizeOffset( + SizeOffsetAPInt findLoadSizeOffset( LoadInst &LoadFrom, BasicBlock &BB, BasicBlock::iterator From, - SmallDenseMap &VisitedBlocks, + SmallDenseMap &VisitedBlocks, unsigned &ScannedInstCount); - SizeOffsetType combineSizeOffset(SizeOffsetType LHS, SizeOffsetType RHS); - SizeOffsetType computeImpl(Value *V); - SizeOffsetType computeValue(Value *V); + SizeOffsetAPInt combineSizeOffset(SizeOffsetAPInt LHS, SizeOffsetAPInt RHS); + SizeOffsetAPInt computeImpl(Value *V); + SizeOffsetAPInt computeValue(Value *V); bool CheckedZextOrTrunc(APInt &I); }; -using SizeOffsetEvalType = std::pair; +/// SizeOffsetValue - Used by \p ObjectSizeOffsetEvaluator, which works with +/// \p Values. +class SizeOffsetWeakTrackingVH; +class SizeOffsetValue : public SizeOffsetType { + friend class SizeOffsetType; + static bool known(Value *V) { return V != nullptr; } + +public: + SizeOffsetValue() : SizeOffsetType(nullptr, nullptr) {} + SizeOffsetValue(Value *Size, Value *Offset) : SizeOffsetType(Size, Offset) {} + SizeOffsetValue(const SizeOffsetWeakTrackingVH &SOT); +}; + +/// SizeOffsetWeakTrackingVH - Used by \p ObjectSizeOffsetEvaluator in a +/// \p DenseMap. +class SizeOffsetWeakTrackingVH + : public SizeOffsetType { + friend class SizeOffsetType; + static bool known(WeakTrackingVH V) { return V.pointsToAliveValue(); } + +public: + SizeOffsetWeakTrackingVH() : SizeOffsetType(nullptr, nullptr) {} + SizeOffsetWeakTrackingVH(Value *Size, Value *Offset) + : SizeOffsetType(Size, Offset) {} + SizeOffsetWeakTrackingVH(const SizeOffsetValue &SOV) + : SizeOffsetType(SOV.Size, SOV.Offset) {} +}; /// Evaluate the size and offset of an object pointed to by a Value*. /// May create code to compute the result at run-time. class ObjectSizeOffsetEvaluator - : public InstVisitor { + : public InstVisitor { using BuilderTy = IRBuilder; - using WeakEvalType = std::pair; + using WeakEvalType = SizeOffsetWeakTrackingVH; using CacheMapTy = DenseMap; using PtrSetTy = SmallPtrSet; @@ -275,45 +320,27 @@ class ObjectSizeOffsetEvaluator ObjectSizeOpts EvalOpts; SmallPtrSet InsertedInstructions; - SizeOffsetEvalType compute_(Value *V); + SizeOffsetValue compute_(Value *V); public: - static SizeOffsetEvalType unknown() { - return std::make_pair(nullptr, nullptr); - } - ObjectSizeOffsetEvaluator(const DataLayout &DL, const TargetLibraryInfo *TLI, LLVMContext &Context, ObjectSizeOpts EvalOpts = {}); - SizeOffsetEvalType compute(Value *V); - - bool knownSize(SizeOffsetEvalType SizeOffset) { - return SizeOffset.first; - } - - bool knownOffset(SizeOffsetEvalType SizeOffset) { - return SizeOffset.second; - } - - bool anyKnown(SizeOffsetEvalType SizeOffset) { - return knownSize(SizeOffset) || knownOffset(SizeOffset); - } + static SizeOffsetValue unknown() { return SizeOffsetValue(); } - bool bothKnown(SizeOffsetEvalType SizeOffset) { - return knownSize(SizeOffset) && knownOffset(SizeOffset); - } + SizeOffsetValue compute(Value *V); // The individual instruction visitors should be treated as private. - SizeOffsetEvalType visitAllocaInst(AllocaInst &I); - SizeOffsetEvalType visitCallBase(CallBase &CB); - SizeOffsetEvalType visitExtractElementInst(ExtractElementInst &I); - SizeOffsetEvalType visitExtractValueInst(ExtractValueInst &I); - SizeOffsetEvalType visitGEPOperator(GEPOperator &GEP); - SizeOffsetEvalType visitIntToPtrInst(IntToPtrInst&); - SizeOffsetEvalType visitLoadInst(LoadInst &I); - SizeOffsetEvalType visitPHINode(PHINode &PHI); - SizeOffsetEvalType visitSelectInst(SelectInst &I); - SizeOffsetEvalType visitInstruction(Instruction &I); + SizeOffsetValue visitAllocaInst(AllocaInst &I); + SizeOffsetValue visitCallBase(CallBase &CB); + SizeOffsetValue visitExtractElementInst(ExtractElementInst &I); + SizeOffsetValue visitExtractValueInst(ExtractValueInst &I); + SizeOffsetValue visitGEPOperator(GEPOperator &GEP); + SizeOffsetValue visitIntToPtrInst(IntToPtrInst &); + SizeOffsetValue visitLoadInst(LoadInst &I); + SizeOffsetValue visitPHINode(PHINode &PHI); + SizeOffsetValue visitSelectInst(SelectInst &I); + SizeOffsetValue visitInstruction(Instruction &I); }; } // end namespace llvm diff --git a/llvm/lib/Analysis/MemoryBuiltins.cpp b/llvm/lib/Analysis/MemoryBuiltins.cpp index 9e6811f3bf881..46a7a921d86d3 100644 --- a/llvm/lib/Analysis/MemoryBuiltins.cpp +++ b/llvm/lib/Analysis/MemoryBuiltins.cpp @@ -577,10 +577,12 @@ Value *llvm::getFreedOperand(const CallBase *CB, const TargetLibraryInfo *TLI) { //===----------------------------------------------------------------------===// // Utility functions to compute size of objects. // -static APInt getSizeWithOverflow(const SizeOffsetType &Data) { - if (Data.second.isNegative() || Data.first.ult(Data.second)) - return APInt(Data.first.getBitWidth(), 0); - return Data.first - Data.second; +static APInt getSizeWithOverflow(const SizeOffsetAPInt &Data) { + APInt Size = Data.Size; + APInt Offset = Data.Offset; + if (Offset.isNegative() || Size.ult(Offset)) + return APInt(Size.getBitWidth(), 0); + return Size - Offset; } /// Compute the size of the object pointed by Ptr. Returns true and the @@ -590,8 +592,8 @@ static APInt getSizeWithOverflow(const SizeOffsetType &Data) { bool llvm::getObjectSize(const Value *Ptr, uint64_t &Size, const DataLayout &DL, const TargetLibraryInfo *TLI, ObjectSizeOpts Opts) { ObjectSizeOffsetVisitor Visitor(DL, TLI, Ptr->getContext(), Opts); - SizeOffsetType Data = Visitor.compute(const_cast(Ptr)); - if (!Visitor.bothKnown(Data)) + SizeOffsetAPInt Data = Visitor.compute(const_cast(Ptr)); + if (!Data.bothKnown()) return false; Size = getSizeWithOverflow(Data).getZExtValue(); @@ -640,8 +642,7 @@ Value *llvm::lowerObjectSizeCall( } else { LLVMContext &Ctx = ObjectSize->getFunction()->getContext(); ObjectSizeOffsetEvaluator Eval(DL, TLI, Ctx, EvalOptions); - SizeOffsetEvalType SizeOffsetPair = - Eval.compute(ObjectSize->getArgOperand(0)); + SizeOffsetValue SizeOffsetPair = Eval.compute(ObjectSize->getArgOperand(0)); if (SizeOffsetPair != ObjectSizeOffsetEvaluator::unknown()) { IRBuilder Builder( @@ -651,19 +652,19 @@ Value *llvm::lowerObjectSizeCall( })); Builder.SetInsertPoint(ObjectSize); + Value *Size = SizeOffsetPair.Size; + Value *Offset = SizeOffsetPair.Offset; + // If we've outside the end of the object, then we can always access // exactly 0 bytes. - Value *ResultSize = - Builder.CreateSub(SizeOffsetPair.first, SizeOffsetPair.second); - Value *UseZero = - Builder.CreateICmpULT(SizeOffsetPair.first, SizeOffsetPair.second); + Value *ResultSize = Builder.CreateSub(Size, Offset); + Value *UseZero = Builder.CreateICmpULT(Size, Offset); ResultSize = Builder.CreateZExtOrTrunc(ResultSize, ResultType); Value *Ret = Builder.CreateSelect( UseZero, ConstantInt::get(ResultType, 0), ResultSize); // The non-constant size expression cannot evaluate to -1. - if (!isa(SizeOffsetPair.first) || - !isa(SizeOffsetPair.second)) + if (!isa(Size) || !isa(Offset)) Builder.CreateAssumption( Builder.CreateICmpNE(Ret, ConstantInt::get(ResultType, -1))); @@ -697,12 +698,12 @@ ObjectSizeOffsetVisitor::ObjectSizeOffsetVisitor(const DataLayout &DL, // a different address space. } -SizeOffsetType ObjectSizeOffsetVisitor::compute(Value *V) { +SizeOffsetAPInt ObjectSizeOffsetVisitor::compute(Value *V) { InstructionsVisited = 0; return computeImpl(V); } -SizeOffsetType ObjectSizeOffsetVisitor::computeImpl(Value *V) { +SizeOffsetAPInt ObjectSizeOffsetVisitor::computeImpl(Value *V) { unsigned InitialIntTyBits = DL.getIndexTypeSizeInBits(V->getType()); // Stripping pointer casts can strip address space casts which can change the @@ -719,7 +720,7 @@ SizeOffsetType ObjectSizeOffsetVisitor::computeImpl(Value *V) { IntTyBits = DL.getIndexTypeSizeInBits(V->getType()); Zero = APInt::getZero(IntTyBits); - SizeOffsetType SOT = computeValue(V); + SizeOffsetAPInt SOT = computeValue(V); bool IndexTypeSizeChanged = InitialIntTyBits != IntTyBits; if (!IndexTypeSizeChanged && Offset.isZero()) @@ -729,27 +730,28 @@ SizeOffsetType ObjectSizeOffsetVisitor::computeImpl(Value *V) { // accumulated some constant offset (or both). Readjust the bit width to match // the argument index type size and apply the offset, as required. if (IndexTypeSizeChanged) { - if (knownSize(SOT) && !::CheckedZextOrTrunc(SOT.first, InitialIntTyBits)) - SOT.first = APInt(); - if (knownOffset(SOT) && !::CheckedZextOrTrunc(SOT.second, InitialIntTyBits)) - SOT.second = APInt(); + if (SOT.knownSize() && !::CheckedZextOrTrunc(SOT.Size, InitialIntTyBits)) + SOT.Size = APInt(); + if (SOT.knownOffset() && + !::CheckedZextOrTrunc(SOT.Offset, InitialIntTyBits)) + SOT.Offset = APInt(); } // If the computed offset is "unknown" we cannot add the stripped offset. - return {SOT.first, - SOT.second.getBitWidth() > 1 ? SOT.second + Offset : SOT.second}; + return {SOT.Size, + SOT.Offset.getBitWidth() > 1 ? SOT.Offset + Offset : SOT.Offset}; } -SizeOffsetType ObjectSizeOffsetVisitor::computeValue(Value *V) { +SizeOffsetAPInt ObjectSizeOffsetVisitor::computeValue(Value *V) { if (Instruction *I = dyn_cast(V)) { // If we have already seen this instruction, bail out. Cycles can happen in // unreachable code after constant propagation. - auto P = SeenInsts.try_emplace(I, unknown()); + auto P = SeenInsts.try_emplace(I, ObjectSizeOffsetVisitor::unknown()); if (!P.second) return P.first->second; ++InstructionsVisited; if (InstructionsVisited > ObjectSizeOffsetVisitorMaxVisitInstructions) - return unknown(); - SizeOffsetType Res = visit(*I); + return ObjectSizeOffsetVisitor::unknown(); + SizeOffsetAPInt Res = visit(*I); // Cache the result for later visits. If we happened to visit this during // the above recursion, we would consider it unknown until now. SeenInsts[I] = Res; @@ -768,55 +770,55 @@ SizeOffsetType ObjectSizeOffsetVisitor::computeValue(Value *V) { LLVM_DEBUG(dbgs() << "ObjectSizeOffsetVisitor::compute() unhandled value: " << *V << '\n'); - return unknown(); + return ObjectSizeOffsetVisitor::unknown(); } bool ObjectSizeOffsetVisitor::CheckedZextOrTrunc(APInt &I) { return ::CheckedZextOrTrunc(I, IntTyBits); } -SizeOffsetType ObjectSizeOffsetVisitor::visitAllocaInst(AllocaInst &I) { +SizeOffsetAPInt ObjectSizeOffsetVisitor::visitAllocaInst(AllocaInst &I) { TypeSize ElemSize = DL.getTypeAllocSize(I.getAllocatedType()); if (ElemSize.isScalable() && Options.EvalMode != ObjectSizeOpts::Mode::Min) - return unknown(); + return ObjectSizeOffsetVisitor::unknown(); APInt Size(IntTyBits, ElemSize.getKnownMinValue()); if (!I.isArrayAllocation()) - return std::make_pair(align(Size, I.getAlign()), Zero); + return SizeOffsetAPInt(align(Size, I.getAlign()), Zero); Value *ArraySize = I.getArraySize(); if (const ConstantInt *C = dyn_cast(ArraySize)) { APInt NumElems = C->getValue(); if (!CheckedZextOrTrunc(NumElems)) - return unknown(); + return ObjectSizeOffsetVisitor::unknown(); bool Overflow; Size = Size.umul_ov(NumElems, Overflow); - return Overflow ? unknown() - : std::make_pair(align(Size, I.getAlign()), Zero); + return Overflow ? ObjectSizeOffsetVisitor::unknown() + : SizeOffsetAPInt(align(Size, I.getAlign()), Zero); } - return unknown(); + return ObjectSizeOffsetVisitor::unknown(); } -SizeOffsetType ObjectSizeOffsetVisitor::visitArgument(Argument &A) { +SizeOffsetAPInt ObjectSizeOffsetVisitor::visitArgument(Argument &A) { Type *MemoryTy = A.getPointeeInMemoryValueType(); // No interprocedural analysis is done at the moment. if (!MemoryTy|| !MemoryTy->isSized()) { ++ObjectVisitorArgument; - return unknown(); + return ObjectSizeOffsetVisitor::unknown(); } APInt Size(IntTyBits, DL.getTypeAllocSize(MemoryTy)); - return std::make_pair(align(Size, A.getParamAlign()), Zero); + return SizeOffsetAPInt(align(Size, A.getParamAlign()), Zero); } -SizeOffsetType ObjectSizeOffsetVisitor::visitCallBase(CallBase &CB) { +SizeOffsetAPInt ObjectSizeOffsetVisitor::visitCallBase(CallBase &CB) { if (std::optional Size = getAllocSize(&CB, TLI)) - return std::make_pair(*Size, Zero); - return unknown(); + return SizeOffsetAPInt(*Size, Zero); + return ObjectSizeOffsetVisitor::unknown(); } -SizeOffsetType -ObjectSizeOffsetVisitor::visitConstantPointerNull(ConstantPointerNull& CPN) { +SizeOffsetAPInt +ObjectSizeOffsetVisitor::visitConstantPointerNull(ConstantPointerNull &CPN) { // If null is unknown, there's nothing we can do. Additionally, non-zero // address spaces can make use of null, so we don't presume to know anything // about that. @@ -825,45 +827,46 @@ ObjectSizeOffsetVisitor::visitConstantPointerNull(ConstantPointerNull& CPN) { // them on the floor, but it's unclear what we should do when a NULL from // addrspace(1) gets casted to addrspace(0) (or vice-versa). if (Options.NullIsUnknownSize || CPN.getType()->getAddressSpace()) - return unknown(); - return std::make_pair(Zero, Zero); + return ObjectSizeOffsetVisitor::unknown(); + return SizeOffsetAPInt(Zero, Zero); } -SizeOffsetType -ObjectSizeOffsetVisitor::visitExtractElementInst(ExtractElementInst&) { - return unknown(); +SizeOffsetAPInt +ObjectSizeOffsetVisitor::visitExtractElementInst(ExtractElementInst &) { + return ObjectSizeOffsetVisitor::unknown(); } -SizeOffsetType -ObjectSizeOffsetVisitor::visitExtractValueInst(ExtractValueInst&) { +SizeOffsetAPInt +ObjectSizeOffsetVisitor::visitExtractValueInst(ExtractValueInst &) { // Easy cases were already folded by previous passes. - return unknown(); + return ObjectSizeOffsetVisitor::unknown(); } -SizeOffsetType ObjectSizeOffsetVisitor::visitGlobalAlias(GlobalAlias &GA) { +SizeOffsetAPInt ObjectSizeOffsetVisitor::visitGlobalAlias(GlobalAlias &GA) { if (GA.isInterposable()) - return unknown(); + return ObjectSizeOffsetVisitor::unknown(); return computeImpl(GA.getAliasee()); } -SizeOffsetType ObjectSizeOffsetVisitor::visitGlobalVariable(GlobalVariable &GV){ +SizeOffsetAPInt +ObjectSizeOffsetVisitor::visitGlobalVariable(GlobalVariable &GV) { if (!GV.getValueType()->isSized() || GV.hasExternalWeakLinkage() || ((!GV.hasInitializer() || GV.isInterposable()) && Options.EvalMode != ObjectSizeOpts::Mode::Min)) - return unknown(); + return ObjectSizeOffsetVisitor::unknown(); APInt Size(IntTyBits, DL.getTypeAllocSize(GV.getValueType())); - return std::make_pair(align(Size, GV.getAlign()), Zero); + return SizeOffsetAPInt(align(Size, GV.getAlign()), Zero); } -SizeOffsetType ObjectSizeOffsetVisitor::visitIntToPtrInst(IntToPtrInst&) { +SizeOffsetAPInt ObjectSizeOffsetVisitor::visitIntToPtrInst(IntToPtrInst &) { // clueless - return unknown(); + return ObjectSizeOffsetVisitor::unknown(); } -SizeOffsetType ObjectSizeOffsetVisitor::findLoadSizeOffset( +SizeOffsetAPInt ObjectSizeOffsetVisitor::findLoadSizeOffset( LoadInst &Load, BasicBlock &BB, BasicBlock::iterator From, - SmallDenseMap &VisitedBlocks, + SmallDenseMap &VisitedBlocks, unsigned &ScannedInstCount) { constexpr unsigned MaxInstsToScan = 128; @@ -871,10 +874,10 @@ SizeOffsetType ObjectSizeOffsetVisitor::findLoadSizeOffset( if (Where != VisitedBlocks.end()) return Where->second; - auto Unknown = [this, &BB, &VisitedBlocks]() { - return VisitedBlocks[&BB] = unknown(); + auto Unknown = [&BB, &VisitedBlocks]() { + return VisitedBlocks[&BB] = ObjectSizeOffsetVisitor::unknown(); }; - auto Known = [&BB, &VisitedBlocks](SizeOffsetType SO) { + auto Known = [&BB, &VisitedBlocks](SizeOffsetAPInt SO) { return VisitedBlocks[&BB] = SO; }; @@ -951,46 +954,47 @@ SizeOffsetType ObjectSizeOffsetVisitor::findLoadSizeOffset( return Unknown(); } while (From-- != BB.begin()); - SmallVector PredecessorSizeOffsets; + SmallVector PredecessorSizeOffsets; for (auto *PredBB : predecessors(&BB)) { PredecessorSizeOffsets.push_back(findLoadSizeOffset( Load, *PredBB, BasicBlock::iterator(PredBB->getTerminator()), VisitedBlocks, ScannedInstCount)); - if (!bothKnown(PredecessorSizeOffsets.back())) + if (!PredecessorSizeOffsets.back().bothKnown()) return Unknown(); } if (PredecessorSizeOffsets.empty()) return Unknown(); - return Known(std::accumulate(PredecessorSizeOffsets.begin() + 1, - PredecessorSizeOffsets.end(), - PredecessorSizeOffsets.front(), - [this](SizeOffsetType LHS, SizeOffsetType RHS) { - return combineSizeOffset(LHS, RHS); - })); + return Known(std::accumulate( + PredecessorSizeOffsets.begin() + 1, PredecessorSizeOffsets.end(), + PredecessorSizeOffsets.front(), + [this](SizeOffsetAPInt LHS, SizeOffsetAPInt RHS) { + return combineSizeOffset(LHS, RHS); + })); } -SizeOffsetType ObjectSizeOffsetVisitor::visitLoadInst(LoadInst &LI) { +SizeOffsetAPInt ObjectSizeOffsetVisitor::visitLoadInst(LoadInst &LI) { if (!Options.AA) { ++ObjectVisitorLoad; - return unknown(); + return ObjectSizeOffsetVisitor::unknown(); } - SmallDenseMap VisitedBlocks; + SmallDenseMap VisitedBlocks; unsigned ScannedInstCount = 0; - SizeOffsetType SO = + SizeOffsetAPInt SO = findLoadSizeOffset(LI, *LI.getParent(), BasicBlock::iterator(LI), VisitedBlocks, ScannedInstCount); - if (!bothKnown(SO)) + if (!SO.bothKnown()) ++ObjectVisitorLoad; return SO; } -SizeOffsetType ObjectSizeOffsetVisitor::combineSizeOffset(SizeOffsetType LHS, - SizeOffsetType RHS) { - if (!bothKnown(LHS) || !bothKnown(RHS)) - return unknown(); +SizeOffsetAPInt +ObjectSizeOffsetVisitor::combineSizeOffset(SizeOffsetAPInt LHS, + SizeOffsetAPInt RHS) { + if (!LHS.bothKnown() || !RHS.bothKnown()) + return ObjectSizeOffsetVisitor::unknown(); switch (Options.EvalMode) { case ObjectSizeOpts::Mode::Min: @@ -998,40 +1002,45 @@ SizeOffsetType ObjectSizeOffsetVisitor::combineSizeOffset(SizeOffsetType LHS, case ObjectSizeOpts::Mode::Max: return (getSizeWithOverflow(LHS).sgt(getSizeWithOverflow(RHS))) ? LHS : RHS; case ObjectSizeOpts::Mode::ExactSizeFromOffset: - return (getSizeWithOverflow(LHS).eq(getSizeWithOverflow(RHS))) ? LHS - : unknown(); + return (getSizeWithOverflow(LHS).eq(getSizeWithOverflow(RHS))) + ? LHS + : ObjectSizeOffsetVisitor::unknown(); case ObjectSizeOpts::Mode::ExactUnderlyingSizeAndOffset: - return LHS == RHS ? LHS : unknown(); + return LHS == RHS ? LHS : ObjectSizeOffsetVisitor::unknown(); } llvm_unreachable("missing an eval mode"); } -SizeOffsetType ObjectSizeOffsetVisitor::visitPHINode(PHINode &PN) { +SizeOffsetAPInt ObjectSizeOffsetVisitor::visitPHINode(PHINode &PN) { if (PN.getNumIncomingValues() == 0) - return unknown(); + return ObjectSizeOffsetVisitor::unknown(); auto IncomingValues = PN.incoming_values(); return std::accumulate(IncomingValues.begin() + 1, IncomingValues.end(), computeImpl(*IncomingValues.begin()), - [this](SizeOffsetType LHS, Value *VRHS) { + [this](SizeOffsetAPInt LHS, Value *VRHS) { return combineSizeOffset(LHS, computeImpl(VRHS)); }); } -SizeOffsetType ObjectSizeOffsetVisitor::visitSelectInst(SelectInst &I) { +SizeOffsetAPInt ObjectSizeOffsetVisitor::visitSelectInst(SelectInst &I) { return combineSizeOffset(computeImpl(I.getTrueValue()), computeImpl(I.getFalseValue())); } -SizeOffsetType ObjectSizeOffsetVisitor::visitUndefValue(UndefValue&) { - return std::make_pair(Zero, Zero); +SizeOffsetAPInt ObjectSizeOffsetVisitor::visitUndefValue(UndefValue &) { + return SizeOffsetAPInt(Zero, Zero); } -SizeOffsetType ObjectSizeOffsetVisitor::visitInstruction(Instruction &I) { +SizeOffsetAPInt ObjectSizeOffsetVisitor::visitInstruction(Instruction &I) { LLVM_DEBUG(dbgs() << "ObjectSizeOffsetVisitor unknown instruction:" << I << '\n'); - return unknown(); + return ObjectSizeOffsetVisitor::unknown(); } +// Just set these right here... +SizeOffsetValue::SizeOffsetValue(const SizeOffsetWeakTrackingVH &SOT) + : SizeOffsetType(SOT.Size, SOT.Offset) {} + ObjectSizeOffsetEvaluator::ObjectSizeOffsetEvaluator( const DataLayout &DL, const TargetLibraryInfo *TLI, LLVMContext &Context, ObjectSizeOpts EvalOpts) @@ -1044,21 +1053,21 @@ ObjectSizeOffsetEvaluator::ObjectSizeOffsetEvaluator( // be different for later objects. } -SizeOffsetEvalType ObjectSizeOffsetEvaluator::compute(Value *V) { +SizeOffsetValue ObjectSizeOffsetEvaluator::compute(Value *V) { // XXX - Are vectors of pointers possible here? IntTy = cast(DL.getIndexType(V->getType())); Zero = ConstantInt::get(IntTy, 0); - SizeOffsetEvalType Result = compute_(V); + SizeOffsetValue Result = compute_(V); - if (!bothKnown(Result)) { + if (!Result.bothKnown()) { // Erase everything that was computed in this iteration from the cache, so // that no dangling references are left behind. We could be a bit smarter if // we kept a dependency graph. It's probably not worth the complexity. for (const Value *SeenVal : SeenVals) { CacheMapTy::iterator CacheIt = CacheMap.find(SeenVal); // non-computable results can be safely cached - if (CacheIt != CacheMap.end() && anyKnown(CacheIt->second)) + if (CacheIt != CacheMap.end() && CacheIt->second.anyKnown()) CacheMap.erase(CacheIt); } @@ -1074,12 +1083,12 @@ SizeOffsetEvalType ObjectSizeOffsetEvaluator::compute(Value *V) { return Result; } -SizeOffsetEvalType ObjectSizeOffsetEvaluator::compute_(Value *V) { +SizeOffsetValue ObjectSizeOffsetEvaluator::compute_(Value *V) { ObjectSizeOffsetVisitor Visitor(DL, TLI, Context, EvalOpts); - SizeOffsetType Const = Visitor.compute(V); - if (Visitor.bothKnown(Const)) - return std::make_pair(ConstantInt::get(Context, Const.first), - ConstantInt::get(Context, Const.second)); + SizeOffsetAPInt Const = Visitor.compute(V); + if (Const.bothKnown()) + return SizeOffsetValue(ConstantInt::get(Context, Const.Size), + ConstantInt::get(Context, Const.Offset)); V = V->stripPointerCasts(); @@ -1095,13 +1104,13 @@ SizeOffsetEvalType ObjectSizeOffsetEvaluator::compute_(Value *V) { Builder.SetInsertPoint(I); // Now compute the size and offset. - SizeOffsetEvalType Result; + SizeOffsetValue Result; // Record the pointers that were handled in this run, so that they can be // cleaned later if something fails. We also use this set to break cycles that // can occur in dead code. if (!SeenVals.insert(V).second) { - Result = unknown(); + Result = ObjectSizeOffsetEvaluator::unknown(); } else if (GEPOperator *GEP = dyn_cast(V)) { Result = visitGEPOperator(*GEP); } else if (Instruction *I = dyn_cast(V)) { @@ -1112,22 +1121,22 @@ SizeOffsetEvalType ObjectSizeOffsetEvaluator::compute_(Value *V) { isa(V) || isa(V)) { // Ignore values where we cannot do more than ObjectSizeVisitor. - Result = unknown(); + Result = ObjectSizeOffsetEvaluator::unknown(); } else { LLVM_DEBUG( dbgs() << "ObjectSizeOffsetEvaluator::compute() unhandled value: " << *V << '\n'); - Result = unknown(); + Result = ObjectSizeOffsetEvaluator::unknown(); } // Don't reuse CacheIt since it may be invalid at this point. - CacheMap[V] = Result; + CacheMap[V] = SizeOffsetWeakTrackingVH(Result); return Result; } -SizeOffsetEvalType ObjectSizeOffsetEvaluator::visitAllocaInst(AllocaInst &I) { +SizeOffsetValue ObjectSizeOffsetEvaluator::visitAllocaInst(AllocaInst &I) { if (!I.getAllocatedType()->isSized()) - return unknown(); + return ObjectSizeOffsetEvaluator::unknown(); // must be a VLA assert(I.isArrayAllocation()); @@ -1143,86 +1152,85 @@ SizeOffsetEvalType ObjectSizeOffsetEvaluator::visitAllocaInst(AllocaInst &I) { Value *Size = ConstantInt::get(ArraySize->getType(), DL.getTypeAllocSize(I.getAllocatedType())); Size = Builder.CreateMul(Size, ArraySize); - return std::make_pair(Size, Zero); + return SizeOffsetValue(Size, Zero); } -SizeOffsetEvalType ObjectSizeOffsetEvaluator::visitCallBase(CallBase &CB) { +SizeOffsetValue ObjectSizeOffsetEvaluator::visitCallBase(CallBase &CB) { std::optional FnData = getAllocationSize(&CB, TLI); if (!FnData) - return unknown(); + return ObjectSizeOffsetEvaluator::unknown(); // Handle strdup-like functions separately. if (FnData->AllocTy == StrDupLike) { // TODO: implement evaluation of strdup/strndup - return unknown(); + return ObjectSizeOffsetEvaluator::unknown(); } Value *FirstArg = CB.getArgOperand(FnData->FstParam); FirstArg = Builder.CreateZExtOrTrunc(FirstArg, IntTy); if (FnData->SndParam < 0) - return std::make_pair(FirstArg, Zero); + return SizeOffsetValue(FirstArg, Zero); Value *SecondArg = CB.getArgOperand(FnData->SndParam); SecondArg = Builder.CreateZExtOrTrunc(SecondArg, IntTy); Value *Size = Builder.CreateMul(FirstArg, SecondArg); - return std::make_pair(Size, Zero); + return SizeOffsetValue(Size, Zero); } -SizeOffsetEvalType -ObjectSizeOffsetEvaluator::visitExtractElementInst(ExtractElementInst&) { - return unknown(); +SizeOffsetValue +ObjectSizeOffsetEvaluator::visitExtractElementInst(ExtractElementInst &) { + return ObjectSizeOffsetEvaluator::unknown(); } -SizeOffsetEvalType -ObjectSizeOffsetEvaluator::visitExtractValueInst(ExtractValueInst&) { - return unknown(); +SizeOffsetValue +ObjectSizeOffsetEvaluator::visitExtractValueInst(ExtractValueInst &) { + return ObjectSizeOffsetEvaluator::unknown(); } -SizeOffsetEvalType -ObjectSizeOffsetEvaluator::visitGEPOperator(GEPOperator &GEP) { - SizeOffsetEvalType PtrData = compute_(GEP.getPointerOperand()); - if (!bothKnown(PtrData)) - return unknown(); +SizeOffsetValue ObjectSizeOffsetEvaluator::visitGEPOperator(GEPOperator &GEP) { + SizeOffsetValue PtrData = compute_(GEP.getPointerOperand()); + if (!PtrData.bothKnown()) + return ObjectSizeOffsetEvaluator::unknown(); Value *Offset = emitGEPOffset(&Builder, DL, &GEP, /*NoAssumptions=*/true); - Offset = Builder.CreateAdd(PtrData.second, Offset); - return std::make_pair(PtrData.first, Offset); + Offset = Builder.CreateAdd(PtrData.Offset, Offset); + return SizeOffsetValue(PtrData.Size, Offset); } -SizeOffsetEvalType ObjectSizeOffsetEvaluator::visitIntToPtrInst(IntToPtrInst&) { +SizeOffsetValue ObjectSizeOffsetEvaluator::visitIntToPtrInst(IntToPtrInst &) { // clueless - return unknown(); + return ObjectSizeOffsetEvaluator::unknown(); } -SizeOffsetEvalType ObjectSizeOffsetEvaluator::visitLoadInst(LoadInst &LI) { - return unknown(); +SizeOffsetValue ObjectSizeOffsetEvaluator::visitLoadInst(LoadInst &LI) { + return ObjectSizeOffsetEvaluator::unknown(); } -SizeOffsetEvalType ObjectSizeOffsetEvaluator::visitPHINode(PHINode &PHI) { +SizeOffsetValue ObjectSizeOffsetEvaluator::visitPHINode(PHINode &PHI) { // Create 2 PHIs: one for size and another for offset. PHINode *SizePHI = Builder.CreatePHI(IntTy, PHI.getNumIncomingValues()); PHINode *OffsetPHI = Builder.CreatePHI(IntTy, PHI.getNumIncomingValues()); // Insert right away in the cache to handle recursive PHIs. - CacheMap[&PHI] = std::make_pair(SizePHI, OffsetPHI); + CacheMap[&PHI] = SizeOffsetWeakTrackingVH(SizePHI, OffsetPHI); // Compute offset/size for each PHI incoming pointer. for (unsigned i = 0, e = PHI.getNumIncomingValues(); i != e; ++i) { BasicBlock *IncomingBlock = PHI.getIncomingBlock(i); Builder.SetInsertPoint(IncomingBlock, IncomingBlock->getFirstInsertionPt()); - SizeOffsetEvalType EdgeData = compute_(PHI.getIncomingValue(i)); + SizeOffsetValue EdgeData = compute_(PHI.getIncomingValue(i)); - if (!bothKnown(EdgeData)) { + if (!EdgeData.bothKnown()) { OffsetPHI->replaceAllUsesWith(PoisonValue::get(IntTy)); OffsetPHI->eraseFromParent(); InsertedInstructions.erase(OffsetPHI); SizePHI->replaceAllUsesWith(PoisonValue::get(IntTy)); SizePHI->eraseFromParent(); InsertedInstructions.erase(SizePHI); - return unknown(); + return ObjectSizeOffsetEvaluator::unknown(); } - SizePHI->addIncoming(EdgeData.first, IncomingBlock); - OffsetPHI->addIncoming(EdgeData.second, IncomingBlock); + SizePHI->addIncoming(EdgeData.Size, IncomingBlock); + OffsetPHI->addIncoming(EdgeData.Offset, IncomingBlock); } Value *Size = SizePHI, *Offset = OffsetPHI; @@ -1238,27 +1246,27 @@ SizeOffsetEvalType ObjectSizeOffsetEvaluator::visitPHINode(PHINode &PHI) { OffsetPHI->eraseFromParent(); InsertedInstructions.erase(OffsetPHI); } - return std::make_pair(Size, Offset); + return SizeOffsetValue(Size, Offset); } -SizeOffsetEvalType ObjectSizeOffsetEvaluator::visitSelectInst(SelectInst &I) { - SizeOffsetEvalType TrueSide = compute_(I.getTrueValue()); - SizeOffsetEvalType FalseSide = compute_(I.getFalseValue()); +SizeOffsetValue ObjectSizeOffsetEvaluator::visitSelectInst(SelectInst &I) { + SizeOffsetValue TrueSide = compute_(I.getTrueValue()); + SizeOffsetValue FalseSide = compute_(I.getFalseValue()); - if (!bothKnown(TrueSide) || !bothKnown(FalseSide)) - return unknown(); + if (!TrueSide.bothKnown() || !FalseSide.bothKnown()) + return ObjectSizeOffsetEvaluator::unknown(); if (TrueSide == FalseSide) return TrueSide; - Value *Size = Builder.CreateSelect(I.getCondition(), TrueSide.first, - FalseSide.first); - Value *Offset = Builder.CreateSelect(I.getCondition(), TrueSide.second, - FalseSide.second); - return std::make_pair(Size, Offset); + Value *Size = + Builder.CreateSelect(I.getCondition(), TrueSide.Size, FalseSide.Size); + Value *Offset = + Builder.CreateSelect(I.getCondition(), TrueSide.Offset, FalseSide.Offset); + return SizeOffsetValue(Size, Offset); } -SizeOffsetEvalType ObjectSizeOffsetEvaluator::visitInstruction(Instruction &I) { +SizeOffsetValue ObjectSizeOffsetEvaluator::visitInstruction(Instruction &I) { LLVM_DEBUG(dbgs() << "ObjectSizeOffsetEvaluator unknown instruction:" << I << '\n'); - return unknown(); + return ObjectSizeOffsetEvaluator::unknown(); } diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp index b2618e35b0855..cc5a4ee8c2bdf 100644 --- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp +++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp @@ -6725,10 +6725,10 @@ struct AAHeapToStackFunction final : public AAHeapToStack { LLVMContext &Ctx = AI.CB->getContext(); ObjectSizeOpts Opts; ObjectSizeOffsetEvaluator Eval(DL, TLI, Ctx, Opts); - SizeOffsetEvalType SizeOffsetPair = Eval.compute(AI.CB); + SizeOffsetValue SizeOffsetPair = Eval.compute(AI.CB); assert(SizeOffsetPair != ObjectSizeOffsetEvaluator::unknown() && - cast(SizeOffsetPair.second)->isZero()); - Size = SizeOffsetPair.first; + cast(SizeOffsetPair.Offset)->isZero()); + Size = SizeOffsetPair.Size; } Instruction *IP = diff --git a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp index afb0e6cd1548b..5e1d8f0e51008 100644 --- a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -3629,10 +3629,14 @@ bool AddressSanitizer::isSafeAccess(ObjectSizeOffsetVisitor &ObjSizeVis, // TODO: We can use vscale_range to convert a scalable value to an // upper bound on the access size. return false; - SizeOffsetType SizeOffset = ObjSizeVis.compute(Addr); - if (!ObjSizeVis.bothKnown(SizeOffset)) return false; - uint64_t Size = SizeOffset.first.getZExtValue(); - int64_t Offset = SizeOffset.second.getSExtValue(); + + SizeOffsetAPInt SizeOffset = ObjSizeVis.compute(Addr); + if (!SizeOffset.bothKnown()) + return false; + + uint64_t Size = SizeOffset.Size.getZExtValue(); + int64_t Offset = SizeOffset.Offset.getSExtValue(); + // Three checks are required to ensure safety: // . Offset >= 0 (since the offset is given from the base ptr) // . Size >= Offset (unsigned) diff --git a/llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp b/llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp index ee5b819604170..cfa8ae26c6257 100644 --- a/llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp +++ b/llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp @@ -61,15 +61,15 @@ static Value *getBoundsCheckCond(Value *Ptr, Value *InstVal, LLVM_DEBUG(dbgs() << "Instrument " << *Ptr << " for " << Twine(NeededSize) << " bytes\n"); - SizeOffsetEvalType SizeOffset = ObjSizeEval.compute(Ptr); + SizeOffsetValue SizeOffset = ObjSizeEval.compute(Ptr); - if (!ObjSizeEval.bothKnown(SizeOffset)) { + if (!SizeOffset.bothKnown()) { ++ChecksUnable; return nullptr; } - Value *Size = SizeOffset.first; - Value *Offset = SizeOffset.second; + Value *Size = SizeOffset.Size; + Value *Offset = SizeOffset.Offset; ConstantInt *SizeCI = dyn_cast(Size); Type *IndexTy = DL.getIndexType(Ptr->getType());