[llvm] [TySan] Support the new size-aware TBAA metadata format (PR #226568)

via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 25 11:56:03 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-compiler-rt-sanitizer

Author: Ofek (OfekShilon)

<details>
<summary>Changes</summary>

Fixes #<!-- -->226169

TypeSanitizer only understands the old TBAA type-node layout, where the type name is the first operand. Under `-new-struct-path-tbaa` the first operand is the parent type node and the name moves to operand 2, so `generateBaseTypeDescriptor()` fails to find a name and returns false. Its
caller then abandons instrumentation for the whole function:

```c++
if (!generateTypeDescriptor(MD, TypeDescriptors, TypeNames, M))
  return Res; // Giving up.
```
So -fsanitize=type combined with -new-struct-path-tbaa silently produces no instrumentation at all — no `__tysan_check` calls, no `__tysan_v1_*` descriptors — with no diagnostic, and every type-aliasing violation goes undetected. This affects plain scalar accesses as well as structs, leaving
TySan entirely non-functional in that mode.

Commit 1: "[IR][NFC] Share the TBAA metadata node readers"
The `!tbaa` layout was directly coded in four places: the node wrappers in TypeBasedAliasAnalysis.cpp, the structural checks in Verifier.cpp, createMutableTBAAAccessTag() in MDBuilder.cpp, and TypeSanitizer.cpp. This commit moves TBAANodeImpl, TBAAStructTagNodeImpl, TBAAStructTypeNode and
isNewFormatTypeNode out of the anonymous namespace in TypeBasedAliasAnalysis.cpp into a new header, llvm/IR/TBAAMetadata.h, next to the MDBuilder methods that create these nodes, and uses them from
Verifier.cpp and MDBuilder.cpp.

isNewFormatTypeNode() now tolerates a null node and a null first operand, making it a superset of the copy it replaces in Verifier.cpp.
TBAAStructTypeNode::getFieldOffset() is new; field offsets were previously only reachable through getField()'s offset-walking logic.
Verifier.cpp deliberately keeps its own field-list walk. Its job is to reject malformed metadata, so it cannot use accessors that assume the invariants it exists to check; only the format predicate is shared.
createMutableTBAAAccessTag() had no test coverage anywhere in the tree, and
the immutability flag it looks up sits at a different operand in each format,
so a unit test for the four tag shapes is added alongside.

No functional change intended.

Commit 2 — "[TySan] Support the new size-aware TBAA metadata format"
TySan is the fourth site that directly used `!tbaa` layout, and wasn't addressed in commit 1 because
this isn't NFC: reading through the shared accessors is precisely what teaches it the second layout.

In the old layout a scalar type node's parent occupies the first field slot, so walking the field list covers scalars and structs alike. The new layout keeps the parent in its own operand and gives a scalar no fields at all, so `collectTypeMembers()` has to contribute it explicitly as member 0 — the runtime depends on this, as `getRootTD()` follows `Members[0]` to find the root of the TBAA tree.



---

Patch is 47.74 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/226568.diff


7 Files Affected:

- (added) llvm/include/llvm/IR/TBAAMetadata.h (+279) 
- (modified) llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp (+1-233) 
- (modified) llvm/lib/IR/MDBuilder.cpp (+10-18) 
- (modified) llvm/lib/IR/Verifier.cpp (+2-10) 
- (modified) llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp (+51-21) 
- (added) llvm/test/Instrumentation/TypeSanitizer/new-struct-path-tbaa.ll (+265) 
- (modified) llvm/unittests/IR/MDBuilderTest.cpp (+33) 


``````````diff
diff --git a/llvm/include/llvm/IR/TBAAMetadata.h b/llvm/include/llvm/IR/TBAAMetadata.h
new file mode 100644
index 0000000000000..2ca9341923fa4
--- /dev/null
+++ b/llvm/include/llvm/IR/TBAAMetadata.h
@@ -0,0 +1,279 @@
+//===- TBAAMetadata.h - Type-Based Alias Analysis metadata ------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file
+/// Readers for the !tbaa metadata format described in LangRef.
+///
+/// TBAA metadata exists in two formats, and the operand layout differs between
+/// them:
+///
+///   old scalar:     { name, parent, offset }
+///   old struct:     { name, field, offset, field, offset, ... }
+///   old access tag: { base type, access type, offset }
+///
+///   new scalar:     { parent, size, name }
+///   new struct:     { parent, size, name, field, offset, size, ... }
+///   new access tag: { base type, access type, offset, size }
+///
+/// These wrappers hide that difference so that producers and consumers of TBAA
+/// metadata do not each have to open-code the operand indices. The nodes
+/// themselves are created by the createTBAA*() methods of MDBuilder.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_IR_TBAAMETADATA_H
+#define LLVM_IR_TBAAMETADATA_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/Metadata.h"
+#include "llvm/Support/Casting.h"
+#include <cstdint>
+
+namespace llvm {
+
+/// isNewFormatTypeNode - Return true iff the given type node is in the new
+/// size-aware format.
+inline bool isNewFormatTypeNode(const MDNode *N) {
+  if (!N || N->getNumOperands() < 3)
+    return false;
+  // In the new format type nodes have a reference to the parent type as their
+  // first operand; in the old format the first operand is the name string.
+  return isa_and_nonnull<MDNode>(N->getOperand(0));
+}
+
+/// This is a simple wrapper around an MDNode which provides a higher-level
+/// interface by hiding the details of how alias analysis information is encoded
+/// in its operands.
+template<typename MDNodeTy>
+class TBAANodeImpl {
+  MDNodeTy *Node = nullptr;
+
+public:
+  TBAANodeImpl() = default;
+  explicit TBAANodeImpl(MDNodeTy *N) : Node(N) {}
+
+  /// getNode - Get the MDNode for this TBAANode.
+  MDNodeTy *getNode() const { return Node; }
+
+  /// isNewFormat - Return true iff the wrapped type node is in the new
+  /// size-aware format.
+  bool isNewFormat() const { return isNewFormatTypeNode(Node); }
+
+  /// getParent - Get this TBAANode's Alias tree parent.
+  TBAANodeImpl<MDNodeTy> getParent() const {
+    if (isNewFormat())
+      return TBAANodeImpl(cast<MDNodeTy>(Node->getOperand(0)));
+
+    if (Node->getNumOperands() < 2)
+      return TBAANodeImpl<MDNodeTy>();
+    MDNodeTy *P = dyn_cast_or_null<MDNodeTy>(Node->getOperand(1));
+    if (!P)
+      return TBAANodeImpl<MDNodeTy>();
+    // Ok, this node has a valid parent. Return it.
+    return TBAANodeImpl<MDNodeTy>(P);
+  }
+
+  /// Test if this TBAANode represents a type for objects which are
+  /// not modified (by any means) in the context where this
+  /// AliasAnalysis is relevant.
+  bool isTypeImmutable() const {
+    if (Node->getNumOperands() < 3)
+      return false;
+    ConstantInt *CI = mdconst::dyn_extract<ConstantInt>(Node->getOperand(2));
+    if (!CI)
+      return false;
+    return CI->getValue()[0];
+  }
+};
+
+/// \name Specializations of \c TBAANodeImpl for const and non const qualified
+/// \c MDNode.
+/// @{
+using TBAANode = TBAANodeImpl<const MDNode>;
+using MutableTBAANode = TBAANodeImpl<MDNode>;
+/// @}
+
+/// This is a simple wrapper around an MDNode which provides a
+/// higher-level interface by hiding the details of how alias analysis
+/// information is encoded in its operands.
+template<typename MDNodeTy>
+class TBAAStructTagNodeImpl {
+  /// This node should be created with createTBAAAccessTag().
+  MDNodeTy *Node;
+
+public:
+  explicit TBAAStructTagNodeImpl(MDNodeTy *N) : Node(N) {}
+
+  /// Get the MDNode for this TBAAStructTagNode.
+  MDNodeTy *getNode() const { return Node; }
+
+  /// isNewFormat - Return true iff the wrapped access tag is in the new
+  /// size-aware format.
+  bool isNewFormat() const {
+    if (Node->getNumOperands() < 4)
+      return false;
+    if (MDNodeTy *AccessType = getAccessType())
+      if (!TBAANodeImpl<MDNodeTy>(AccessType).isNewFormat())
+        return false;
+    return true;
+  }
+
+  MDNodeTy *getBaseType() const {
+    return dyn_cast_or_null<MDNode>(Node->getOperand(0));
+  }
+
+  MDNodeTy *getAccessType() const {
+    return dyn_cast_or_null<MDNode>(Node->getOperand(1));
+  }
+
+  uint64_t getOffset() const {
+    return mdconst::extract<ConstantInt>(Node->getOperand(2))->getZExtValue();
+  }
+
+  uint64_t getSize() const {
+    if (!isNewFormat())
+      return UINT64_MAX;
+    return mdconst::extract<ConstantInt>(Node->getOperand(3))->getZExtValue();
+  }
+
+  /// Test if this TBAAStructTagNode represents a type for objects
+  /// which are not modified (by any means) in the context where this
+  /// AliasAnalysis is relevant.
+  bool isTypeImmutable() const {
+    unsigned OpNo = isNewFormat() ? 4 : 3;
+    if (Node->getNumOperands() < OpNo + 1)
+      return false;
+    ConstantInt *CI = mdconst::dyn_extract<ConstantInt>(Node->getOperand(OpNo));
+    if (!CI)
+      return false;
+    return CI->getValue()[0];
+  }
+};
+
+/// \name Specializations of \c TBAAStructTagNodeImpl for const and non const
+/// qualified \c MDNods.
+/// @{
+using TBAAStructTagNode = TBAAStructTagNodeImpl<const MDNode>;
+using MutableTBAAStructTagNode = TBAAStructTagNodeImpl<MDNode>;
+/// @}
+
+/// This is a simple wrapper around an MDNode which provides a
+/// higher-level interface by hiding the details of how alias analysis
+/// information is encoded in its operands.
+class TBAAStructTypeNode {
+  /// This node should be created with createTBAATypeNode().
+  const MDNode *Node = nullptr;
+
+public:
+  TBAAStructTypeNode() = default;
+  explicit TBAAStructTypeNode(const MDNode *N) : Node(N) {}
+
+  /// Get the MDNode for this TBAAStructTypeNode.
+  const MDNode *getNode() const { return Node; }
+
+  /// isNewFormat - Return true iff the wrapped type node is in the new
+  /// size-aware format.
+  bool isNewFormat() const { return isNewFormatTypeNode(Node); }
+
+  bool operator==(const TBAAStructTypeNode &Other) const {
+    return getNode() == Other.getNode();
+  }
+
+  /// getId - Return type identifier.
+  Metadata *getId() const {
+    return Node->getOperand(isNewFormat() ? 2 : 0);
+  }
+
+  unsigned getNumFields() const {
+    unsigned FirstFieldOpNo = isNewFormat() ? 3 : 1;
+    unsigned NumOpsPerField = isNewFormat() ? 3 : 2;
+    return (getNode()->getNumOperands() - FirstFieldOpNo) / NumOpsPerField;
+  }
+
+  TBAAStructTypeNode getFieldType(unsigned FieldIndex) const {
+    unsigned FirstFieldOpNo = isNewFormat() ? 3 : 1;
+    unsigned NumOpsPerField = isNewFormat() ? 3 : 2;
+    unsigned OpIndex = FirstFieldOpNo + FieldIndex * NumOpsPerField;
+    auto *TypeNode = cast<MDNode>(getNode()->getOperand(OpIndex));
+    return TBAAStructTypeNode(TypeNode);
+  }
+
+  /// Get the offset of the field at \p FieldIndex within this type.
+  uint64_t getFieldOffset(unsigned FieldIndex) const {
+    unsigned FirstFieldOpNo = isNewFormat() ? 3 : 1;
+    unsigned NumOpsPerField = isNewFormat() ? 3 : 2;
+    unsigned OpIndex = FirstFieldOpNo + FieldIndex * NumOpsPerField;
+    return mdconst::extract<ConstantInt>(getNode()->getOperand(OpIndex + 1))
+        ->getZExtValue();
+  }
+
+  /// Get this TBAAStructTypeNode's field in the type DAG with
+  /// given offset. Update the offset to be relative to the field type.
+  TBAAStructTypeNode getField(uint64_t &Offset) const {
+    bool NewFormat = isNewFormat();
+    const ArrayRef<MDOperand> Operands = Node->operands();
+    const unsigned NumOperands = Operands.size();
+
+    if (NewFormat) {
+      // New-format root and scalar type nodes have no fields.
+      if (NumOperands < 6)
+        return TBAAStructTypeNode();
+    } else {
+      // Parent can be omitted for the root node.
+      if (NumOperands < 2)
+        return TBAAStructTypeNode();
+
+      // Fast path for a scalar type node and a struct type node with a single
+      // field.
+      if (NumOperands <= 3) {
+        uint64_t Cur =
+            NumOperands == 2
+                ? 0
+                : mdconst::extract<ConstantInt>(Operands[2])->getZExtValue();
+        Offset -= Cur;
+        MDNode *P = dyn_cast_or_null<MDNode>(Operands[1]);
+        if (!P)
+          return TBAAStructTypeNode();
+        return TBAAStructTypeNode(P);
+      }
+    }
+
+    // Assume the offsets are in order. We return the previous field if
+    // the current offset is bigger than the given offset.
+    unsigned FirstFieldOpNo = NewFormat ? 3 : 1;
+    unsigned NumOpsPerField = NewFormat ? 3 : 2;
+    unsigned TheIdx = 0;
+
+    for (unsigned Idx = FirstFieldOpNo; Idx < NumOperands;
+         Idx += NumOpsPerField) {
+      uint64_t Cur =
+          mdconst::extract<ConstantInt>(Operands[Idx + 1])->getZExtValue();
+      if (Cur > Offset) {
+        assert(Idx >= FirstFieldOpNo + NumOpsPerField &&
+               "TBAAStructTypeNode::getField should have an offset match!");
+        TheIdx = Idx - NumOpsPerField;
+        break;
+      }
+    }
+    // Move along the last field.
+    if (TheIdx == 0)
+      TheIdx = NumOperands - NumOpsPerField;
+    uint64_t Cur =
+        mdconst::extract<ConstantInt>(Operands[TheIdx + 1])->getZExtValue();
+    Offset -= Cur;
+    MDNode *P = dyn_cast_or_null<MDNode>(Operands[TheIdx]);
+    if (!P)
+      return TBAAStructTypeNode();
+    return TBAAStructTypeNode(P);
+  }
+};
+
+} // end namespace llvm
+
+#endif // LLVM_IR_TBAAMETADATA_H
diff --git a/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp b/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp
index dbe4ccac7801d..75b12d0325b0e 100644
--- a/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp
+++ b/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp
@@ -110,6 +110,7 @@
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/Metadata.h"
 #include "llvm/IR/Module.h"
+#include "llvm/IR/TBAAMetadata.h"
 #include "llvm/InitializePasses.h"
 #include "llvm/Pass.h"
 #include "llvm/Support/Casting.h"
@@ -125,239 +126,6 @@ using namespace llvm;
 // more convenient.
 static cl::opt<bool> EnableTBAA("enable-tbaa", cl::init(true), cl::Hidden);
 
-namespace {
-
-/// isNewFormatTypeNode - Return true iff the given type node is in the new
-/// size-aware format.
-static bool isNewFormatTypeNode(const MDNode *N) {
-  if (N->getNumOperands() < 3)
-    return false;
-  // In the old format the first operand is a string.
-  if (!isa<MDNode>(N->getOperand(0)))
-    return false;
-  return true;
-}
-
-/// This is a simple wrapper around an MDNode which provides a higher-level
-/// interface by hiding the details of how alias analysis information is encoded
-/// in its operands.
-template<typename MDNodeTy>
-class TBAANodeImpl {
-  MDNodeTy *Node = nullptr;
-
-public:
-  TBAANodeImpl() = default;
-  explicit TBAANodeImpl(MDNodeTy *N) : Node(N) {}
-
-  /// getNode - Get the MDNode for this TBAANode.
-  MDNodeTy *getNode() const { return Node; }
-
-  /// isNewFormat - Return true iff the wrapped type node is in the new
-  /// size-aware format.
-  bool isNewFormat() const { return isNewFormatTypeNode(Node); }
-
-  /// getParent - Get this TBAANode's Alias tree parent.
-  TBAANodeImpl<MDNodeTy> getParent() const {
-    if (isNewFormat())
-      return TBAANodeImpl(cast<MDNodeTy>(Node->getOperand(0)));
-
-    if (Node->getNumOperands() < 2)
-      return TBAANodeImpl<MDNodeTy>();
-    MDNodeTy *P = dyn_cast_or_null<MDNodeTy>(Node->getOperand(1));
-    if (!P)
-      return TBAANodeImpl<MDNodeTy>();
-    // Ok, this node has a valid parent. Return it.
-    return TBAANodeImpl<MDNodeTy>(P);
-  }
-
-  /// Test if this TBAANode represents a type for objects which are
-  /// not modified (by any means) in the context where this
-  /// AliasAnalysis is relevant.
-  bool isTypeImmutable() const {
-    if (Node->getNumOperands() < 3)
-      return false;
-    ConstantInt *CI = mdconst::dyn_extract<ConstantInt>(Node->getOperand(2));
-    if (!CI)
-      return false;
-    return CI->getValue()[0];
-  }
-};
-
-/// \name Specializations of \c TBAANodeImpl for const and non const qualified
-/// \c MDNode.
-/// @{
-using TBAANode = TBAANodeImpl<const MDNode>;
-using MutableTBAANode = TBAANodeImpl<MDNode>;
-/// @}
-
-/// This is a simple wrapper around an MDNode which provides a
-/// higher-level interface by hiding the details of how alias analysis
-/// information is encoded in its operands.
-template<typename MDNodeTy>
-class TBAAStructTagNodeImpl {
-  /// This node should be created with createTBAAAccessTag().
-  MDNodeTy *Node;
-
-public:
-  explicit TBAAStructTagNodeImpl(MDNodeTy *N) : Node(N) {}
-
-  /// Get the MDNode for this TBAAStructTagNode.
-  MDNodeTy *getNode() const { return Node; }
-
-  /// isNewFormat - Return true iff the wrapped access tag is in the new
-  /// size-aware format.
-  bool isNewFormat() const {
-    if (Node->getNumOperands() < 4)
-      return false;
-    if (MDNodeTy *AccessType = getAccessType())
-      if (!TBAANodeImpl<MDNodeTy>(AccessType).isNewFormat())
-        return false;
-    return true;
-  }
-
-  MDNodeTy *getBaseType() const {
-    return dyn_cast_or_null<MDNode>(Node->getOperand(0));
-  }
-
-  MDNodeTy *getAccessType() const {
-    return dyn_cast_or_null<MDNode>(Node->getOperand(1));
-  }
-
-  uint64_t getOffset() const {
-    return mdconst::extract<ConstantInt>(Node->getOperand(2))->getZExtValue();
-  }
-
-  uint64_t getSize() const {
-    if (!isNewFormat())
-      return UINT64_MAX;
-    return mdconst::extract<ConstantInt>(Node->getOperand(3))->getZExtValue();
-  }
-
-  /// Test if this TBAAStructTagNode represents a type for objects
-  /// which are not modified (by any means) in the context where this
-  /// AliasAnalysis is relevant.
-  bool isTypeImmutable() const {
-    unsigned OpNo = isNewFormat() ? 4 : 3;
-    if (Node->getNumOperands() < OpNo + 1)
-      return false;
-    ConstantInt *CI = mdconst::dyn_extract<ConstantInt>(Node->getOperand(OpNo));
-    if (!CI)
-      return false;
-    return CI->getValue()[0];
-  }
-};
-
-/// \name Specializations of \c TBAAStructTagNodeImpl for const and non const
-/// qualified \c MDNods.
-/// @{
-using TBAAStructTagNode = TBAAStructTagNodeImpl<const MDNode>;
-using MutableTBAAStructTagNode = TBAAStructTagNodeImpl<MDNode>;
-/// @}
-
-/// This is a simple wrapper around an MDNode which provides a
-/// higher-level interface by hiding the details of how alias analysis
-/// information is encoded in its operands.
-class TBAAStructTypeNode {
-  /// This node should be created with createTBAATypeNode().
-  const MDNode *Node = nullptr;
-
-public:
-  TBAAStructTypeNode() = default;
-  explicit TBAAStructTypeNode(const MDNode *N) : Node(N) {}
-
-  /// Get the MDNode for this TBAAStructTypeNode.
-  const MDNode *getNode() const { return Node; }
-
-  /// isNewFormat - Return true iff the wrapped type node is in the new
-  /// size-aware format.
-  bool isNewFormat() const { return isNewFormatTypeNode(Node); }
-
-  bool operator==(const TBAAStructTypeNode &Other) const {
-    return getNode() == Other.getNode();
-  }
-
-  /// getId - Return type identifier.
-  Metadata *getId() const {
-    return Node->getOperand(isNewFormat() ? 2 : 0);
-  }
-
-  unsigned getNumFields() const {
-    unsigned FirstFieldOpNo = isNewFormat() ? 3 : 1;
-    unsigned NumOpsPerField = isNewFormat() ? 3 : 2;
-    return (getNode()->getNumOperands() - FirstFieldOpNo) / NumOpsPerField;
-  }
-
-  TBAAStructTypeNode getFieldType(unsigned FieldIndex) const {
-    unsigned FirstFieldOpNo = isNewFormat() ? 3 : 1;
-    unsigned NumOpsPerField = isNewFormat() ? 3 : 2;
-    unsigned OpIndex = FirstFieldOpNo + FieldIndex * NumOpsPerField;
-    auto *TypeNode = cast<MDNode>(getNode()->getOperand(OpIndex));
-    return TBAAStructTypeNode(TypeNode);
-  }
-
-  /// Get this TBAAStructTypeNode's field in the type DAG with
-  /// given offset. Update the offset to be relative to the field type.
-  TBAAStructTypeNode getField(uint64_t &Offset) const {
-    bool NewFormat = isNewFormat();
-    const ArrayRef<MDOperand> Operands = Node->operands();
-    const unsigned NumOperands = Operands.size();
-
-    if (NewFormat) {
-      // New-format root and scalar type nodes have no fields.
-      if (NumOperands < 6)
-        return TBAAStructTypeNode();
-    } else {
-      // Parent can be omitted for the root node.
-      if (NumOperands < 2)
-        return TBAAStructTypeNode();
-
-      // Fast path for a scalar type node and a struct type node with a single
-      // field.
-      if (NumOperands <= 3) {
-        uint64_t Cur =
-            NumOperands == 2
-                ? 0
-                : mdconst::extract<ConstantInt>(Operands[2])->getZExtValue();
-        Offset -= Cur;
-        MDNode *P = dyn_cast_or_null<MDNode>(Operands[1]);
-        if (!P)
-          return TBAAStructTypeNode();
-        return TBAAStructTypeNode(P);
-      }
-    }
-
-    // Assume the offsets are in order. We return the previous field if
-    // the current offset is bigger than the given offset.
-    unsigned FirstFieldOpNo = NewFormat ? 3 : 1;
-    unsigned NumOpsPerField = NewFormat ? 3 : 2;
-    unsigned TheIdx = 0;
-
-    for (unsigned Idx = FirstFieldOpNo; Idx < NumOperands;
-         Idx += NumOpsPerField) {
-      uint64_t Cur =
-          mdconst::extract<ConstantInt>(Operands[Idx + 1])->getZExtValue();
-      if (Cur > Offset) {
-        assert(Idx >= FirstFieldOpNo + NumOpsPerField &&
-               "TBAAStructTypeNode::getField should have an offset match!");
-        TheIdx = Idx - NumOpsPerField;
-        break;
-      }
-    }
-    // Move along the last field.
-    if (TheIdx == 0)
-      TheIdx = NumOperands - NumOpsPerField;
-    uint64_t Cur =
-        mdconst::extract<ConstantInt>(Operands[TheIdx + 1])->getZExtValue();
-    Offset -= Cur;
-    MDNode *P = dyn_cast_or_null<MDNode>(Operands[TheIdx]);
-    if (!P)
-      return TBAAStructTypeNode();
-    return TBAAStructTypeNode(P);
-  }
-};
-
-} // end anonymous namespace
-
 AliasResult TypeBasedAAResult::alias(const MemoryLocation &LocA,
                                      const MemoryLocation &LocB,
                                      AAQueryInfo &AAQI, const Instruction *) {
diff --git a/llvm/lib/IR/MDBuilder.cpp b/llvm/lib/IR/MDBuilder.cpp
index 9a8e417b43ba7..102ad2a65fc1c 100644
--- a/llvm/lib/IR/MDBuilder.cpp
+++ b/llvm/lib/IR/MDBuilder.cpp
@@ -15,6 +15,7 @@
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/Function.h"
 #include "llvm/IR/Metadata.h"
+#include "llvm/IR/TBAAMetadata.h"
 #include "llvm/IR/ProfDataUtils.h"
 using namespace llvm;
 
@@ -314,30 +315,21 @@ MDNode *MDBuilder::createTBAAAccessTag(MDNode *BaseType, MDNode *AccessType,
 }
 
 MDNode *MDBuilder::createMutableTBAAAccessTag(MDNode *Tag) {
-  MDNode *BaseType = cast<MDNode>(Tag->getOperand(0));
-  MDNode *AccessType = cast<MDNode>(Tag->getOperand(1));
-  Metadata *OffsetNode = Tag->getOperand(2);
-  uint64_t Offset = mdconst::extract<ConstantInt>(OffsetNode)->getZExtValue();
-
-  bool NewFormat = isa<MDNode>(AccessType->getOperand(0));
-
-  // See if the tag is already mutable.
-  unsigned ImmutabilityFlagOp = NewFormat ? 4 : 3;
-  if (Tag->getNumOperands() <= ImmutabilityFlagOp)
-    return Tag;
-
-  // If Tag is already mutable then return it.
-  Metadata *ImmutabilityFlagNode = Tag->getOperand(ImmutabilityFlagOp);
-  if (!mdconst::extract<ConstantInt>(ImmutabilityFlagNode)->getValue())
+  MutableTBAAStructTagNode TagNode(Tag);
+  MDNode *BaseType = TagNode.getBaseType();
+  MDNode *AccessType = TagNode.getAccessType();
+  uint64_t Offset = TagNode.getOffset();
+  bool NewFormat = isNewFormatTypeNode(AccessType);
+
+  // If the tag has no immutability flag, or is already mutable, return it.
+  if (!TagNode.isTypeImmutable())
     return Tag;
 
   // Otherwise, create another node.
   if (!NewFormat)
     return createTBAAStructTagNode(BaseType, AccessType, Offset);
 
-  Metad...
[truncated]

``````````

</details>


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


More information about the llvm-commits mailing list