[llvm] [VPlan] Add poisoning value handle for VPValue. (NFCI) (PR #185054)

Florian Hahn via llvm-commits llvm-commits at lists.llvm.org
Tue Mar 10 06:40:56 PDT 2026


================
@@ -427,6 +430,140 @@ class VPDef {
   unsigned getNumDefinedValues() const { return DefinedValues.size(); }
 };
 
+/// Value handle that poisons itself when the referenced VPValue is deleted,
+/// catching dangling pointer bugs (e.g. stale DenseMap keys). Only
+/// VPRecipeValues with a retrievable VPlan are tracked; other VPValue types
+/// work but are not poisoned. Does *not* follow RAUW.
+class LLVM_ABI_FOR_TEST PoisoningVPValueHandle {
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS && !defined(NDEBUG)
+  const VPValue *VP = nullptr;
+  const VPlan *Plan = nullptr;
+  bool Poisoned = false;
+  PoisoningVPValueHandle *Next = nullptr;
+
+  /// Returns true if \p V is not null and not a DenseMap sentinel.
+  static bool isValid(const VPValue *V) {
+    return V && V != DenseMapInfo<const VPValue *>::getEmptyKey() &&
+           V != DenseMapInfo<const VPValue *>::getTombstoneKey();
+  }
+
+  /// Return the VPlan owning \p V, or nullptr if not available.
+  static const VPlan *getVPlan(const VPValue *V);
+
+  const VPValue *getRawValPtr() const { return VP; }
+  void setRawValPtr(const VPValue *P) {
+    if (isValid(VP) && !Poisoned)
+      removeFromList();
+    VP = P;
+    Poisoned = false;
+    Plan = nullptr;
+    if (isValid(VP))
+      addToList();
+  }
+
+  void addToList();
+  void removeFromList();
+
+  friend struct DenseMapInfo<PoisoningVPValueHandle>;
+#else
+  const VPValue *VP = nullptr;
+
+  const VPValue *getRawValPtr() const { return VP; }
+  void setRawValPtr(const VPValue *P) { VP = P; }
+#endif
+
+  const VPValue *getValPtr() const {
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS && !defined(NDEBUG)
+    assert(!Poisoned && "Accessed a poisoned VPValue handle!");
+#endif
+    return VP;
+  }
+
+public:
+  PoisoningVPValueHandle() = default;
+  PoisoningVPValueHandle(const VPValue *V) : VP(V) {
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS && !defined(NDEBUG)
+    if (isValid(VP))
+      addToList();
+#endif
+  }
+
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS && !defined(NDEBUG)
+  PoisoningVPValueHandle(const PoisoningVPValueHandle &RHS)
+      : VP(RHS.VP), Poisoned(RHS.Poisoned) {
+    if (isValid(VP) && !Poisoned)
+      addToList();
+  }
+
+  ~PoisoningVPValueHandle() {
+    if (isValid(VP) && !Poisoned)
+      removeFromList();
+  }
+
+  PoisoningVPValueHandle &operator=(const PoisoningVPValueHandle &RHS) {
+    if (this == &RHS)
+      return *this;
+    if (isValid(VP) && !Poisoned)
+      removeFromList();
+    VP = RHS.VP;
+    Poisoned = RHS.Poisoned;
+    if (isValid(VP) && !Poisoned)
+      addToList();
+    return *this;
+  }
+#endif
+
+  operator const VPValue *() const { return getValPtr(); }
+  const VPValue *operator->() const { return getValPtr(); }
+  const VPValue &operator*() const { return *getValPtr(); }
+
+  static void poisonAll(const VPlan *Plan, const VPValue *V);
+};
+
+template <> struct DenseMapInfo<PoisoningVPValueHandle> {
+  static inline PoisoningVPValueHandle getEmptyKey() {
+    PoisoningVPValueHandle Res;
+    Res.setRawValPtr(DenseMapInfo<const VPValue *>::getEmptyKey());
+    return Res;
----------------
fhahn wrote:

Yep that works, updated, thanks! Same for below

https://github.com/llvm/llvm-project/pull/185054


More information about the llvm-commits mailing list