[llvm] [libc] [mlir] [clang] [lldb] [NFC][ObjectSizeOffset] Use classes instead of std::pair (PR #76882)

Bill Wendling via cfe-commits cfe-commits at lists.llvm.org
Wed Jan 3 17:46:04 PST 2024


https://github.com/bwendling updated https://github.com/llvm/llvm-project/pull/76882

>From ca7a96a40952fe94b916dacc52f07aa90bbdb1e7 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Wed, 3 Jan 2024 13:22:37 -0800
Subject: [PATCH 1/4] [builtin_object_size] Use classes instead of std::pair
 (NFC)

The use of std::pair makes the values it holds opaque. Using classes
improves this while keeping the POD aspect of a std::pair. As a nice
addition, the "known" functions held inappropriately in the Visitor
classes can now properly reside in the value classes. :-)
---
 llvm/include/llvm/Analysis/MemoryBuiltins.h   | 192 +++++++----
 llvm/lib/Analysis/MemoryBuiltins.cpp          | 314 +++++++++---------
 .../Transforms/IPO/AttributorAttributes.cpp   |   8 +-
 .../Instrumentation/AddressSanitizer.cpp      |  12 +-
 .../Instrumentation/BoundsChecking.cpp        |   8 +-
 5 files changed, 299 insertions(+), 235 deletions(-)

diff --git a/llvm/include/llvm/Analysis/MemoryBuiltins.h b/llvm/include/llvm/Analysis/MemoryBuiltins.h
index 827b5081b2ce75..56faa32fb0b226 100644
--- a/llvm/include/llvm/Analysis/MemoryBuiltins.h
+++ b/llvm/include/llvm/Analysis/MemoryBuiltins.h
@@ -187,80 +187,146 @@ Value *lowerObjectSizeCall(
     const TargetLibraryInfo *TLI, AAResults *AA, bool MustSucceed,
     SmallVectorImpl<Instruction *> *InsertedInstructions = nullptr);
 
-using SizeOffsetType = std::pair<APInt, APInt>;
+/// 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 <typename T> struct SizeOffsetType {
+  T Size;
+  T Offset;
+
+  bool knownSize() const;
+  bool knownOffset() const;
+  bool anyKnown() const;
+  bool bothKnown() const;
+};
+
+/// SizeOffsetType<APInt> - Used by \p ObjectSizeOffsetVisitor, which works
+/// with \p APInts.
+template <> struct SizeOffsetType<APInt> {
+  APInt Size;
+  APInt Offset;
+
+  SizeOffsetType() = default;
+  SizeOffsetType(APInt Size, APInt Offset) : Size(Size), Offset(Offset) {}
+
+  bool knownSize() const { return Size.getBitWidth() > 1; }
+  bool knownOffset() const { return Offset.getBitWidth() > 1; }
+  bool anyKnown() const { return knownSize() || knownOffset(); }
+  bool bothKnown() const { return knownSize() && knownOffset(); }
+
+  bool operator==(const SizeOffsetType<APInt> &RHS) {
+    return Size == RHS.Size && Offset == RHS.Offset;
+  }
+  bool operator!=(const SizeOffsetType<APInt> &RHS) { return !(*this == RHS); }
+};
+using SizeOffsetAPInt = SizeOffsetType<APInt>;
 
 /// 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<ObjectSizeOffsetVisitor, SizeOffsetType> {
+    : public InstVisitor<ObjectSizeOffsetVisitor, SizeOffsetAPInt> {
   const DataLayout &DL;
   const TargetLibraryInfo *TLI;
   ObjectSizeOpts Options;
   unsigned IntTyBits;
   APInt Zero;
-  SmallDenseMap<Instruction *, SizeOffsetType, 8> SeenInsts;
+  SmallDenseMap<Instruction *, SizeOffsetAPInt, 8> SeenInsts;
   unsigned InstructionsVisited;
 
   APInt align(APInt Size, MaybeAlign Align);
 
-  SizeOffsetType unknown() {
-    return std::make_pair(APInt(), APInt());
-  }
+  static SizeOffsetAPInt unknown;
 
 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<BasicBlock *, SizeOffsetType, 8> &VisitedBlocks,
+      SmallDenseMap<BasicBlock *, SizeOffsetAPInt, 8> &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<Value *, Value *>;
+template <> struct SizeOffsetType<WeakTrackingVH>;
+
+/// SizeOffsetType<Value *> - Used by \p ObjectSizeOffsetEvaluator, which works
+/// with \p Values.
+template <> struct SizeOffsetType<Value *> {
+  Value *Size;
+  Value *Offset;
+
+  SizeOffsetType() = default;
+  SizeOffsetType(Value *Size, Value *Offset) : Size(Size), Offset(Offset) {}
+  SizeOffsetType(SizeOffsetType<WeakTrackingVH> &SOT);
+
+  bool knownSize() const { return Size != nullptr; }
+  bool knownOffset() const { return Offset != nullptr; }
+  bool anyKnown() const { return knownSize() || knownOffset(); }
+  bool bothKnown() const { return knownSize() && knownOffset(); }
+
+  bool operator==(const SizeOffsetType<Value *> &RHS) {
+    return Size == RHS.Size && Offset == RHS.Offset;
+  }
+  bool operator!=(const SizeOffsetType<Value *> &RHS) {
+    return !(*this == RHS);
+  }
+};
+using SizeOffsetValue = SizeOffsetType<Value *>;
+
+/// SizeOffsetType<WeakTrackingVH> - Used by \p ObjectSizeOffsetEvaluator in a
+/// \p DenseMap.
+template <> struct SizeOffsetType<WeakTrackingVH> {
+  WeakTrackingVH Size;
+  WeakTrackingVH Offset;
+
+  SizeOffsetType() = default;
+  SizeOffsetType(Value *Size, Value *Offset) : Size(Size), Offset(Offset) {}
+
+  bool knownSize() const { return Size.pointsToAliveValue(); }
+  bool knownOffset() const { return Offset.pointsToAliveValue(); }
+  bool anyKnown() const { return knownSize() || knownOffset(); }
+  bool bothKnown() const { return knownSize() && knownOffset(); }
+
+  bool operator==(const SizeOffsetType<Value *> &RHS) {
+    return (Value *)Size == (Value *)RHS.Size &&
+           (Value *)Offset == (Value *)RHS.Offset;
+  }
+  bool operator!=(const SizeOffsetType<Value *> &RHS) {
+    return !(*this == RHS);
+  }
+};
+using SizeOffsetWeakTrackingVH = SizeOffsetType<WeakTrackingVH>;
 
 /// 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<ObjectSizeOffsetEvaluator, SizeOffsetEvalType> {
+    : public InstVisitor<ObjectSizeOffsetEvaluator, SizeOffsetValue> {
   using BuilderTy = IRBuilder<TargetFolder, IRBuilderCallbackInserter>;
-  using WeakEvalType = std::pair<WeakTrackingVH, WeakTrackingVH>;
+  using WeakEvalType = SizeOffsetType<WeakTrackingVH>;
   using CacheMapTy = DenseMap<const Value *, WeakEvalType>;
   using PtrSetTy = SmallPtrSet<const Value *, 8>;
 
@@ -275,45 +341,27 @@ class ObjectSizeOffsetEvaluator
   ObjectSizeOpts EvalOpts;
   SmallPtrSet<Instruction *, 8> 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);
+  static SizeOffsetValue unknown;
 
-  bool knownSize(SizeOffsetEvalType SizeOffset) {
-    return SizeOffset.first;
-  }
-
-  bool knownOffset(SizeOffsetEvalType SizeOffset) {
-    return SizeOffset.second;
-  }
-
-  bool anyKnown(SizeOffsetEvalType SizeOffset) {
-    return knownSize(SizeOffset) || knownOffset(SizeOffset);
-  }
-
-  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 9e6811f3bf8815..8cc2d070d1d8e7 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(Size))
+    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<Value*>(Ptr));
-  if (!Visitor.bothKnown(Data))
+  SizeOffsetAPInt Data = Visitor.compute(const_cast<Value *>(Ptr));
+  if (!Data.bothKnown())
     return false;
 
   Size = getSizeWithOverflow(Data).getZExtValue();
@@ -640,10 +642,9 @@ 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()) {
+    if (SizeOffsetPair != ObjectSizeOffsetEvaluator::unknown) {
       IRBuilder<TargetFolder, IRBuilderCallbackInserter> Builder(
           Ctx, TargetFolder(DL), IRBuilderCallbackInserter([&](Instruction *I) {
             if (InsertedInstructions)
@@ -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<Constant>(SizeOffsetPair.first) ||
-          !isa<Constant>(SizeOffsetPair.second))
+      if (!isa<Constant>(Size) || !isa<Constant>(Offset))
         Builder.CreateAssumption(
             Builder.CreateICmpNE(Ret, ConstantInt::get(ResultType, -1)));
 
@@ -682,6 +683,8 @@ STATISTIC(ObjectVisitorArgument,
 STATISTIC(ObjectVisitorLoad,
           "Number of load instructions with unsolved size and offset");
 
+SizeOffsetAPInt ObjectSizeOffsetVisitor::unknown;
+
 APInt ObjectSizeOffsetVisitor::align(APInt Size, MaybeAlign Alignment) {
   if (Options.RoundToAlign && Alignment)
     return APInt(IntTyBits, alignTo(Size.getZExtValue(), *Alignment));
@@ -697,12 +700,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 +722,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 +732,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<Instruction>(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 +772,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<ConstantInt>(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<APInt> 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 +829,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<BasicBlock *, SizeOffsetType, 8> &VisitedBlocks,
+    SmallDenseMap<BasicBlock *, SizeOffsetAPInt, 8> &VisitedBlocks,
     unsigned &ScannedInstCount) {
   constexpr unsigned MaxInstsToScan = 128;
 
@@ -871,10 +876,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 +956,47 @@ SizeOffsetType ObjectSizeOffsetVisitor::findLoadSizeOffset(
     return Unknown();
   } while (From-- != BB.begin());
 
-  SmallVector<SizeOffsetType> PredecessorSizeOffsets;
+  SmallVector<SizeOffsetAPInt> 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<BasicBlock *, SizeOffsetType, 8> VisitedBlocks;
+  SmallDenseMap<BasicBlock *, SizeOffsetAPInt, 8> 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 +1004,47 @@ 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::SizeOffsetType(SizeOffsetWeakTrackingVH &SOT)
+    : Size((Value *)SOT.Size), Offset((Value *)SOT.Offset) {}
+
+SizeOffsetValue ObjectSizeOffsetEvaluator::unknown;
+
 ObjectSizeOffsetEvaluator::ObjectSizeOffsetEvaluator(
     const DataLayout &DL, const TargetLibraryInfo *TLI, LLVMContext &Context,
     ObjectSizeOpts EvalOpts)
@@ -1044,21 +1057,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<IntegerType>(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 +1087,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 +1108,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<GEPOperator>(V)) {
     Result = visitGEPOperator(*GEP);
   } else if (Instruction *I = dyn_cast<Instruction>(V)) {
@@ -1112,22 +1125,22 @@ SizeOffsetEvalType ObjectSizeOffsetEvaluator::compute_(Value *V) {
              isa<GlobalAlias>(V) ||
              isa<GlobalVariable>(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.Size, Result.Offset);
   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 +1156,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<AllocFnsTy> 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 +1250,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 b2618e35b08552..b4d83ef728bd12 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);
-        assert(SizeOffsetPair != ObjectSizeOffsetEvaluator::unknown() &&
-               cast<ConstantInt>(SizeOffsetPair.second)->isZero());
-        Size = SizeOffsetPair.first;
+        SizeOffsetValue SizeOffsetPair = Eval.compute(AI.CB);
+        assert(SizeOffsetPair != ObjectSizeOffsetEvaluator::unknown &&
+               cast<ConstantInt>(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 afb0e6cd1548b0..5e1d8f0e51008d 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 ee5b819604170e..cfa8ae26c62572 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<ConstantInt>(Size);
 
   Type *IndexTy = DL.getIndexType(Ptr->getType());

>From 68900ef913c47991ed4761b2917a5d4f08d81dd7 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Wed, 3 Jan 2024 16:19:16 -0800
Subject: [PATCH 2/4] Use correct value.

---
 llvm/lib/Analysis/MemoryBuiltins.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Analysis/MemoryBuiltins.cpp b/llvm/lib/Analysis/MemoryBuiltins.cpp
index 8cc2d070d1d8e7..47ac5446c3142b 100644
--- a/llvm/lib/Analysis/MemoryBuiltins.cpp
+++ b/llvm/lib/Analysis/MemoryBuiltins.cpp
@@ -580,7 +580,7 @@ Value *llvm::getFreedOperand(const CallBase *CB, const TargetLibraryInfo *TLI) {
 static APInt getSizeWithOverflow(const SizeOffsetAPInt &Data) {
   APInt Size = Data.Size;
   APInt Offset = Data.Offset;
-  if (Offset.isNegative() || Size.ult(Size))
+  if (Offset.isNegative() || Size.ult(Offset))
     return APInt(Size.getBitWidth(), 0);
   return Size - Offset;
 }

>From 2a235d3a6254f5c880b35c77159d547881fc1e92 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Wed, 3 Jan 2024 16:22:03 -0800
Subject: [PATCH 3/4] Add helpful c'tor.

---
 llvm/include/llvm/Analysis/MemoryBuiltins.h | 1 +
 llvm/lib/Analysis/MemoryBuiltins.cpp        | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/llvm/include/llvm/Analysis/MemoryBuiltins.h b/llvm/include/llvm/Analysis/MemoryBuiltins.h
index 56faa32fb0b226..aff5a29445ef70 100644
--- a/llvm/include/llvm/Analysis/MemoryBuiltins.h
+++ b/llvm/include/llvm/Analysis/MemoryBuiltins.h
@@ -305,6 +305,7 @@ template <> struct SizeOffsetType<WeakTrackingVH> {
 
   SizeOffsetType() = default;
   SizeOffsetType(Value *Size, Value *Offset) : Size(Size), Offset(Offset) {}
+  SizeOffsetType(SizeOffsetValue &SOT) : Size(SOT.Size), Offset(SOT.Offset) {}
 
   bool knownSize() const { return Size.pointsToAliveValue(); }
   bool knownOffset() const { return Offset.pointsToAliveValue(); }
diff --git a/llvm/lib/Analysis/MemoryBuiltins.cpp b/llvm/lib/Analysis/MemoryBuiltins.cpp
index 47ac5446c3142b..ac8005df29d14e 100644
--- a/llvm/lib/Analysis/MemoryBuiltins.cpp
+++ b/llvm/lib/Analysis/MemoryBuiltins.cpp
@@ -1134,7 +1134,7 @@ SizeOffsetValue ObjectSizeOffsetEvaluator::compute_(Value *V) {
   }
 
   // Don't reuse CacheIt since it may be invalid at this point.
-  CacheMap[V] = SizeOffsetWeakTrackingVH(Result.Size, Result.Offset);
+  CacheMap[V] = SizeOffsetWeakTrackingVH(Result);
   return Result;
 }
 

>From 278faa86119ed25214534951a9ccd078e4b69f1f Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Wed, 3 Jan 2024 17:45:48 -0800
Subject: [PATCH 4/4] Move common functions and items into the base class. Use
 inheritance instead of specialization.

---
 llvm/include/llvm/Analysis/MemoryBuiltins.h | 96 ++++++++-------------
 llvm/lib/Analysis/MemoryBuiltins.cpp        |  4 +-
 2 files changed, 37 insertions(+), 63 deletions(-)

diff --git a/llvm/include/llvm/Analysis/MemoryBuiltins.h b/llvm/include/llvm/Analysis/MemoryBuiltins.h
index aff5a29445ef70..10a98739377d24 100644
--- a/llvm/include/llvm/Analysis/MemoryBuiltins.h
+++ b/llvm/include/llvm/Analysis/MemoryBuiltins.h
@@ -190,36 +190,36 @@ Value *lowerObjectSizeCall(
 /// 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 <typename T> struct SizeOffsetType {
+template <typename T>
+struct SizeOffsetType {
   T Size;
   T Offset;
 
-  bool knownSize() const;
-  bool knownOffset() const;
-  bool anyKnown() const;
-  bool bothKnown() const;
-};
-
-/// SizeOffsetType<APInt> - Used by \p ObjectSizeOffsetVisitor, which works
-/// with \p APInts.
-template <> struct SizeOffsetType<APInt> {
-  APInt Size;
-  APInt Offset;
-
   SizeOffsetType() = default;
-  SizeOffsetType(APInt Size, APInt Offset) : Size(Size), Offset(Offset) {}
+  SizeOffsetType(T Size, T Offset) : Size(Size), Offset(Offset) {}
 
-  bool knownSize() const { return Size.getBitWidth() > 1; }
-  bool knownOffset() const { return Offset.getBitWidth() > 1; }
+  bool knownSize() const { return false; }
+  bool knownOffset() const { return false; }
   bool anyKnown() const { return knownSize() || knownOffset(); }
   bool bothKnown() const { return knownSize() && knownOffset(); }
 
-  bool operator==(const SizeOffsetType<APInt> &RHS) {
-    return Size == RHS.Size && Offset == RHS.Offset;
+  bool operator==(const SizeOffsetType<T> &RHS) const {
+    return (T)Size == (T)RHS.Size && (T)Offset == (T)RHS.Offset;
+  }
+  bool operator!=(const SizeOffsetType<T> &RHS) const {
+    return !(*this == RHS);
   }
-  bool operator!=(const SizeOffsetType<APInt> &RHS) { return !(*this == RHS); }
 };
-using SizeOffsetAPInt = SizeOffsetType<APInt>;
+
+/// SizeOffsetAPInt - Used by \p ObjectSizeOffsetVisitor, which works with
+/// \p APInts.
+struct SizeOffsetAPInt : public SizeOffsetType<APInt> {
+  SizeOffsetAPInt() = default;
+  SizeOffsetAPInt(APInt Size, APInt Offset) : SizeOffsetType(Size, Offset) {}
+
+  bool knownSize() const { return Size.getBitWidth() > 1; }
+  bool knownOffset() const { return Offset.getBitWidth() > 1; }
+};
 
 /// 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.
@@ -271,63 +271,37 @@ class ObjectSizeOffsetVisitor
   bool CheckedZextOrTrunc(APInt &I);
 };
 
-template <> struct SizeOffsetType<WeakTrackingVH>;
-
-/// SizeOffsetType<Value *> - Used by \p ObjectSizeOffsetEvaluator, which works
-/// with \p Values.
-template <> struct SizeOffsetType<Value *> {
-  Value *Size;
-  Value *Offset;
-
-  SizeOffsetType() = default;
-  SizeOffsetType(Value *Size, Value *Offset) : Size(Size), Offset(Offset) {}
-  SizeOffsetType(SizeOffsetType<WeakTrackingVH> &SOT);
+/// SizeOffsetValue - Used by \p ObjectSizeOffsetEvaluator, which works with
+/// \p Values.
+struct SizeOffsetWeakTrackingVH;
+struct SizeOffsetValue : public SizeOffsetType<Value *> {
+  SizeOffsetValue() = default;
+  SizeOffsetValue(Value *Size, Value *Offset) : SizeOffsetType(Size, Offset) {}
+  SizeOffsetValue(const SizeOffsetWeakTrackingVH &SOT);
 
   bool knownSize() const { return Size != nullptr; }
   bool knownOffset() const { return Offset != nullptr; }
-  bool anyKnown() const { return knownSize() || knownOffset(); }
-  bool bothKnown() const { return knownSize() && knownOffset(); }
-
-  bool operator==(const SizeOffsetType<Value *> &RHS) {
-    return Size == RHS.Size && Offset == RHS.Offset;
-  }
-  bool operator!=(const SizeOffsetType<Value *> &RHS) {
-    return !(*this == RHS);
-  }
 };
-using SizeOffsetValue = SizeOffsetType<Value *>;
 
-/// SizeOffsetType<WeakTrackingVH> - Used by \p ObjectSizeOffsetEvaluator in a
+/// SizeOffsetWeakTrackingVH - Used by \p ObjectSizeOffsetEvaluator in a
 /// \p DenseMap.
-template <> struct SizeOffsetType<WeakTrackingVH> {
-  WeakTrackingVH Size;
-  WeakTrackingVH Offset;
-
-  SizeOffsetType() = default;
-  SizeOffsetType(Value *Size, Value *Offset) : Size(Size), Offset(Offset) {}
-  SizeOffsetType(SizeOffsetValue &SOT) : Size(SOT.Size), Offset(SOT.Offset) {}
+struct SizeOffsetWeakTrackingVH : public SizeOffsetType<WeakTrackingVH> {
+  SizeOffsetWeakTrackingVH() = default;
+  SizeOffsetWeakTrackingVH(Value *Size, Value *Offset)
+      : SizeOffsetType(Size, Offset) {}
+  SizeOffsetWeakTrackingVH(const SizeOffsetValue &SOV)
+      : SizeOffsetType(SOV.Size, SOV.Offset) {}
 
   bool knownSize() const { return Size.pointsToAliveValue(); }
   bool knownOffset() const { return Offset.pointsToAliveValue(); }
-  bool anyKnown() const { return knownSize() || knownOffset(); }
-  bool bothKnown() const { return knownSize() && knownOffset(); }
-
-  bool operator==(const SizeOffsetType<Value *> &RHS) {
-    return (Value *)Size == (Value *)RHS.Size &&
-           (Value *)Offset == (Value *)RHS.Offset;
-  }
-  bool operator!=(const SizeOffsetType<Value *> &RHS) {
-    return !(*this == RHS);
-  }
 };
-using SizeOffsetWeakTrackingVH = SizeOffsetType<WeakTrackingVH>;
 
 /// 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<ObjectSizeOffsetEvaluator, SizeOffsetValue> {
   using BuilderTy = IRBuilder<TargetFolder, IRBuilderCallbackInserter>;
-  using WeakEvalType = SizeOffsetType<WeakTrackingVH>;
+  using WeakEvalType = SizeOffsetWeakTrackingVH;
   using CacheMapTy = DenseMap<const Value *, WeakEvalType>;
   using PtrSetTy = SmallPtrSet<const Value *, 8>;
 
diff --git a/llvm/lib/Analysis/MemoryBuiltins.cpp b/llvm/lib/Analysis/MemoryBuiltins.cpp
index ac8005df29d14e..e03f5c0977127f 100644
--- a/llvm/lib/Analysis/MemoryBuiltins.cpp
+++ b/llvm/lib/Analysis/MemoryBuiltins.cpp
@@ -1040,8 +1040,8 @@ SizeOffsetAPInt ObjectSizeOffsetVisitor::visitInstruction(Instruction &I) {
 }
 
 // Just set these right here...
-SizeOffsetValue::SizeOffsetType(SizeOffsetWeakTrackingVH &SOT)
-    : Size((Value *)SOT.Size), Offset((Value *)SOT.Offset) {}
+SizeOffsetValue::SizeOffsetValue(const SizeOffsetWeakTrackingVH &SOT)
+    : SizeOffsetType((Value *)SOT.Size, (Value *)SOT.Offset) {}
 
 SizeOffsetValue ObjectSizeOffsetEvaluator::unknown;
 



More information about the cfe-commits mailing list