diff --git a/llvm/include/llvm/Analysis/MemoryBuiltins.h b/llvm/include/llvm/Analysis/MemoryBuiltins.h index 0f0605e4f01b2..1b509fb66ce37 100644 --- a/llvm/include/llvm/Analysis/MemoryBuiltins.h +++ b/llvm/include/llvm/Analysis/MemoryBuiltins.h @@ -181,6 +181,14 @@ LLVM_ABI bool getObjectSize(const Value *Ptr, uint64_t &Size, const DataLayout &DL, const TargetLibraryInfo *TLI, ObjectSizeOpts Opts = {}); +/// Like getObjectSize(), but only returns the size of base objects (like +/// allocas, global variables and allocator calls) and std::nullopt otherwise. +/// Requires ExactSizeFromOffset mode. +LLVM_ABI std::optional getBaseObjectSize(const Value *Ptr, + const DataLayout &DL, + const TargetLibraryInfo *TLI, + ObjectSizeOpts Opts = {}); + /// Try to turn a call to \@llvm.objectsize into an integer value of the given /// Type. Returns null on failure. If MustSucceed is true, this function will /// not return null, and may return conservative values governed by the second diff --git a/llvm/lib/Analysis/BasicAliasAnalysis.cpp b/llvm/lib/Analysis/BasicAliasAnalysis.cpp index 86a2edbd8bd41..a8e2f221e2cbb 100644 --- a/llvm/lib/Analysis/BasicAliasAnalysis.cpp +++ b/llvm/lib/Analysis/BasicAliasAnalysis.cpp @@ -103,12 +103,15 @@ static std::optional getObjectSize(const Value *V, const TargetLibraryInfo &TLI, bool NullIsValidLoc, bool RoundToAlign = false) { - uint64_t Size; ObjectSizeOpts Opts; Opts.RoundToAlign = RoundToAlign; Opts.NullIsUnknownSize = NullIsValidLoc; - if (getObjectSize(V, Size, DL, &TLI, Opts)) - return TypeSize::getFixed(Size); + if (std::optional Size = getBaseObjectSize(V, DL, &TLI, Opts)) { + // FIXME: Remove this check, only exists to preserve previous behavior. + if (Size->isScalable()) + return std::nullopt; + return Size; + } return std::nullopt; } diff --git a/llvm/lib/Analysis/MemoryBuiltins.cpp b/llvm/lib/Analysis/MemoryBuiltins.cpp index e0b7f65d18a30..1df4eda2580df 100644 --- a/llvm/lib/Analysis/MemoryBuiltins.cpp +++ b/llvm/lib/Analysis/MemoryBuiltins.cpp @@ -589,6 +589,59 @@ bool llvm::getObjectSize(const Value *Ptr, uint64_t &Size, const DataLayout &DL, return true; } +std::optional llvm::getBaseObjectSize(const Value *Ptr, + const DataLayout &DL, + const TargetLibraryInfo *TLI, + ObjectSizeOpts Opts) { + assert(Opts.EvalMode == ObjectSizeOpts::Mode::ExactSizeFromOffset && + "Other modes are currently not supported"); + + auto Align = [&](TypeSize Size, MaybeAlign Alignment) { + if (Opts.RoundToAlign && Alignment && !Size.isScalable()) + return TypeSize::getFixed(alignTo(Size.getFixedValue(), *Alignment)); + return Size; + }; + + if (isa(Ptr)) + return TypeSize::getZero(); + + if (isa(Ptr)) { + if (Opts.NullIsUnknownSize || Ptr->getType()->getPointerAddressSpace()) + return std::nullopt; + return TypeSize::getZero(); + } + + if (auto *GV = dyn_cast(Ptr)) { + if (!GV->getValueType()->isSized() || GV->hasExternalWeakLinkage() || + !GV->hasInitializer() || GV->isInterposable()) + return std::nullopt; + return Align(DL.getTypeAllocSize(GV->getValueType()), GV->getAlign()); + } + + if (auto *A = dyn_cast(Ptr)) { + Type *MemoryTy = A->getPointeeInMemoryValueType(); + if (!MemoryTy || !MemoryTy->isSized()) + return std::nullopt; + return Align(DL.getTypeAllocSize(MemoryTy), A->getParamAlign()); + } + + if (auto *AI = dyn_cast(Ptr)) { + if (std::optional Size = AI->getAllocationSize(DL)) + return Align(*Size, AI->getAlign()); + return std::nullopt; + } + + if (auto *CB = dyn_cast(Ptr)) { + if (std::optional Size = getAllocSize(CB, TLI)) { + if (std::optional ZExtSize = Size->tryZExtValue()) + return TypeSize::getFixed(*ZExtSize); + } + return std::nullopt; + } + + return std::nullopt; +} + Value *llvm::lowerObjectSizeCall(IntrinsicInst *ObjectSize, const DataLayout &DL, const TargetLibraryInfo *TLI,