Skip to content

Commit a987022

Browse files
authored
[MemoryBuiltins] Add getBaseObjectSize() (NFCI) (#155911)
getObjectSize() is based on ObjectSizeOffsetVisitor, which has become very expensive over time. The implementation is geared towards computing as-good-as-possible results for the objectsize intrinsics and similar. However, we also use it in BasicAA, which is very hot, and really only cares about the base cases like alloca/malloc/global, not any of the analysis for GEPs, phis, or loads. Add a new getBaseObjectSize() API for this use case, which only handles the non-recursive cases. As a bonus, this API can easily return a TypeSize and thus support scalable vectors. For now, I'm explicitly discarding the scalable sizes in BasicAA just to avoid unnecessary behavior changes during this refactor.
1 parent af41d0d commit a987022

File tree

3 files changed

+67
-3
lines changed

3 files changed

+67
-3
lines changed

llvm/include/llvm/Analysis/MemoryBuiltins.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,14 @@ LLVM_ABI bool getObjectSize(const Value *Ptr, uint64_t &Size,
181181
const DataLayout &DL, const TargetLibraryInfo *TLI,
182182
ObjectSizeOpts Opts = {});
183183

184+
/// Like getObjectSize(), but only returns the size of base objects (like
185+
/// allocas, global variables and allocator calls) and std::nullopt otherwise.
186+
/// Requires ExactSizeFromOffset mode.
187+
LLVM_ABI std::optional<TypeSize> getBaseObjectSize(const Value *Ptr,
188+
const DataLayout &DL,
189+
const TargetLibraryInfo *TLI,
190+
ObjectSizeOpts Opts = {});
191+
184192
/// Try to turn a call to \@llvm.objectsize into an integer value of the given
185193
/// Type. Returns null on failure. If MustSucceed is true, this function will
186194
/// not return null, and may return conservative values governed by the second

llvm/lib/Analysis/BasicAliasAnalysis.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,12 +103,15 @@ static std::optional<TypeSize> getObjectSize(const Value *V,
103103
const TargetLibraryInfo &TLI,
104104
bool NullIsValidLoc,
105105
bool RoundToAlign = false) {
106-
uint64_t Size;
107106
ObjectSizeOpts Opts;
108107
Opts.RoundToAlign = RoundToAlign;
109108
Opts.NullIsUnknownSize = NullIsValidLoc;
110-
if (getObjectSize(V, Size, DL, &TLI, Opts))
111-
return TypeSize::getFixed(Size);
109+
if (std::optional<TypeSize> Size = getBaseObjectSize(V, DL, &TLI, Opts)) {
110+
// FIXME: Remove this check, only exists to preserve previous behavior.
111+
if (Size->isScalable())
112+
return std::nullopt;
113+
return Size;
114+
}
112115
return std::nullopt;
113116
}
114117

llvm/lib/Analysis/MemoryBuiltins.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,59 @@ bool llvm::getObjectSize(const Value *Ptr, uint64_t &Size, const DataLayout &DL,
589589
return true;
590590
}
591591

592+
std::optional<TypeSize> llvm::getBaseObjectSize(const Value *Ptr,
593+
const DataLayout &DL,
594+
const TargetLibraryInfo *TLI,
595+
ObjectSizeOpts Opts) {
596+
assert(Opts.EvalMode == ObjectSizeOpts::Mode::ExactSizeFromOffset &&
597+
"Other modes are currently not supported");
598+
599+
auto Align = [&](TypeSize Size, MaybeAlign Alignment) {
600+
if (Opts.RoundToAlign && Alignment && !Size.isScalable())
601+
return TypeSize::getFixed(alignTo(Size.getFixedValue(), *Alignment));
602+
return Size;
603+
};
604+
605+
if (isa<UndefValue>(Ptr))
606+
return TypeSize::getZero();
607+
608+
if (isa<ConstantPointerNull>(Ptr)) {
609+
if (Opts.NullIsUnknownSize || Ptr->getType()->getPointerAddressSpace())
610+
return std::nullopt;
611+
return TypeSize::getZero();
612+
}
613+
614+
if (auto *GV = dyn_cast<GlobalVariable>(Ptr)) {
615+
if (!GV->getValueType()->isSized() || GV->hasExternalWeakLinkage() ||
616+
!GV->hasInitializer() || GV->isInterposable())
617+
return std::nullopt;
618+
return Align(DL.getTypeAllocSize(GV->getValueType()), GV->getAlign());
619+
}
620+
621+
if (auto *A = dyn_cast<Argument>(Ptr)) {
622+
Type *MemoryTy = A->getPointeeInMemoryValueType();
623+
if (!MemoryTy || !MemoryTy->isSized())
624+
return std::nullopt;
625+
return Align(DL.getTypeAllocSize(MemoryTy), A->getParamAlign());
626+
}
627+
628+
if (auto *AI = dyn_cast<AllocaInst>(Ptr)) {
629+
if (std::optional<TypeSize> Size = AI->getAllocationSize(DL))
630+
return Align(*Size, AI->getAlign());
631+
return std::nullopt;
632+
}
633+
634+
if (auto *CB = dyn_cast<CallBase>(Ptr)) {
635+
if (std::optional<APInt> Size = getAllocSize(CB, TLI)) {
636+
if (std::optional<uint64_t> ZExtSize = Size->tryZExtValue())
637+
return TypeSize::getFixed(*ZExtSize);
638+
}
639+
return std::nullopt;
640+
}
641+
642+
return std::nullopt;
643+
}
644+
592645
Value *llvm::lowerObjectSizeCall(IntrinsicInst *ObjectSize,
593646
const DataLayout &DL,
594647
const TargetLibraryInfo *TLI,

0 commit comments

Comments
 (0)