[llvm] [AutoUpgrade] Upgrade old-style !tbaa.struct field tags (PR #225967)

via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 23 15:52:12 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-ir

Author: Abhay Kanhere (AbhayKanhere)

<details>
<summary>Changes</summary>

Extend the TBAA auto-upgrade to rewrite old-style scalar field tags inside !tbaa.struct 
to the struct-path aware format, on both the textual (LLParser) and bitcode (MetadataLoader) 
paths, matching the existing top-level !tbaa upgrade.

---
Full diff: https://github.com/llvm/llvm-project/pull/225967.diff


6 Files Affected:

- (modified) llvm/include/llvm/AsmParser/LLParser.h (+1) 
- (modified) llvm/include/llvm/IR/AutoUpgrade.h (+5) 
- (modified) llvm/lib/AsmParser/LLParser.cpp (+10) 
- (modified) llvm/lib/Bitcode/Reader/MetadataLoader.cpp (+3) 
- (modified) llvm/lib/IR/AutoUpgrade.cpp (+22) 
- (added) llvm/test/Bitcode/upgrade-tbaa-struct.ll (+46) 


``````````diff
diff --git a/llvm/include/llvm/AsmParser/LLParser.h b/llvm/include/llvm/AsmParser/LLParser.h
index 7cc8e9877bbd0..ccd8b61b119e3 100644
--- a/llvm/include/llvm/AsmParser/LLParser.h
+++ b/llvm/include/llvm/AsmParser/LLParser.h
@@ -120,6 +120,7 @@ namespace llvm {
     SlotMapping *Slots;
 
     SmallVector<Instruction*, 64> InstsWithTBAATag;
+    SmallVector<Instruction *, 64> InstsWithTBAAStructTag;
 
     /// DIAssignID metadata does not support temporary RAUW so we cannot use
     /// the normal metadata forward reference resolution method. Instead,
diff --git a/llvm/include/llvm/IR/AutoUpgrade.h b/llvm/include/llvm/IR/AutoUpgrade.h
index 53da20d63a7f1..b129994885b2d 100644
--- a/llvm/include/llvm/IR/AutoUpgrade.h
+++ b/llvm/include/llvm/IR/AutoUpgrade.h
@@ -85,6 +85,11 @@ namespace llvm {
   /// Otherwise return the \p TBAANode itself.
   LLVM_ABI MDNode *UpgradeTBAANode(MDNode &TBAANode);
 
+  /// If the given !tbaa.struct node has old-style scalar field tags, return an
+  /// equivalent node with each field tag upgraded to the struct-path aware
+  /// format. Otherwise return the node itself.
+  LLVM_ABI MDNode *UpgradeTBAAStructNode(MDNode &TBAAStructNode);
+
   /// This is an auto-upgrade for bitcast between pointers with different
   /// address spaces: the instruction is replaced by a pair ptrtoint+inttoptr.
   LLVM_ABI Instruction *UpgradeBitCastInst(unsigned Opc, Value *V, Type *DestTy,
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index cc7633894fb74..30da28a7f0193 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -550,6 +550,14 @@ bool LLParser::validateEndOfModule(bool UpgradeDebugInfo) {
     }
   }
 
+  for (auto *Inst : InstsWithTBAAStructTag) {
+    MDNode *MD = Inst->getMetadata(LLVMContext::MD_tbaa_struct);
+    if (!MD)
+      continue;
+    if (MDNode *Upgraded = UpgradeTBAAStructNode(*MD); Upgraded != MD)
+      Inst->setMetadata(LLVMContext::MD_tbaa_struct, Upgraded);
+  }
+
   // Look for intrinsic functions and CallInst that need to be upgraded.  We use
   // make_early_inc_range here because we may remove some functions.
   for (Function &F : llvm::make_early_inc_range(*M))
@@ -2554,6 +2562,8 @@ bool LLParser::parseInstructionMetadata(Instruction &Inst) {
 
     if (MDK == LLVMContext::MD_tbaa)
       InstsWithTBAATag.push_back(&Inst);
+    else if (MDK == LLVMContext::MD_tbaa_struct)
+      InstsWithTBAAStructTag.push_back(&Inst);
 
     // If this is the end of the list, we're done.
   } while (EatIfPresent(lltok::comma));
diff --git a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp
index 6f1fbd627edbc..80e44634d6f95 100644
--- a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp
+++ b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp
@@ -2647,6 +2647,9 @@ Error MetadataLoader::MetadataLoaderImpl::parseMetadataAttachment(
         if (I->second == LLVMContext::MD_tbaa) {
           assert(!MD->isTemporary() && "should load MDs before attachments");
           MD = UpgradeTBAANode(*MD);
+        } else if (I->second == LLVMContext::MD_tbaa_struct) {
+          assert(!MD->isTemporary() && "should load MDs before attachments");
+          MD = UpgradeTBAAStructNode(*MD);
         }
         Inst->setMetadata(I->second, MD);
       }
diff --git a/llvm/lib/IR/AutoUpgrade.cpp b/llvm/lib/IR/AutoUpgrade.cpp
index 16751a4954844..5e50ca23be37c 100644
--- a/llvm/lib/IR/AutoUpgrade.cpp
+++ b/llvm/lib/IR/AutoUpgrade.cpp
@@ -6655,6 +6655,28 @@ MDNode *llvm::UpgradeTBAANode(MDNode &MD) {
   return MDNode::get(Context, Elts);
 }
 
+MDNode *llvm::UpgradeTBAAStructNode(MDNode &MD) {
+  // !tbaa.struct is a list of (offset, size, tag) triples. Upgrade any
+  // old-style scalar field tag to struct-path form via UpgradeTBAANode.
+  unsigned NumOperands = MD.getNumOperands();
+  if (NumOperands == 0 || NumOperands % 3 != 0)
+    return &MD; // Malformed; leave it for the verifier to reject.
+
+  SmallVector<Metadata *, 12> Elts(MD.op_begin(), MD.op_end());
+  bool Changed = false;
+  for (unsigned I = 2; I < NumOperands; I += 3) {
+    auto *Tag = dyn_cast_or_null<MDNode>(Elts[I]);
+    if (!Tag)
+      continue;
+    MDNode *Upgraded = UpgradeTBAANode(*Tag);
+    if (Upgraded == Tag)
+      continue;
+    Elts[I] = Upgraded;
+    Changed = true;
+  }
+  return Changed ? MDNode::get(MD.getContext(), Elts) : &MD;
+}
+
 Instruction *llvm::UpgradeBitCastInst(unsigned Opc, Value *V, Type *DestTy,
                                       Instruction *&Temp) {
   if (Opc != Instruction::BitCast)
diff --git a/llvm/test/Bitcode/upgrade-tbaa-struct.ll b/llvm/test/Bitcode/upgrade-tbaa-struct.ll
new file mode 100644
index 0000000000000..6e4cf0cced95e
--- /dev/null
+++ b/llvm/test/Bitcode/upgrade-tbaa-struct.ll
@@ -0,0 +1,46 @@
+; RUN: llvm-as < %s | llvm-dis | FileCheck %s
+; RUN: verify-uselistorder < %s
+
+; Old-style scalar tags used as !tbaa.struct field tags are auto-upgraded to
+; the struct-path aware format, like top-level !tbaa. Null and already
+; struct-path field tags are left unchanged; an immutability flag is kept.
+
+define void @copy(ptr %a, ptr %b) {
+  call void @llvm.memcpy.p0.p0.i64(ptr %a, ptr %b, i64 12, i1 false), !tbaa.struct !0
+; CHECK: !tbaa.struct [[TS:![0-9]+]]
+  ret void
+}
+
+define void @copy_flag_and_structpath(ptr %a, ptr %b) {
+  call void @llvm.memcpy.p0.p0.i64(ptr %a, ptr %b, i64 8, i1 false), !tbaa.struct !5
+; CHECK: !tbaa.struct [[TS2:![0-9]+]]
+  ret void
+}
+
+declare void @llvm.memcpy.p0.p0.i64(ptr, ptr, i64, i1)
+
+; Old-style 2-operand scalar field tags and a null field tag.
+!0 = !{i64 0, i64 4, !1, i64 4, i64 4, !3, i64 8, i64 4, null}
+!1 = !{!"int", !2}
+!2 = !{!"omnipotent char", !4}
+!3 = !{!"float", !2}
+!4 = !{!"Simple C/C++ TBAA"}
+
+; Old-style 3-operand (immutable) field tag and an already struct-path field tag.
+!5 = !{i64 0, i64 4, !6, i64 4, i64 4, !7}
+!6 = !{!"const int", !2, i64 1}
+!7 = !{!8, !8, i64 0}
+!8 = !{!"double", !2}
+
+; CHECK: [[TS]] = !{i64 0, i64 4, [[TAG_INT:![0-9]+]], i64 4, i64 4, [[TAG_FLOAT:![0-9]+]], i64 8, i64 4, null}
+; CHECK: [[TAG_INT]] = !{[[TYPE_INT:![0-9]+]], [[TYPE_INT]], i64 0}
+; CHECK: [[TYPE_INT]] = !{!"int", [[TYPE_CHAR:![0-9]+]]}
+; CHECK: [[TYPE_CHAR]] = !{!"omnipotent char", !{{[0-9]+}}}
+; CHECK: [[TAG_FLOAT]] = !{[[TYPE_FLOAT:![0-9]+]], [[TYPE_FLOAT]], i64 0}
+; CHECK: [[TYPE_FLOAT]] = !{!"float", [[TYPE_CHAR]]}
+; The immutability flag (i64 1) is preserved; the already struct-path tag is unchanged.
+; CHECK: [[TS2]] = !{i64 0, i64 4, [[TAG_CONST:![0-9]+]], i64 4, i64 4, [[TAG_DOUBLE:![0-9]+]]}
+; CHECK: [[TAG_CONST]] = !{[[TYPE_CONST:![0-9]+]], [[TYPE_CONST]], i64 0, i64 1}
+; CHECK: [[TYPE_CONST]] = !{!"const int", [[TYPE_CHAR]]}
+; CHECK: [[TAG_DOUBLE]] = !{[[TYPE_DOUBLE:![0-9]+]], [[TYPE_DOUBLE]], i64 0}
+; CHECK: [[TYPE_DOUBLE]] = !{!"double", [[TYPE_CHAR]]}

``````````

</details>


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


More information about the llvm-commits mailing list