]> granicus.if.org Git - llvm/commitdiff
[Verifier] Add verification for TBAA metadata
authorSanjoy Das <sanjoy@playingwithpointers.com>
Sun, 11 Dec 2016 20:07:15 +0000 (20:07 +0000)
committerSanjoy Das <sanjoy@playingwithpointers.com>
Sun, 11 Dec 2016 20:07:15 +0000 (20:07 +0000)
Summary:
This change adds some verification in the IR verifier around struct path
TBAA metadata.

Other than some basic sanity checks (e.g. we get constant integers where
we expect constant integers), this checks:

 - That by the time an struct access tuple `(base-type, offset)` is
   "reduced" to a scalar base type, the offset is `0`.  For instance, in
   C++ you can't start from, say `("struct-a", 16)`, and end up with
   `("int", 4)` -- by the time the base type is `"int"`, the offset
   better be zero.  In particular, a variant of this invariant is needed
   for `llvm::getMostGenericTBAA` to be correct.

 - That there are no cycles in a struct path.

 - That struct type nodes have their offsets listed in an ascending
   order.

 - That when generating the struct access path, you eventually reach the
   access type listed in the tbaa tag node.

Reviewers: dexonsmith, chandlerc, reames, mehdi_amini, manmanren

Subscribers: mcrosier, llvm-commits

Differential Revision: https://reviews.llvm.org/D26438

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@289402 91177308-0d34-0410-b5e6-96231b3b80d8

36 files changed:
lib/IR/Verifier.cpp
test/Analysis/BasicAA/full-store-partial-alias.ll
test/Analysis/CFLAliasAnalysis/Steensgaard/full-store-partial-alias.ll
test/Analysis/TypeBasedAliasAnalysis/aliastest.ll
test/Analysis/TypeBasedAliasAnalysis/cyclic.ll
test/Analysis/TypeBasedAliasAnalysis/dse.ll
test/Analysis/TypeBasedAliasAnalysis/dynamic-indices.ll
test/Analysis/TypeBasedAliasAnalysis/gvn-nonlocal-type-mismatch.ll
test/Analysis/TypeBasedAliasAnalysis/intrinsics.ll
test/Analysis/TypeBasedAliasAnalysis/licm.ll
test/Analysis/TypeBasedAliasAnalysis/memcpyopt.ll
test/CodeGen/AMDGPU/llvm.SI.load.dword.ll
test/CodeGen/AMDGPU/sgpr-copy.ll
test/CodeGen/AMDGPU/si-lod-bias.ll
test/CodeGen/AMDGPU/si-scheduler.ll
test/CodeGen/AMDGPU/si-sgpr-spill.ll
test/CodeGen/AMDGPU/split-smrd.ll
test/CodeGen/AMDGPU/vgpr-spill-emergency-stack-slot.ll
test/CodeGen/AMDGPU/wait.ll
test/CodeGen/ARM/2011-05-04-MultipleLandingPadSuccs.ll
test/Instrumentation/AddressSanitizer/X86/bug_11395.ll
test/Instrumentation/ThreadSanitizer/read_from_global.ll
test/Instrumentation/ThreadSanitizer/vptr_read.ll
test/Instrumentation/ThreadSanitizer/vptr_update.ll
test/Transforms/GVN/PRE/preserve-tbaa.ll
test/Transforms/GVN/tbaa.ll
test/Transforms/InstCombine/load-combine-metadata.ll
test/Transforms/InstCombine/loadstore-metadata.ll
test/Transforms/InstCombine/tbaa-store-to-load.ll
test/Transforms/JumpThreading/thread-loads.ll
test/Transforms/LICM/2011-04-06-PromoteResultOfPromotion.ll
test/Transforms/LoopVectorize/ARM/vector_cast.ll
test/Transforms/SLPVectorizer/X86/crash_scheduling.ll
test/Transforms/SimplifyCFG/basictest.ll
test/Transforms/Util/store-first-op.ll
test/Verifier/tbaa.ll [new file with mode: 0644]

index 6f7e344b1b3bc523ad433035e39a54f82de299a7..037506a389caa0f676291445dd39be617edeeee9 100644 (file)
@@ -187,6 +187,14 @@ private:
     *OS << *C;
   }
 
+  void Write(const APInt *AI) {
+    if (!AI)
+      return;
+    *OS << *AI << '\n';
+  }
+
+  void Write(const unsigned i) { *OS << i << '\n'; }
+
   template <typename T> void Write(ArrayRef<T> Vs) {
     for (const T &V : Vs)
       Write(V);
@@ -285,6 +293,17 @@ class Verifier : public InstVisitor<Verifier>, VerifierSupport {
   // constant expressions, we can arrive at a particular user many times.
   SmallPtrSet<const Value *, 32> GlobalValueVisited;
 
+  /// Cache of TBAA base nodes that have already been visited.  This cachce maps
+  /// a node that has been visited to a pair (IsInvalid, BitWidth) where
+  ///
+  ///  \c IsInvalid is true iff the node is invalid.
+  ///  \c BitWidth, if non-zero, is the bitwidth of the integer used to denoting
+  ///    the offset of the access.  If zero, only a zero offset is allowed.
+  ///
+  /// \c BitWidth has no meaning if \c IsInvalid is true.
+  typedef std::pair<bool, unsigned> TBAABaseNodeSummary;
+  DenseMap<MDNode *, TBAABaseNodeSummary> TBAABaseNodes;
+
   void checkAtomicMemAccessSize(Type *Ty, const Instruction *I);
 
 public:
@@ -393,6 +412,14 @@ private:
   void visitDereferenceableMetadata(Instruction &I, MDNode *MD);
   void visitTBAAMetadata(Instruction &I, MDNode *MD);
 
+  /// \name Helper functions used by \c visitTBAAMetadata.
+  /// @{
+  MDNode *getFieldNodeFromTBAABaseNode(Instruction &I, MDNode *BaseNode,
+                                       APInt &Offset);
+  TBAABaseNodeSummary verifyTBAABaseNode(Instruction &I, MDNode *BaseNode);
+  TBAABaseNodeSummary verifyTBAABaseNodeImpl(Instruction &I, MDNode *BaseNode);
+  /// @}
+
   template <class Ty> bool isValidMetadataArray(const MDTuple &N);
 #define HANDLE_SPECIALIZED_MDNODE_LEAF(CLASS) void visit##CLASS(const CLASS &N);
 #include "llvm/IR/Metadata.def"
@@ -3657,6 +3684,174 @@ void Verifier::visitDereferenceableMetadata(Instruction& I, MDNode* MD) {
          "dereferenceable_or_null metadata value must be an i64!", &I);
 }
 
+/// Verify that \p BaseNode can be used as the "base type" in the struct-path
+/// TBAA scheme.  This means \p BaseNode is either a scalar node, or a
+/// struct-type node describing an aggregate data structure (like a struct).
+Verifier::TBAABaseNodeSummary Verifier::verifyTBAABaseNode(Instruction &I,
+                                                           MDNode *BaseNode) {
+  if (BaseNode->getNumOperands() < 2) {
+    CheckFailed("Base nodes must have at least two operands", &I, BaseNode);
+    return {true, ~0u};
+  }
+
+  auto Itr = TBAABaseNodes.find(BaseNode);
+  if (Itr != TBAABaseNodes.end())
+    return Itr->second;
+
+  auto Result = verifyTBAABaseNodeImpl(I, BaseNode);
+  auto InsertResult = TBAABaseNodes.insert({BaseNode, Result});
+  (void)InsertResult;
+  assert(InsertResult.second && "We just checked!");
+  return Result;
+}
+
+Verifier::TBAABaseNodeSummary
+Verifier::verifyTBAABaseNodeImpl(Instruction &I, MDNode *BaseNode) {
+  const Verifier::TBAABaseNodeSummary InvalidNode = {true, ~0u};
+
+  if (BaseNode->getNumOperands() == 2) {
+    // This is a scalar base node.
+    if (!BaseNode->getOperand(0) || !BaseNode->getOperand(1)) {
+      CheckFailed("Null operands in scalar type nodes!", &I, BaseNode);
+      return InvalidNode;
+    }
+    if (!isa<MDNode>(BaseNode->getOperand(1))) {
+      CheckFailed("Invalid parent operand in scalar TBAA node", &I, BaseNode);
+      return InvalidNode;
+    }
+    if (!isa<MDString>(BaseNode->getOperand(0))) {
+      CheckFailed("Invalid name operand in scalar TBAA node", &I, BaseNode);
+      return InvalidNode;
+    }
+
+    // Scalar nodes can only be accessed at offset 0.
+    return {false, 0};
+  }
+
+  if (BaseNode->getNumOperands() % 2 != 1) {
+    CheckFailed("Struct tag nodes must have an odd number of operands!",
+                BaseNode);
+    return InvalidNode;
+  }
+
+  bool Failed = false;
+
+  Optional<APInt> PrevOffset;
+  unsigned BitWidth = ~0u;
+
+  // We've already checked that BaseNode is not a degenerate root node with one
+  // operand in \c verifyTBAABaseNode, so this loop should run at least once.
+  for (unsigned Idx = 1; Idx < BaseNode->getNumOperands(); Idx += 2) {
+    const MDOperand &FieldTy = BaseNode->getOperand(Idx);
+    const MDOperand &FieldOffset = BaseNode->getOperand(Idx + 1);
+    if (!isa<MDNode>(FieldTy)) {
+      CheckFailed("Incorrect field entry in struct type node!", &I, BaseNode);
+      Failed = true;
+      continue;
+    }
+
+    auto *OffsetEntryCI =
+        mdconst::dyn_extract_or_null<ConstantInt>(FieldOffset);
+    if (!OffsetEntryCI) {
+      CheckFailed("Offset entries must be constants!", &I, BaseNode);
+      Failed = true;
+      continue;
+    }
+
+    if (BitWidth == ~0u)
+      BitWidth = OffsetEntryCI->getBitWidth();
+
+    if (OffsetEntryCI->getBitWidth() != BitWidth) {
+      CheckFailed(
+          "Bitwidth between the offsets and struct type entries must match", &I,
+          BaseNode);
+      Failed = true;
+      continue;
+    }
+
+    // NB! As far as I can tell, we generate a non-strictly increasing offset
+    // sequence only from structs that have zero size bit fields.  When
+    // recursing into a contained struct in \c getFieldNodeFromTBAABaseNode we
+    // pick the field lexically the latest in struct type metadata node.  This
+    // mirrors the actual behavior of the alias analysis implementation.
+    bool IsAscending =
+        !PrevOffset || PrevOffset->ule(OffsetEntryCI->getValue());
+
+    if (!IsAscending) {
+      CheckFailed("Offsets must be increasing!", &I, BaseNode);
+      Failed = true;
+    }
+
+    PrevOffset = OffsetEntryCI->getValue();
+  }
+
+  return Failed ? InvalidNode : Verifier::TBAABaseNodeSummary(false, BitWidth);
+}
+
+static bool IsRootTBAANode(const MDNode *MD) {
+  return MD->getNumOperands() < 2;
+}
+
+static bool IsScalarTBAANodeImpl(const MDNode *MD,
+                                 SmallPtrSetImpl<const MDNode *> &Visited) {
+  if (MD->getNumOperands() == 2)
+    return true;
+
+  if (MD->getNumOperands() != 3)
+    return false;
+
+  auto *Offset = mdconst::dyn_extract<ConstantInt>(MD->getOperand(2));
+  if (!(Offset && Offset->isZero() && isa<MDString>(MD->getOperand(0))))
+    return false;
+
+  auto *Parent = dyn_cast<MDNode>(MD->getOperand(1));
+  return Visited.insert(Parent).second &&
+         (IsRootTBAANode(Parent) || IsScalarTBAANodeImpl(Parent, Visited));
+}
+
+static bool IsScalarTBAANode(const MDNode *MD) {
+  SmallPtrSet<const MDNode *, 4> Visited;
+  return IsScalarTBAANodeImpl(MD, Visited);
+}
+
+/// Returns the field node at the offset \p Offset in \p BaseNode.  Update \p
+/// Offset in place to be the offset within the field node returned.
+///
+/// We assume we've okayed \p BaseNode via \c verifyTBAABaseNode.
+MDNode *Verifier::getFieldNodeFromTBAABaseNode(Instruction &I, MDNode *BaseNode,
+                                               APInt &Offset) {
+  assert(BaseNode->getNumOperands() >= 2 && "Invalid base node!");
+
+  // Scalar nodes have only one possible "field" -- their parent in the access
+  // hierarchy.  Offset must be zero at this point, but our caller is supposed
+  // to Assert that.
+  if (BaseNode->getNumOperands() == 2)
+    return cast<MDNode>(BaseNode->getOperand(1));
+
+  for (unsigned Idx = 1; Idx < BaseNode->getNumOperands(); Idx += 2) {
+    auto *OffsetEntryCI =
+        mdconst::extract<ConstantInt>(BaseNode->getOperand(Idx + 1));
+    if (OffsetEntryCI->getValue().ugt(Offset)) {
+      if (Idx == 1) {
+        CheckFailed("Could not find TBAA parent in struct type node", &I,
+                    BaseNode, &Offset);
+        return nullptr;
+      }
+
+      auto *PrevOffsetEntryCI =
+          mdconst::extract<ConstantInt>(BaseNode->getOperand(Idx - 1));
+      Offset -= PrevOffsetEntryCI->getValue();
+      return cast<MDNode>(BaseNode->getOperand(Idx - 2));
+    }
+  }
+
+  auto *LastOffsetEntryCI = mdconst::extract<ConstantInt>(
+      BaseNode->getOperand(BaseNode->getNumOperands() - 1));
+
+  Offset -= LastOffsetEntryCI->getValue();
+  return cast<MDNode>(BaseNode->getOperand(BaseNode->getNumOperands() - 2));
+}
+
 void Verifier::visitTBAAMetadata(Instruction &I, MDNode *MD) {
   bool IsStructPathTBAA =
       isa<MDNode>(MD->getOperand(0)) && MD->getNumOperands() >= 3;
@@ -3664,6 +3859,70 @@ void Verifier::visitTBAAMetadata(Instruction &I, MDNode *MD) {
   Assert(IsStructPathTBAA,
          "Old-style TBAA is no longer allowed, use struct-path TBAA instead",
          &I);
+
+  Assert(MD->getNumOperands() < 5,
+         "Struct tag metadata must have either 3 or 4 operands", &I, MD);
+
+  MDNode *BaseNode = dyn_cast_or_null<MDNode>(MD->getOperand(0));
+  MDNode *AccessType = dyn_cast_or_null<MDNode>(MD->getOperand(1));
+
+  if (MD->getNumOperands() == 4) {
+    auto *IsImmutableCI =
+        mdconst::dyn_extract_or_null<ConstantInt>(MD->getOperand(3));
+    Assert(IsImmutableCI,
+           "Immutability tag on struct tag metadata must be a constant", &I,
+           MD);
+    Assert(IsImmutableCI->isZero() || IsImmutableCI->isOne(),
+           "Immutability part of the struct tag metadata must be either 0 or 1",
+           &I, MD);
+  }
+
+  Assert(BaseNode && AccessType,
+         "Malformed struct tag metadata:  base and access-type "
+         "should be non-null and point to Metadata nodes",
+         &I, MD, BaseNode, AccessType);
+
+  Assert(IsScalarTBAANode(AccessType), "Access type node must be scalar", &I,
+         MD, AccessType);
+
+  auto *OffsetCI = mdconst::dyn_extract_or_null<ConstantInt>(MD->getOperand(2));
+  Assert(OffsetCI, "Offset must be constant integer", &I, MD);
+
+  APInt Offset = OffsetCI->getValue();
+  bool SeenAccessTypeInPath = false;
+
+  SmallPtrSet<MDNode *, 4> StructPath;
+
+  for (/* empty */; BaseNode && !IsRootTBAANode(BaseNode);
+       BaseNode = getFieldNodeFromTBAABaseNode(I, BaseNode, Offset)) {
+    if (!StructPath.insert(BaseNode).second) {
+      CheckFailed("Cycle detected in struct path", &I, MD);
+      return;
+    }
+
+    bool Invalid;
+    unsigned BaseNodeBitWidth;
+    std::tie(Invalid, BaseNodeBitWidth) = verifyTBAABaseNode(I, BaseNode);
+
+    // If the base node is invalid in itself, then we've already printed all the
+    // errors we wanted to print.
+    if (Invalid)
+      return;
+
+    SeenAccessTypeInPath |= BaseNode == AccessType;
+
+    if (IsScalarTBAANode(BaseNode) || BaseNode == AccessType)
+      Assert(Offset == 0, "Offset not zero at the point of scalar access", &I,
+             MD, &Offset);
+
+    Assert(BaseNodeBitWidth == Offset.getBitWidth() ||
+               (BaseNodeBitWidth == 0 && Offset == 0),
+           "Access bit-width not the same as description bit-width", &I, MD,
+           BaseNodeBitWidth, Offset.getBitWidth());
+  }
+
+  Assert(SeenAccessTypeInPath, "Did not see access type in access path!", &I,
+         MD);
 }
 
 /// verifyInstruction - Verify that an instruction is well formed.
@@ -3801,8 +4060,12 @@ void Verifier::visitInstruction(Instruction &I) {
   if (MDNode *MD = I.getMetadata(LLVMContext::MD_dereferenceable_or_null))
     visitDereferenceableMetadata(I, MD);
 
-  if (MDNode *MD = I.getMetadata(LLVMContext::MD_tbaa))
-    visitTBAAMetadata(I, MD);
+  if (MDNode *TBAA = I.getMetadata(LLVMContext::MD_tbaa)) {
+    Assert(isa<LoadInst>(I) || isa<StoreInst>(I) || isa<CallInst>(I) ||
+               isa<VAArgInst>(I),
+           "TBAA is only for loads, stores and calls!", &I);
+    visitTBAAMetadata(I, TBAA);
+  }
 
   if (MDNode *AlignMD = I.getMetadata(LLVMContext::MD_align)) {
     Assert(I.getType()->isPointerTy(), "align applies only to pointer types",
index 20f6f7ec4ad04c210c212a83c0869135638c0ebd..e1337d6805b7a3fddd2021ce27051261116fdac0 100644 (file)
@@ -31,7 +31,7 @@ entry:
 
 !0 = !{!4, !4, i64 0}
 !1 = !{!"omnipotent char", !2}
-!2 = !{!"Simple C/C++ TBAA", null}
+!2 = !{!"Simple C/C++ TBAA"}
 !3 = !{!5, !5, i64 0}
 !4 = !{!"double", !1}
 !5 = !{!"int", !1}
index 39ea845f2a3a32d71b68253dbdd17c9666814d14..2f9ac96c0cc62f143c398113ce7097032f2751ea 100644 (file)
@@ -33,7 +33,7 @@ entry:
 
 !0 = !{!4, !4, i64 0}
 !1 = !{!"omnipotent char", !2}
-!2 = !{!"Simple C/C++ TBAA", null}
+!2 = !{!"Simple C/C++ TBAA"}
 !3 = !{!5, !5, i64 0}
 !4 = !{!"double", !1}
 !5 = !{!"int", !1}
index 93c34f9503ce6f3b78e3cb97e12fc27ac66afce6..3bdd9d8a2ef530bd21c78d9e085f3b8103f8232e 100644 (file)
@@ -63,5 +63,6 @@ define i8 @test1_no(i8* %a, i8* %b) nounwind {
 !7 = !{ !"foo", !0 }
 !8 = !{ !"bar", !0 }
 !9 = !{ !"foo", !0 }
-!10 = !{ !"bar", !"different" }
+!10 = !{ !"bar", !12 }
 !11 = !{ !"qux", !0}
+!12 = !{!"different"}
index a88e26c5cd52b10cceb13a596abf9a64b8cc5b04..8400b3ce8d7f7ceefcec94f0504a01dbb6af1273 100644 (file)
@@ -1,5 +1,5 @@
 ; RUN: not opt -instcombine < %s 2>&1 | FileCheck %s
-; CHECK: Cycle found in TBAA metadata.
+; CHECK: Access type node must be scalar
 
 define void @test6(i32* %gi) #0 {
 entry:
index b6dc9b298eb060e69c8b8cc08270848692e4025b..8c51e99e3101db790632d8eba3629e99b76e6e22 100644 (file)
@@ -68,5 +68,6 @@ define i8 @test1_no(i8* %a, i8* %b) nounwind {
 !7 = !{ !"foo", !0 }
 !8 = !{ !"bar", !0 }
 !9 = !{ !"foo", !0 }
-!10 = !{ !"bar", !"different" }
+!10 = !{ !"bar", !12}
 !11 = !{ !"qux", !0}
+!12 = !{!"different"}
index afc83c9f4f573277c039e37f0be80b15e703dbe8..455968d7a40179c7a132e8614562da72fe5b698d 100644 (file)
@@ -127,7 +127,7 @@ for.end:                                          ; preds = %for.body
 ; CHECK: [[TYPE_LL]] = !{!"long long", {{!.*}}}
 !0 = !{!6, !6, i64 0}
 !1 = !{!"omnipotent char", !2}
-!2 = !{!"Simple C/C++ TBAA", null}
+!2 = !{!"Simple C/C++ TBAA"}
 !3 = !{!7, !7, i64 0}
 !4 = !{!8, !8, i64 0}
 !5 = !{!9, !9, i64 0}
index aaa43a4609009d66ab0c1aa720f643433eaf1b3a..1b541a52843611213ecc25d733efe7c1cc3cc984 100644 (file)
@@ -91,5 +91,6 @@ if.else:
 !4 = !{!8, !8, i64 0}
 !5 = !{!"red", !0}
 !6 = !{!"blu", !0}
-!7 = !{!"outer space"}
+!7 = !{!"outer space", !9}
 !8 = !{!"brick red", !5}
+!9 = !{!"observable universe"}
index 197ef7e5196fa77e6fc60129b1b849f5e27d0816..eab314eaa9c27cf7b5b52f09c28736cdf0a89cde 100644 (file)
@@ -26,7 +26,7 @@ declare void @llvm.arm.neon.vst1.p0i8.v8i16(i8*, <8 x i16>, i32) nounwind
 ; CHECK: attributes #1 = { argmemonly nounwind }
 ; CHECK: attributes [[NUW]] = { nounwind }
 
-!0 = !{!"tbaa root", null}
+!0 = !{!"tbaa root"}
 !1 = !{!3, !3, i64 0}
 !2 = !{!4, !4, i64 0}
 !3 = !{!"A", !0}
index d2aee58204df9b8119aeb64c12f4ede0ac6e5b91..03c64fff0969cdb341abcb643311edba4a28c230 100644 (file)
@@ -29,7 +29,7 @@ for.end:                                          ; preds = %for.body, %entry
   ret void
 }
 
-!0 = !{!"root", null}
+!0 = !{!"root"}
 !1 = !{!6, !6, i64 0}
 !2 = !{!7, !7, i64 0}
 
@@ -58,8 +58,9 @@ loop:
 
 !3 = !{!"pointer", !8}
 !4 = !{!8, !8, i64 0}
-!5 = !{!9, !9, i64 0}
+!5 = !{!10, !10, i64 0}
 !6 = !{!"pointer", !0}
 !7 = !{!"double", !0}
 !8 = !{!"char", !9}
-!9 = !{!"root", null}
+!9 = !{!"root"}
+!10 = !{!"scalar-type", !9}
index 9fc9e42fc6cb6295a1b9061163b16e98755b0ee3..64e35788429b1ea6a8e6482810d89949d4389a14 100644 (file)
@@ -20,7 +20,7 @@ declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i32,
 
 ; CHECK: [[TAGA]] = !{[[TYPEA:!.*]], [[TYPEA]], i64 0}
 ; CHECK: [[TYPEA]] = !{!"A", !{{.*}}}
-!0 = !{!"tbaa root", null}
+!0 = !{!"tbaa root"}
 !1 = !{!3, !3, i64 0}
 !2 = !{!4, !4, i64 0}
 !3 = !{!"A", !0}
index d0cc00d81b4e14caf184014d33f9ece72fe1da6b..ee0a41f2210f18c89bb940037b3cc83663eb35e0 100644 (file)
@@ -49,4 +49,5 @@ declare void @llvm.SI.export(i32, i32, i32, i32, i32, float, float, float, float
 
 attributes #0 = { nounwind readonly }
 
-!0 = !{!"const", null, i32 1}
+!0 = !{!"const", !1, i32 1}
+!1 = !{!"tbaa root"}
index e65f1e2da5706e8b47cf14d06d16ea0d0f17991a..31ce4a681992e43de79f56804255fa2ad3c4a413 100644 (file)
@@ -412,5 +412,6 @@ attributes #1 = { nounwind readnone }
 attributes #2 = { nounwind readonly }
 
 !0 = !{!1, !1, i64 0, i32 1}
-!1 = !{!"const", null}
+!1 = !{!"const", !3}
 !2 = !{!1, !1, i64 0}
+!3 = !{!"tbaa root"}
index 8df0a64a2b7caeea42d5f8887d289102af3dda8e..bca34af3e27055ec8fd8c6219d9c91d1242e1c44 100644 (file)
@@ -49,4 +49,5 @@ declare void @llvm.SI.export(i32, i32, i32, i32, i32, float, float, float, float
 attributes #1 = { nounwind readnone }
 
 !0 = !{!1, !1, i64 0, i32 1}
-!1 = !{!"const", null}
+!1 = !{!"const", !2}
+!2 = !{!"tbaa root"}
index 5520fe61d8678b3f893cf73f0d0d2185abb5984b..9374ef3cd9070d100cabf1b59fd03c3aca33df27 100644 (file)
@@ -57,4 +57,5 @@ declare void @llvm.SI.export(i32, i32, i32, i32, i32, float, float, float, float
 attributes #1 = { nounwind readnone }
 
 !0 = !{!1, !1, i64 0, i32 1}
-!1 = !{!"const", null}
+!1 = !{!"const", !2}
+!2 = !{!"tbaa root"}
index ac06c262e9e6da33ebe7d72ec9bd5ca6472abc76..f035da83d18c96feae9a8c0f047876749b329a11 100644 (file)
@@ -1619,4 +1619,5 @@ attributes #2 = { nounwind readnone }
 attributes #3 = { nounwind readonly }
 
 !0 = !{!1, !1, i64 0, i32 1}
-!1 = !{!"const", null}
+!1 = !{!"const", !2}
+!2 = !{!"tbaa root"}
index 237a62c1360aab8ba2cd806f6419a98713f4427c..d07da103093671ddb257940b2a7a5d1044bf67ec 100644 (file)
@@ -42,5 +42,6 @@ attributes #0 = { nounwind }
 attributes #1 = { nounwind readnone }
 
 !0 = !{!1, !1, i64 0, i32 1}
-!1 = !{!"const", null}
+!1 = !{!"const", !3}
 !2 = !{!1, !1, i64 0}
+!3 = !{!"tbaa root"}
index 35a014bf7249188aed7a202b9df94e17d743c244..4de35b97aeabec8da1f55237154f2ced30df1408 100644 (file)
@@ -497,4 +497,5 @@ attributes #0 = { nounwind }
 attributes #1 = { nounwind readnone }
 
 !0 = !{!1, !1, i64 0, i32 1}
-!1 = !{!"const", null}
+!1 = !{!"const", !2}
+!2 = !{!"tbaa root"}
index 265774180a7f99a2c120df8b7eb1c66f8029ae53..152a474cde7e321fe3001a46b2ba0c056ac9fa91 100644 (file)
@@ -82,4 +82,5 @@ attributes #1 = { convergent nounwind }
 attributes #2 = { nounwind readnone }
 
 !0 = !{!1, !1, i64 0, i32 1}
-!1 = !{!"const", null}
+!1 = !{!"const", !2}
+!2 = !{!"tbaa root"}
index 559b027fb115dc7139b326506916840831332d5a..bd96ada2ea69be533f5e27905c93146c4e310eb0 100644 (file)
@@ -83,6 +83,6 @@ declare void @_ZSt9terminatev()
 
 !0 = !{!"any pointer", !1}
 !1 = !{!"omnipotent char", !2}
-!2 = !{!"Simple C/C++ TBAA", null}
+!2 = !{!"Simple C/C++ TBAA"}
 !3 = !{!"bool", !1}
 !4 = !{!"int", !1}
index dc943fe257cede0905cbd04b9f109a5128fb1a61..027148a0acd6d90038178e5cb680529ddddf2f7c 100644 (file)
@@ -66,7 +66,7 @@ entry:
 
 !0 = !{!5, !5, i64 0}
 !1 = !{!"omnipotent char", !2}
-!2 = !{!"Simple C/C++ TBAA", null}
+!2 = !{!"Simple C/C++ TBAA"}
 !3 = !{!6, !6, i64 0}
 !4 = !{i32 156132, i32 156164, i32 156205, i32 156238, i32 156282, i32 156332, i32 156370, i32 156408, i32 156447, i32 156486, i32 156536, i32 156574, i32 156612, i32 156651, i32 156690, i32 156740, i32 156778, i32 156816, i32 156855, i32 156894, i32 156944, i32 156982, i32 157020, i32 157059, i32 157098, i32 157148, i32 157186, i32 157224, i32 157263, i32 157302, i32 157352, i32 157390, i32 157428, i32 157467, i32 157506, i32 157556, i32 157594, i32 157632, i32 157671, i32 157710, i32 157760, i32 157798, i32 157836, i32 157875, i32 157914, i32 157952, i32 157996, i32 158046, i32 158099, i32 158140, i32 158179, i32 158218, i32 158268, i32 158321, i32 158362, i32 158401, i32 158440, i32 158490, i32 158543, i32 158584, i32 158623, i32 158662, i32 158712, i32 158765, i32 158806, i32 158845, i32 158884, i32 158922, i32 158963, i32 158996, i32 159029, i32 159062, i32 159109, i32 159154, i32 159199, i32 159243, i32 159286, i32 159329, i32 159375, i32 159422, i32 159478, i32 159522, i32 159566}
 !5 = !{!"any pointer", !1}
index 76ee50c91fd28f9b7e9553a81368e1ec0b9728ef..4fa8d0bd7d391569cba45a67d106f8bbfa9bec5a 100644 (file)
@@ -54,6 +54,6 @@ entry:
 ; CHECK: = load
 ; CHECK: ret void
 
-!0 = !{!"Simple C/C++ TBAA", null}
+!0 = !{!"Simple C/C++ TBAA"}
 !1 = !{!"vtable pointer", !0}
 !2 = !{!1, !1, i64 0}
index 6ed64c6acdfc60f543209c08c2fa1aba48336578..00e3ece222e53d3dc10eec0aede3e018a265f4cf 100644 (file)
@@ -9,5 +9,5 @@ entry:
   ret i8 %0
 }
 !0 = !{!2, !2, i64 0}
-!1 = !{!"Simple C/C++ TBAA", null}
+!1 = !{!"Simple C/C++ TBAA"}
 !2 = !{!"vtable pointer", !1}
index 78f7f31e1346f48d8f5474c66e91f0193ec5fe34..444ea61f64039a8c29495895ef733b2def7bcc3f 100644 (file)
@@ -36,5 +36,5 @@ entry:
 }
 
 !0 = !{!2, !2, i64 0}
-!1 = !{!"Simple C/C++ TBAA", null}
+!1 = !{!"Simple C/C++ TBAA"}
 !2 = !{!"vtable pointer", !1}
index 19467eeff4042083ea5c1afe6995e6b5b0e1a90f..2ec8e88184f5609fa8926e485c64fb9f7ca9e5b4 100644 (file)
@@ -27,5 +27,5 @@ for.end:                                          ; preds = %for.body, %entry
 
 !0 = !{!3, !3, i64 0}
 !1 = !{!"omnipotent char", !2}
-!2 = !{!"Simple C/C++ TBAA", null}
+!2 = !{!"Simple C/C++ TBAA"}
 !3 = !{!"short", !1}
index b5a717b0984a37e2c840149922afa3d34be11011..7c05fda6cb8f1eec7d09703ee61629583c690b78 100644 (file)
@@ -113,13 +113,14 @@ declare i32 @foo(i8*) readonly
 ; CHECK: [[TAGA]] = !{[[TYPEA]], [[TYPEA]], i64 0}
 !0 = !{!5, !5, i64 0}
 !1 = !{!6, !6, i64 0}
-!2 = !{!"tbaa root", null}
+!2 = !{!"tbaa root"}
 !3 = !{!7, !7, i64 0}
-!4 = !{!8, !8, i64 0}
+!4 = !{!11, !11, i64 0}
 !5 = !{!"C", !6}
 !6 = !{!"A", !2}
 !7 = !{!"B", !6}
-!8 = !{!"another root", null}
+!8 = !{!"another root"}
+!11 = !{!"scalar type", !8}
 
 
 ;; A TBAA structure who's only point is to have a constant location
index 24b26fa42135d7bb8dcdb8fdb7205bbe7d714d3c..b7f42e7a0e768dff01a983abb8c557830c24bca0 100644 (file)
@@ -26,4 +26,5 @@ define void @test_load_load_combine_metadata(i32*, i32*, i32*) {
 !5 = !{!3}
 !6 = !{!4}
 !7 = !{ !"tbaa root" }
-!8 = !{ !7, !7, i64 0 }
+!8 = !{ !9, !9, i64 0 }
+!9 = !{ !"scalar type", !7}
index f72e36a7ea377bd7ac65b2e8e09677771f669216..4856350133efda646022fcecb6159b97ef639696 100644 (file)
@@ -15,9 +15,9 @@ entry:
 define i32 @test_load_cast_combine_noalias(float* %ptr) {
 ; Ensure (cast (load (...))) -> (load (cast (...))) preserves no-alias metadata.
 ; CHECK-LABEL: @test_load_cast_combine_noalias(
-; CHECK: load i32, i32* %{{.*}}, !alias.scope !2, !noalias !1
+; CHECK: load i32, i32* %{{.*}}, !alias.scope !3, !noalias !4
 entry:
-  %l = load float, float* %ptr, !alias.scope !2, !noalias !1
+  %l = load float, float* %ptr, !alias.scope !3, !noalias !4
   %c = bitcast float %l to i32
   ret i32 %c
 }
@@ -31,7 +31,7 @@ define float @test_load_cast_combine_range(i32* %ptr) {
 ; CHECK-NOT: !range
 ; CHECK: ret float
 entry:
-  %l = load i32, i32* %ptr, !range !6
+  %l = load i32, i32* %ptr, !range !5
   %c = bitcast i32 %l to float
   ret float %c
 }
@@ -39,9 +39,9 @@ entry:
 define i32 @test_load_cast_combine_invariant(float* %ptr) {
 ; Ensure (cast (load (...))) -> (load (cast (...))) preserves invariant metadata.
 ; CHECK-LABEL: @test_load_cast_combine_invariant(
-; CHECK: load i32, i32* %{{.*}}, !invariant.load !3
+; CHECK: load i32, i32* %{{.*}}, !invariant.load !5
 entry:
-  %l = load float, float* %ptr, !invariant.load !3
+  %l = load float, float* %ptr, !invariant.load !6
   %c = bitcast float %l to i32
   ret i32 %c
 }
@@ -50,9 +50,9 @@ define i32 @test_load_cast_combine_nontemporal(float* %ptr) {
 ; Ensure (cast (load (...))) -> (load (cast (...))) preserves nontemporal
 ; metadata.
 ; CHECK-LABEL: @test_load_cast_combine_nontemporal(
-; CHECK: load i32, i32* %{{.*}}, !nontemporal !4
+; CHECK: load i32, i32* %{{.*}}, !nontemporal !6
 entry:
-  %l = load float, float* %ptr, !nontemporal !4
+  %l = load float, float* %ptr, !nontemporal !7
   %c = bitcast float %l to i32
   ret i32 %c
 }
@@ -61,9 +61,9 @@ define i8* @test_load_cast_combine_align(i32** %ptr) {
 ; Ensure (cast (load (...))) -> (load (cast (...))) preserves align
 ; metadata.
 ; CHECK-LABEL: @test_load_cast_combine_align(
-; CHECK: load i8*, i8** %{{.*}}, !align !5
+; CHECK: load i8*, i8** %{{.*}}, !align !7
 entry:
-  %l = load i32*, i32** %ptr, !align !5
+  %l = load i32*, i32** %ptr, !align !8
   %c = bitcast i32* %l to i8*
   ret i8* %c
 }
@@ -72,9 +72,9 @@ define i8* @test_load_cast_combine_deref(i32** %ptr) {
 ; Ensure (cast (load (...))) -> (load (cast (...))) preserves dereferenceable
 ; metadata.
 ; CHECK-LABEL: @test_load_cast_combine_deref(
-; CHECK: load i8*, i8** %{{.*}}, !dereferenceable !5
+; CHECK: load i8*, i8** %{{.*}}, !dereferenceable !7
 entry:
-  %l = load i32*, i32** %ptr, !dereferenceable !5
+  %l = load i32*, i32** %ptr, !dereferenceable !8
   %c = bitcast i32* %l to i8*
   ret i8* %c
 }
@@ -83,9 +83,9 @@ define i8* @test_load_cast_combine_deref_or_null(i32** %ptr) {
 ; Ensure (cast (load (...))) -> (load (cast (...))) preserves
 ; dereferenceable_or_null metadata.
 ; CHECK-LABEL: @test_load_cast_combine_deref_or_null(
-; CHECK: load i8*, i8** %{{.*}}, !dereferenceable_or_null !5
+; CHECK: load i8*, i8** %{{.*}}, !dereferenceable_or_null !7
 entry:
-  %l = load i32*, i32** %ptr, !dereferenceable_or_null !5
+  %l = load i32*, i32** %ptr, !dereferenceable_or_null !8
   %c = bitcast i32* %l to i8*
   ret i8* %c
 }
@@ -94,7 +94,7 @@ define void @test_load_cast_combine_loop(float* %src, i32* %dst, i32 %n) {
 ; Ensure (cast (load (...))) -> (load (cast (...))) preserves loop access
 ; metadata.
 ; CHECK-LABEL: @test_load_cast_combine_loop(
-; CHECK: load i32, i32* %{{.*}}, !llvm.mem.parallel_loop_access !1
+; CHECK: load i32, i32* %{{.*}}, !llvm.mem.parallel_loop_access !4
 entry:
   br label %loop
 
@@ -102,7 +102,7 @@ loop:
   %i = phi i32 [ 0, %entry ], [ %i.next, %loop ]
   %src.gep = getelementptr inbounds float, float* %src, i32 %i
   %dst.gep = getelementptr inbounds i32, i32* %dst, i32 %i
-  %l = load float, float* %src.gep, !llvm.mem.parallel_loop_access !1
+  %l = load float, float* %src.gep, !llvm.mem.parallel_loop_access !4
   %c = bitcast float %l to i32
   store i32 %c, i32* %dst.gep
   %i.next = add i32 %i, 1
@@ -130,7 +130,7 @@ define void @test_load_cast_combine_nonnull(float** %ptr) {
 ; CHECK-NOT: !nonnull
 ; CHECK: store i64 %[[V]], i64*
 entry:
-  %p = load float*, float** %ptr, !nonnull !3
+  %p = load float*, float** %ptr, !nonnull !6
   %gep = getelementptr float*, float** %ptr, i32 42
   store float* %p, float** %gep
   ret void
@@ -138,10 +138,12 @@ entry:
 
 ; This is the metadata tuple that we reference above:
 ; CHECK: ![[MD]] = !{i64 1, i64 0}
-!0 = !{ !1, !1, i64 0 }
-!1 = !{ !1 }
-!2 = !{ !2, !1 }
-!3 = !{ }
-!4 = !{ i32 1 }
-!5 = !{ i64 8 }
-!6 = !{ i32 0, i32 42 }
+!0 = !{!1, !1, i64 0}
+!1 = !{!"scalar type", !2}
+!2 = !{!"root"}
+!3 = distinct !{!3, !4}
+!4 = distinct !{!4}
+!5 = !{i32 0, i32 42}
+!6 = !{}
+!7 = !{i32 1}
+!8 = !{i64 8}
index 707be7350139bc59fd178c694db2c809f8559b90..696a1643a71b1bc398c4fe2e3f35e4cdbce8b68f 100644 (file)
@@ -14,4 +14,5 @@ top:
 }
 
 !0 = !{!1, !1, i64 0}
-!1 = !{!"load_tbaa"}
+!1 = !{!"scalar type", !2}
+!2 = !{!"load_tbaa"}
index 71f5538c173c4ae921372b036aa5fc42addd4cda..f54672d1956695eee0ae7d5bed34e1da113a9859 100644 (file)
@@ -304,7 +304,7 @@ ret2:
 
 !0 = !{!3, !3, i64 0}
 !1 = !{!"omnipotent char", !2}
-!2 = !{!"Simple C/C++ TBAA", null}
+!2 = !{!"Simple C/C++ TBAA"}
 !3 = !{!"int", !1}
 !4 = !{ i32 0, i32 1 }
 !5 = !{ i32 8, i32 10 }
index 370491eab9804b535a19ea26f436ad6935f002e9..ede773f5f039c253de43b0cf46cb26468f2ceb4f 100644 (file)
@@ -32,7 +32,7 @@ for.end:                                          ; preds = %for.inc
 
 !0 = !{!5, !5, i64 0}
 !1 = !{!"omnipotent char", !2}
-!2 = !{!"Simple C/C++ TBAA", null}
+!2 = !{!"Simple C/C++ TBAA"}
 !3 = !{!"short", !1}
 !4 = !{!6, !6, i64 0}
 !5 = !{!"any pointer", !1}
index 78af9960e0641f8d85686bed0e2b2e59cfe932b4..3be22d708dac55bcc47320301040ae8a3b06bb8c 100644 (file)
@@ -32,6 +32,6 @@ exit:
 !6 = !{!"omnipotent char", !7, i64 0}
 !7 = !{!"Simple C/C++ TBAA"}
 !8 = !{!9, !5, i64 0}
-!9 = !{!5, i64 0, !10, i64 4}
+!9 = !{!"some struct", !5, i64 0, !10, i64 4}
 !10 = !{!"int", !6, i64 0}
 !11 = !{!9, !10, i64 4}
index 14a8b35f550af0e8b721e37738e466fcef8f818a..916772ca8ccd55422c4eac3563ac90ca86c571af 100644 (file)
@@ -1,4 +1,4 @@
-; RUN: opt < %s -basicaa -slp-vectorizer -S -mtriple=x86_64-apple-macosx10.8.0 -mcpu=corei7
+; RUN: opt < %s -basicaa -disable-verify -slp-vectorizer -S -mtriple=x86_64-apple-macosx10.8.0 -mcpu=corei7
 
 target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
 target triple = "x86_64-apple-darwin13.3.0"
index 686a535a32d9de7c96872a7c9eb56687412eb7fe..f82cbd71c294c13aff877766d2bd01874a227443 100644 (file)
@@ -106,7 +106,7 @@ bb0:
   %tmp1 = icmp eq i8 %tmp, 0
   br i1 %tmp1, label %bb2, label %bb1
 bb1:
-  %tmp3 = load i8, i8* %r, align 1, !range !2, !tbaa !1, !dbg !5
+  %tmp3 = load i8, i8* %r, align 1, !range !2, !tbaa !10, !dbg !5
   %tmp4 = icmp eq i8 %tmp3, 1
   br i1 %tmp4, label %bb2, label %bb3
 bb2:
@@ -120,7 +120,7 @@ declare i8 @test6g(i8*)
 !llvm.dbg.cu = !{!3}
 !llvm.module.flags = !{!8, !9}
 
-!0 = !{!1, !1, i64 0}
+!0 = !{!10, !10, i64 0}
 !1 = !{!"foo"}
 !2 = !{i8 0, i8 2}
 !3 = distinct !DICompileUnit(language: DW_LANG_C99, file: !7, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !4)
@@ -130,3 +130,4 @@ declare i8 @test6g(i8*)
 !7 = !DIFile(filename: "foo.c", directory: "/")
 !8 = !{i32 2, !"Dwarf Version", i32 2}
 !9 = !{i32 2, !"Debug Info Version", i32 3}
+!10 = !{!"scalar type", !1}
index 08efbe47ccfe4568e499b291672586fcbfadb34f..397925dbb645bbf7f8ed24f5308191449b12906f 100644 (file)
@@ -32,5 +32,6 @@ attributes #1 = { nounwind readnone }
 !5 = !DICompositeType(tag: DW_TAG_class_type, scope: !4, file: !1, line: 25, size: 8, align: 8)
 !6 = !DIExpression()
 !7 = !DILocation(line: 25, column: 8, scope: !4)
-!8 = !{!9, !9, i64 0}
+!8 = !{!10, !10, i64 0}
 !9 = !{i64 0}
+!10 = !{!"scalar type", !9}
diff --git a/test/Verifier/tbaa.ll b/test/Verifier/tbaa.ll
new file mode 100644 (file)
index 0000000..6c6b9d1
--- /dev/null
@@ -0,0 +1,109 @@
+; RUN: not llvm-as < %s 2>&1 | FileCheck %s
+
+define void @f_0(i32* %ptr) {
+; This part checks for the easy syntactic verifier rules.
+
+; CHECK: Struct tag metadata must have either 3 or 4 operands
+; CHECK-NEXT:  store i32 0, i32* %ptr, !tbaa !{{[0-9]+}}
+
+; CHECK: Immutability tag on struct tag metadata must be a constant
+; CHECK-NEXT:  store i32 1, i32* %ptr, !tbaa !{{[0-9]+}}
+
+; CHECK: Immutability part of the struct tag metadata must be either 0 or 1
+; CHECK-NEXT:  store i32 2, i32* %ptr, !tbaa !{{[0-9]+}}
+
+; CHECK: Offset must be constant integer
+; CHECK-NEXT:  store i32 3, i32* %ptr, !tbaa !{{[0-9]+}}
+
+; CHECK: Malformed struct tag metadata:  base and access-type should be non-null and point to Metadata nodes
+; CHECK-NEXT:  store i32 4, i32* %ptr, !tbaa !{{[0-9]+}}
+
+; CHECK: Access type node must be scalar
+; CHECK-NEXT:  store i32 5, i32* %ptr, !tbaa !{{[0-9]+}}
+
+; CHECK: Access bit-width not the same as description bit-width
+; CHECK-NEXT:  store i32 6, i32* %ptr, !tbaa !{{[0-9]+}}
+
+; CHECK: Access type node must be scalar
+; CHECK-NEXT:  store i32 7, i32* %ptr, !tbaa !{{[0-9]+}}
+
+  store i32 0, i32* %ptr, !tbaa !{!3, !2, i64 40, i64 0, i64 1, i64 2}
+  store i32 1, i32* %ptr, !tbaa !{!3, !2, i64 40, !"immutable"}
+  store i32 2, i32* %ptr, !tbaa !{!3, !2, i64 40, i64 4}
+  store i32 3, i32* %ptr, !tbaa !{!3, !2, !"40", i64 0}
+  store i32 4, i32* %ptr, !tbaa !{!3, null, !"40", i64 0}
+  store i32 5, i32* %ptr, !tbaa !{!3, !3, !"40", i64 0}
+  store i32 6, i32* %ptr, !tbaa !{!3, !2, i32 40, i64 0}
+  store i32 7, i32* %ptr, !tbaa !{!3, !12, i32 40, i64 0}
+  ret void
+}
+
+
+define void @f_1(i32* %ptr) {
+; This part checks for more semantic verifier rules.
+
+; CHECK: Cycle detected in struct path
+; CHECK-NEXT:  store i32 0, i32* %ptr, !tbaa !{{[0-9]+}}
+
+; CHECK: Offset not zero at the point of scalar access
+; CHECK-NEXT:  store i32 1, i32* %ptr, !tbaa !{{[0-9]+}}
+
+; CHECK: Offset not zero at the point of scalar access
+; CHECK-NEXT:  store i32 2, i32* %ptr, !tbaa !{{[0-9]+}}
+
+; CHECK: Could not find TBAA parent in struct type node
+; CHECK-NEXT:  store i32 3, i32* %ptr, !tbaa !{{[0-9]+}}
+
+; CHECK: Did not see access type in access path!
+; CHECK-NEXT:  store i32 3, i32* %ptr, !tbaa !{{[0-9]+}}
+
+; CHECK: Invalid parent operand in scalar TBAA node
+; CHECK-NEXT:  store i32 4, i32* %ptr, !tbaa !{{[0-9]+}}
+
+; CHECK: Invalid name operand in scalar TBAA node
+; CHECK-NEXT:  store i32 5, i32* %ptr, !tbaa !{{[0-9]+}}
+
+; CHECK: Null operands in scalar type nodes!
+; CHECK-NEXT:  store i32 6, i32* %ptr, !tbaa !{{[0-9]+}}
+
+; CHECK: Struct tag nodes must have an odd number of operands!
+; CHECK-NEXT:!{{[0-9]+}} = !{!"bad-struct-type-0", !{{[0-9]+}}, i64 40, !{{[0-9]+}}}
+
+; CHECK: Incorrect field entry in struct type node!
+; CHECK-NEXT:  store i32 8, i32* %ptr, !tbaa !{{[0-9]+}}
+
+; CHECK: Bitwidth between the offsets and struct type entries must match
+; CHECK-NEXT:  store i32 9, i32* %ptr, !tbaa !{{[0-9]+}}
+
+; CHECK: Offsets must be increasing!
+; CHECK-NEXT:  store i32 10, i32* %ptr, !tbaa !{{[0-9]+}}
+
+  store i32 0, i32* %ptr, !tbaa !{!4, !2, i64 40}
+  store i32 1, i32* %ptr, !tbaa !{!3, !2, i64 45}
+  store i32 2, i32* %ptr, !tbaa !{!3, !2, i64 45}
+  store i32 3, i32* %ptr, !tbaa !{!3, !2, i64 10}
+  store i32 4, i32* %ptr, !tbaa !{!5, !5, i64 0}
+  store i32 5, i32* %ptr, !tbaa !{!6, !6, i64 0}
+  store i32 6, i32* %ptr, !tbaa !{!7, !7, i64 0}
+  store i32 7, i32* %ptr, !tbaa !{!8, !1, i64 40}
+  store i32 8, i32* %ptr, !tbaa !{!9, !1, i64 40}
+  store i32 9, i32* %ptr, !tbaa !{!10, !1, i64 40}
+  store i32 10, i32* %ptr, !tbaa !{!11, !1, i64 40}
+  ret void
+}
+
+
+
+!0 = !{!"root"}
+!1 = !{!"scalar-a", !0}
+!2 = !{!"scalar-b", !0}
+!3 = !{!"struct-a", !2, i64 20, !1, i64 40}
+!4 = distinct !{!"self-recursive-struct", !2, i64 20, !4, i64 40}
+!5 = !{!"bad-scalar-0", i64 40}
+!6 = !{i64 42, !0}
+!7 = !{!"bad-scalar-1", null}
+!8 = !{!"bad-struct-type-0", !1, i64 40, !1}
+!9 = !{!"bad-struct-type-1", !1, i64 40, i64 56, !1}
+!10 = !{!"bad-struct-type-2", !1, i64 40, !1, i32 56}
+!11 = !{!"bad-struct-type-2", !1, i64 80, !1, i64 56}
+!12 = !{!"bad-scalar-2", !3, i64 0}