https://github.com/c-rhodes updated 
https://github.com/llvm/llvm-project/pull/176437

>From aba17bb896b75b2a64753b937599b44eb76678a9 Mon Sep 17 00:00:00 2001
From: Marc Auberer <[email protected]>
Date: Fri, 16 Jan 2026 17:46:52 +0100
Subject: [PATCH] [IR] Use alloc markers for operator delete variants (#138261)

Follow-up to https://github.com/llvm/llvm-project/pull/129914
This fixes the problem properly by using the data via the allocation
markers.

PS: Sorry for the long delay ;)
(cherry picked from commit 72d5925412522d01e48f8d6027e51c2dead11617)
---
 llvm/include/llvm/Analysis/MemorySSA.h |  6 ++--
 llvm/include/llvm/IR/Constants.h       |  4 +--
 llvm/include/llvm/IR/GlobalAlias.h     |  2 +-
 llvm/include/llvm/IR/GlobalIFunc.h     |  2 +-
 llvm/include/llvm/IR/GlobalVariable.h  |  2 +-
 llvm/include/llvm/IR/InstrTypes.h      |  6 ++--
 llvm/include/llvm/IR/Instructions.h    | 26 +++++++++-------
 llvm/include/llvm/IR/User.h            | 42 +++++---------------------
 llvm/lib/IR/ConstantsContext.h         | 12 +++++---
 llvm/lib/IR/User.cpp                   | 25 +++++++++++++--
 10 files changed, 64 insertions(+), 63 deletions(-)

diff --git a/llvm/include/llvm/Analysis/MemorySSA.h 
b/llvm/include/llvm/Analysis/MemorySSA.h
index 07d39ab3e10a9..ab44bc09d9550 100644
--- a/llvm/include/llvm/Analysis/MemorySSA.h
+++ b/llvm/include/llvm/Analysis/MemorySSA.h
@@ -318,7 +318,7 @@ class MemoryUse final : public MemoryUseOrDef {
 
   // allocate space for exactly one operand
   void *operator new(size_t S) { return User::operator new(S, AllocMarker); }
-  void operator delete(void *Ptr) { User::operator delete(Ptr); }
+  void operator delete(void *Ptr) { User::operator delete(Ptr, AllocMarker); }
 
   static bool classof(const Value *MA) {
     return MA->getValueID() == MemoryUseVal;
@@ -383,7 +383,7 @@ class MemoryDef final : public MemoryUseOrDef {
 
   // allocate space for exactly two operands
   void *operator new(size_t S) { return User::operator new(S, AllocMarker); }
-  void operator delete(void *Ptr) { User::operator delete(Ptr); }
+  void operator delete(void *Ptr) { User::operator delete(Ptr, AllocMarker); }
 
   static bool classof(const Value *MA) {
     return MA->getValueID() == MemoryDefVal;
@@ -483,7 +483,7 @@ class MemoryPhi final : public MemoryAccess {
   void *operator new(size_t S) { return User::operator new(S, AllocMarker); }
 
 public:
-  void operator delete(void *Ptr) { User::operator delete(Ptr); }
+  void operator delete(void *Ptr) { User::operator delete(Ptr, AllocMarker); }
 
   /// Provide fast operand accessors
   DECLARE_TRANSPARENT_OPERAND_ACCESSORS(MemoryAccess);
diff --git a/llvm/include/llvm/IR/Constants.h b/llvm/include/llvm/IR/Constants.h
index 3bb2fa28cced8..6bf990c69e19f 100644
--- a/llvm/include/llvm/IR/Constants.h
+++ b/llvm/include/llvm/IR/Constants.h
@@ -917,7 +917,7 @@ class BlockAddress final : public Constant {
   Value *handleOperandChangeImpl(Value *From, Value *To);
 
 public:
-  void operator delete(void *Ptr) { User::operator delete(Ptr); }
+  void operator delete(void *Ptr) { User::operator delete(Ptr, AllocMarker); }
 
   /// Return a BlockAddress for the specified function and basic block.
   LLVM_ABI static BlockAddress *get(Function *F, BasicBlock *BB);
@@ -970,7 +970,7 @@ class DSOLocalEquivalent final : public Constant {
   Value *handleOperandChangeImpl(Value *From, Value *To);
 
 public:
-  void operator delete(void *Ptr) { User::operator delete(Ptr); }
+  void operator delete(void *Ptr) { User::operator delete(Ptr, AllocMarker); }
 
   /// Return a DSOLocalEquivalent for the specified global value.
   LLVM_ABI static DSOLocalEquivalent *get(GlobalValue *GV);
diff --git a/llvm/include/llvm/IR/GlobalAlias.h 
b/llvm/include/llvm/IR/GlobalAlias.h
index 12b9f053abb17..c0a6c3d69374c 100644
--- a/llvm/include/llvm/IR/GlobalAlias.h
+++ b/llvm/include/llvm/IR/GlobalAlias.h
@@ -63,7 +63,7 @@ class GlobalAlias : public GlobalValue, public 
ilist_node<GlobalAlias> {
 
   // allocate space for exactly one operand
   void *operator new(size_t S) { return User::operator new(S, AllocMarker); }
-  void operator delete(void *Ptr) { User::operator delete(Ptr); }
+  void operator delete(void *Ptr) { User::operator delete(Ptr, AllocMarker); }
 
   /// Provide fast operand accessors
   DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Constant);
diff --git a/llvm/include/llvm/IR/GlobalIFunc.h 
b/llvm/include/llvm/IR/GlobalIFunc.h
index d93146aa016be..853b3fe250cc9 100644
--- a/llvm/include/llvm/IR/GlobalIFunc.h
+++ b/llvm/include/llvm/IR/GlobalIFunc.h
@@ -52,7 +52,7 @@ class GlobalIFunc final : public GlobalObject, public 
ilist_node<GlobalIFunc> {
 
   // allocate space for exactly one operand
   void *operator new(size_t S) { return User::operator new(S, AllocMarker); }
-  void operator delete(void *Ptr) { User::operator delete(Ptr); }
+  void operator delete(void *Ptr) { User::operator delete(Ptr, AllocMarker); }
 
   /// Provide fast operand accessors
   DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Constant);
diff --git a/llvm/include/llvm/IR/GlobalVariable.h 
b/llvm/include/llvm/IR/GlobalVariable.h
index d1d42cebc1352..8e6af8ae6e203 100644
--- a/llvm/include/llvm/IR/GlobalVariable.h
+++ b/llvm/include/llvm/IR/GlobalVariable.h
@@ -100,7 +100,7 @@ class GlobalVariable : public GlobalObject, public 
ilist_node<GlobalVariable> {
   void *operator new(size_t s) { return User::operator new(s, AllocMarker); }
 
   // delete space for exactly one operand as created in the corresponding new 
operator
-  void operator delete(void *ptr) { User::operator delete(ptr); }
+  void operator delete(void *ptr) { User::operator delete(ptr, AllocMarker); }
 
   /// Provide fast operand accessors
   DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value);
diff --git a/llvm/include/llvm/IR/InstrTypes.h 
b/llvm/include/llvm/IR/InstrTypes.h
index 9f56779a9b935..55cc26d1e9c8f 100644
--- a/llvm/include/llvm/IR/InstrTypes.h
+++ b/llvm/include/llvm/IR/InstrTypes.h
@@ -68,7 +68,7 @@ class UnaryInstruction : public Instruction {
 public:
   // allocate space for exactly one operand
   void *operator new(size_t S) { return User::operator new(S, AllocMarker); }
-  void operator delete(void *Ptr) { User::operator delete(Ptr); }
+  void operator delete(void *Ptr) { User::operator delete(Ptr, AllocMarker); }
 
   /// Transparently provide more efficient getOperand methods.
   DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value);
@@ -185,7 +185,7 @@ class BinaryOperator : public Instruction {
 public:
   // allocate space for exactly two operands
   void *operator new(size_t S) { return User::operator new(S, AllocMarker); }
-  void operator delete(void *Ptr) { User::operator delete(Ptr); }
+  void operator delete(void *Ptr) { User::operator delete(Ptr, AllocMarker); }
 
   /// Transparently provide more efficient getOperand methods.
   DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value);
@@ -734,7 +734,7 @@ class CmpInst : public Instruction {
 public:
   // allocate space for exactly two operands
   void *operator new(size_t S) { return User::operator new(S, AllocMarker); }
-  void operator delete(void *Ptr) { User::operator delete(Ptr); }
+  void operator delete(void *Ptr) { User::operator delete(Ptr, AllocMarker); }
 
   /// Construct a compare instruction, given the opcode, the predicate and
   /// the two operands.  Optionally (if InstBefore is specified) insert the
diff --git a/llvm/include/llvm/IR/Instructions.h 
b/llvm/include/llvm/IR/Instructions.h
index dbcaa6459eea9..d4ea74c05ae62 100644
--- a/llvm/include/llvm/IR/Instructions.h
+++ b/llvm/include/llvm/IR/Instructions.h
@@ -325,7 +325,7 @@ class StoreInst : public Instruction {
 
   // allocate space for exactly two operands
   void *operator new(size_t S) { return User::operator new(S, AllocMarker); }
-  void operator delete(void *Ptr) { User::operator delete(Ptr); }
+  void operator delete(void *Ptr) { User::operator delete(Ptr, AllocMarker); }
 
   /// Return true if this is a store to a volatile memory location.
   bool isVolatile() const { return getSubclassData<VolatileField>(); }
@@ -449,7 +449,7 @@ class FenceInst : public Instruction {
 
   // allocate space for exactly zero operands
   void *operator new(size_t S) { return User::operator new(S, AllocMarker); }
-  void operator delete(void *Ptr) { User::operator delete(Ptr); }
+  void operator delete(void *Ptr) { User::operator delete(Ptr, AllocMarker); }
 
   /// Returns the ordering constraint of this fence instruction.
   AtomicOrdering getOrdering() const {
@@ -530,7 +530,7 @@ class AtomicCmpXchgInst : public Instruction {
 
   // allocate space for exactly three operands
   void *operator new(size_t S) { return User::operator new(S, AllocMarker); }
-  void operator delete(void *Ptr) { User::operator delete(Ptr); }
+  void operator delete(void *Ptr) { User::operator delete(Ptr, AllocMarker); }
 
   using VolatileField = BoolBitfieldElementT<0>;
   using WeakField = BoolBitfieldElementT<VolatileField::NextBit>;
@@ -806,7 +806,7 @@ class AtomicRMWInst : public Instruction {
 
   // allocate space for exactly two operands
   void *operator new(size_t S) { return User::operator new(S, AllocMarker); }
-  void operator delete(void *Ptr) { User::operator delete(Ptr); }
+  void operator delete(void *Ptr) { User::operator delete(Ptr, AllocMarker); }
 
   using VolatileField = BoolBitfieldElementT<0>;
   using AtomicOrderingField =
@@ -1958,7 +1958,9 @@ class ShuffleVectorInst : public Instruction {
                              InsertPosition InsertBefore = nullptr);
 
   void *operator new(size_t S) { return User::operator new(S, AllocMarker); }
-  void operator delete(void *Ptr) { return User::operator delete(Ptr); }
+  void operator delete(void *Ptr) {
+    return User::operator delete(Ptr, AllocMarker);
+  }
 
   /// Swap the operands and adjust the mask to preserve the semantics
   /// of the instruction.
@@ -2553,7 +2555,7 @@ class InsertValueInst : public Instruction {
 public:
   // allocate space for exactly two operands
   void *operator new(size_t S) { return User::operator new(S, AllocMarker); }
-  void operator delete(void *Ptr) { User::operator delete(Ptr); }
+  void operator delete(void *Ptr) { User::operator delete(Ptr, AllocMarker); }
 
   static InsertValueInst *Create(Value *Agg, Value *Val,
                                  ArrayRef<unsigned> Idxs,
@@ -2906,7 +2908,7 @@ class LandingPadInst : public Instruction {
   LLVM_ABI LandingPadInst *cloneImpl() const;
 
 public:
-  void operator delete(void *Ptr) { User::operator delete(Ptr); }
+  void operator delete(void *Ptr) { User::operator delete(Ptr, AllocMarker); }
 
   /// Constructors - NumReservedClauses is a hint for the number of incoming
   /// clauses that this landingpad will have (use 0 if you really have no 
idea).
@@ -3233,7 +3235,7 @@ class SwitchInst : public Instruction {
   }
 
 public:
-  void operator delete(void *Ptr) { User::operator delete(Ptr); }
+  void operator delete(void *Ptr) { User::operator delete(Ptr, AllocMarker); }
 
   // -2
   static const unsigned DefaultPseudoIndex = static_cast<unsigned>(~0L-1);
@@ -3623,7 +3625,7 @@ class IndirectBrInst : public Instruction {
   LLVM_ABI IndirectBrInst *cloneImpl() const;
 
 public:
-  void operator delete(void *Ptr) { User::operator delete(Ptr); }
+  void operator delete(void *Ptr) { User::operator delete(Ptr, AllocMarker); }
 
   /// Iterator type that casts an operand to a basic block.
   ///
@@ -4145,7 +4147,9 @@ class CatchSwitchInst : public Instruction {
   LLVM_ABI CatchSwitchInst *cloneImpl() const;
 
 public:
-  void operator delete(void *Ptr) { return User::operator delete(Ptr); }
+  void operator delete(void *Ptr) {
+    return User::operator delete(Ptr, AllocMarker);
+  }
 
   static CatchSwitchInst *Create(Value *ParentPad, BasicBlock *UnwindDest,
                                  unsigned NumHandlers,
@@ -4532,7 +4536,7 @@ class UnreachableInst : public Instruction {
 
   // allocate space for exactly zero operands
   void *operator new(size_t S) { return User::operator new(S, AllocMarker); }
-  void operator delete(void *Ptr) { User::operator delete(Ptr); }
+  void operator delete(void *Ptr) { User::operator delete(Ptr, AllocMarker); }
 
   unsigned getNumSuccessors() const { return 0; }
 
diff --git a/llvm/include/llvm/IR/User.h b/llvm/include/llvm/IR/User.h
index da886a508a3e8..1d83cfef06c6a 100644
--- a/llvm/include/llvm/IR/User.h
+++ b/llvm/include/llvm/IR/User.h
@@ -128,6 +128,10 @@ class User : public Value {
     // null.
     assert((!AllocInfo.HasHungOffUses || !getOperandList()) &&
            "Error in initializing hung off uses for User");
+
+    Use *Operands = reinterpret_cast<Use *>(this) - NumUserOperands;
+    for (unsigned I = 0; I < NumUserOperands; ++I)
+      new (&Operands[I]) Use(this);
   }
 
   /// Allocate the array of Uses, followed by a pointer
@@ -150,42 +154,12 @@ class User : public Value {
   /// Free memory allocated for User and Use objects.
   LLVM_ABI void operator delete(void *Usr);
   /// Placement delete - required by std, called if the ctor throws.
-  void operator delete(void *Usr, HungOffOperandsAllocMarker) {
-    // Note: If a subclass manipulates the information which is required to
-    // calculate the Usr memory pointer, e.g. NumUserOperands, the operator
-    // delete of that subclass has to restore the changed information to the
-    // original value, since the dtor of that class is not called if the ctor
-    // fails.
-    User::operator delete(Usr);
-
-#ifndef LLVM_ENABLE_EXCEPTIONS
-    llvm_unreachable("Constructor throws?");
-#endif
-  }
+  LLVM_ABI void operator delete(void *Usr, HungOffOperandsAllocMarker);
   /// Placement delete - required by std, called if the ctor throws.
-  void operator delete(void *Usr, IntrusiveOperandsAllocMarker) {
-    // Note: If a subclass manipulates the information which is required to 
calculate the
-    // Usr memory pointer, e.g. NumUserOperands, the operator delete of that 
subclass has
-    // to restore the changed information to the original value, since the 
dtor of that class
-    // is not called if the ctor fails.
-    User::operator delete(Usr);
-
-#ifndef LLVM_ENABLE_EXCEPTIONS
-    llvm_unreachable("Constructor throws?");
-#endif
-  }
+  LLVM_ABI void operator delete(void *Usr,
+                                IntrusiveOperandsAndDescriptorAllocMarker);
   /// Placement delete - required by std, called if the ctor throws.
-  void operator delete(void *Usr, IntrusiveOperandsAndDescriptorAllocMarker) {
-    // Note: If a subclass manipulates the information which is required to 
calculate the
-    // Usr memory pointer, e.g. NumUserOperands, the operator delete of that 
subclass has
-    // to restore the changed information to the original value, since the 
dtor of that class
-    // is not called if the ctor fails.
-    User::operator delete(Usr);
-
-#ifndef LLVM_ENABLE_EXCEPTIONS
-    llvm_unreachable("Constructor throws?");
-#endif
-  }
+  LLVM_ABI void operator delete(void *Usr, IntrusiveOperandsAllocMarker 
Marker);
 
 protected:
   template <int Idx, typename U> static Use &OpFrom(const U *that) {
diff --git a/llvm/lib/IR/ConstantsContext.h b/llvm/lib/IR/ConstantsContext.h
index 2073e0d42d8e3..cc9bad431787c 100644
--- a/llvm/lib/IR/ConstantsContext.h
+++ b/llvm/lib/IR/ConstantsContext.h
@@ -54,7 +54,7 @@ class CastConstantExpr final : public ConstantExpr {
 
   // allocate space for exactly one operand
   void *operator new(size_t S) { return User::operator new(S, AllocMarker); }
-  void operator delete(void *Ptr) { User::operator delete(Ptr); }
+  void operator delete(void *Ptr) { User::operator delete(Ptr, AllocMarker); }
 
   DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value);
 
@@ -82,7 +82,7 @@ class BinaryConstantExpr final : public ConstantExpr {
 
   // allocate space for exactly two operands
   void *operator new(size_t S) { return User::operator new(S, AllocMarker); }
-  void operator delete(void *Ptr) { User::operator delete(Ptr); }
+  void operator delete(void *Ptr) { User::operator delete(Ptr, AllocMarker); }
 
   /// Transparently provide more efficient getOperand methods.
   DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value);
@@ -111,7 +111,7 @@ class ExtractElementConstantExpr final : public 
ConstantExpr {
 
   // allocate space for exactly two operands
   void *operator new(size_t S) { return User::operator new(S, AllocMarker); }
-  void operator delete(void *Ptr) { User::operator delete(Ptr); }
+  void operator delete(void *Ptr) { User::operator delete(Ptr, AllocMarker); }
 
   /// Transparently provide more efficient getOperand methods.
   DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value);
@@ -140,7 +140,7 @@ class InsertElementConstantExpr final : public ConstantExpr 
{
 
   // allocate space for exactly three operands
   void *operator new(size_t S) { return User::operator new(S, AllocMarker); }
-  void operator delete(void *Ptr) { User::operator delete(Ptr); }
+  void operator delete(void *Ptr) { User::operator delete(Ptr, AllocMarker); }
 
   /// Transparently provide more efficient getOperand methods.
   DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value);
@@ -178,7 +178,9 @@ class ShuffleVectorConstantExpr final : public ConstantExpr 
{
   Constant *ShuffleMaskForBitcode;
 
   void *operator new(size_t S) { return User::operator new(S, AllocMarker); }
-  void operator delete(void *Ptr) { return User::operator delete(Ptr); }
+  void operator delete(void *Ptr) {
+    return User::operator delete(Ptr, AllocMarker);
+  }
 
   /// Transparently provide more efficient getOperand methods.
   DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value);
diff --git a/llvm/lib/IR/User.cpp b/llvm/lib/IR/User.cpp
index e97a07fe5e7a2..4acfba6766a5d 100644
--- a/llvm/lib/IR/User.cpp
+++ b/llvm/lib/IR/User.cpp
@@ -158,8 +158,6 @@ void *User::allocateFixedOperandUser(size_t Size, unsigned 
Us,
   Obj->NumUserOperands = Us;
   Obj->HasHungOffUses = false;
   Obj->HasDescriptor = DescBytes != 0;
-  for (unsigned I = 0; I < Us; ++I)
-    new (&Operands[I]) Use(Obj);
 
   if (DescBytes != 0) {
     auto *DescInfo = reinterpret_cast<DescriptorInfo *>(Operands) - 1;
@@ -234,3 +232,26 @@ User::~User() {
 }
 
 void User::operator delete(void *Usr) { ::operator delete(((void **)Usr)[-1]); 
}
+
+void User::operator delete(void *Usr, HungOffOperandsAllocMarker) {
+  Use **HungOffOperandList = static_cast<Use **>(Usr) - 1;
+  ::operator delete(HungOffOperandList);
+}
+
+void User::operator delete(void *Usr,
+                           IntrusiveOperandsAndDescriptorAllocMarker Marker) {
+  unsigned NumOps = Marker.NumOps;
+  Use *UseBegin = static_cast<Use *>(Usr) - NumOps;
+  auto *DI = reinterpret_cast<DescriptorInfo *>(UseBegin) - 1;
+  uint8_t *Storage = reinterpret_cast<uint8_t *>(DI) - DI->SizeInBytes;
+  ::operator delete(Storage);
+}
+
+void User::operator delete(void *Usr, IntrusiveOperandsAllocMarker Marker) {
+  unsigned NumOps = Marker.NumOps;
+  size_t LeadingSize = sizeof(Use) * NumOps;
+  // Handle the edge case where there are no operands and no descriptor.
+  LeadingSize = std::max(LeadingSize, sizeof(void *));
+  uint8_t *Storage = static_cast<uint8_t *>(Usr) - LeadingSize;
+  ::operator delete(Storage);
+}

_______________________________________________
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits

Reply via email to