[llvm-branch-commits] [mlir] [MLIR][LLVM] Preserve global value metadata operands on import (PR #203017)

Akimasa Watanuki via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Fri Jun 12 09:06:30 PDT 2026


https://github.com/Men-cotton updated https://github.com/llvm/llvm-project/pull/203017

>From 4e26843bccb767cc3d7c938722888ebd705b0e63 Mon Sep 17 00:00:00 2001
From: mencotton <mencotton0410 at gmail.com>
Date: Wed, 10 Jun 2026 00:46:12 +0900
Subject: [PATCH] [MLIR][LLVM] Preserve global value metadata operands on
 import

Import global value references inside LLVM metadata operands as LLVM dialect metadata symbol-reference attributes. Add llvm.read_register import coverage for function, global, alias, and nameless-global metadata operands.
---
 mlir/lib/Target/LLVMIR/ModuleImport.cpp       | 61 +++++++++++---
 .../Target/LLVMIR/Import/import-failure.ll    | 45 +++++++++++
 .../LLVMIR/Import/intrinsic-unregistered.ll   | 80 +++++++++++++++++--
 3 files changed, 169 insertions(+), 17 deletions(-)

diff --git a/mlir/lib/Target/LLVMIR/ModuleImport.cpp b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
index f6b12c91fba4d..def83537df2f8 100644
--- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
@@ -150,6 +150,28 @@ static LogicalResult convertInstructionImpl(OpBuilder &odsBuilder,
   return failure();
 }
 
+static FlatSymbolRefAttr getMetadataGlobalValueSymbolRef(
+    MLIRContext *ctx, LLVMImportInterface &iface, llvm::GlobalValue *global,
+    llvm::function_ref<FlatSymbolRefAttr(llvm::GlobalVariable *)>
+        getNamelessGlobalSymbol) {
+  if (auto *globalVar = dyn_cast<llvm::GlobalVariable>(global)) {
+    StringRef name = globalVar->getName();
+    if (name.empty())
+      return getNamelessGlobalSymbol(globalVar);
+    if (name == getGlobalCtorsVarName() || name == getGlobalDtorsVarName())
+      return {};
+  }
+
+  if (auto *func = dyn_cast<llvm::Function>(global))
+    if (func->isIntrinsic() &&
+        iface.isConvertibleIntrinsic(func->getIntrinsicID()))
+      return {};
+
+  if (global->getName().empty())
+    return {};
+  return FlatSymbolRefAttr::get(ctx, global->getName());
+}
+
 /// Depth-first conversion of the metadata node `md` to the matching LLVM
 /// dialect metadata attribute. Returns a null attribute for shapes that the
 /// dialect's metadata-attribute hierarchy does not currently model. `path`
@@ -162,23 +184,30 @@ static LogicalResult convertInstructionImpl(OpBuilder &odsBuilder,
 static Attribute convertMetadataToAttrImpl(
     MLIRContext *ctx, const llvm::Metadata *md,
     SmallPtrSetImpl<const llvm::Metadata *> &path,
-    DenseMap<const llvm::Metadata *, Attribute> &attrMap) {
+    DenseMap<const llvm::Metadata *, Attribute> &attrMap,
+    LLVMImportInterface &iface,
+    llvm::function_ref<FlatSymbolRefAttr(llvm::GlobalVariable *)>
+        getNamelessGlobalSymbol) {
   if (!md)
     return {};
   if (auto *mdStr = dyn_cast<llvm::MDString>(md))
     return MDStringAttr::get(ctx, StringAttr::get(ctx, mdStr->getString()));
   if (auto *cam = dyn_cast<llvm::ConstantAsMetadata>(md)) {
-    auto *ci = dyn_cast<llvm::ConstantInt>(cam->getValue());
+    llvm::Constant *constant = cam->getValue();
+    if (auto *global = dyn_cast<llvm::GlobalValue>(constant))
+      if (FlatSymbolRefAttr symbolRef = getMetadataGlobalValueSymbolRef(
+              ctx, iface, global, getNamelessGlobalSymbol))
+        return MDValueAttr::get(ctx, symbolRef);
+    auto *ci = dyn_cast<llvm::ConstantInt>(constant);
     if (!ci)
       return {};
     auto intType = IntegerType::get(ctx, ci->getBitWidth());
     return MDConstantAttr::get(ctx, IntegerAttr::get(intType, ci->getValue()));
   }
   if (auto *vam = dyn_cast<llvm::ValueAsMetadata>(md)) {
-    auto *fn = dyn_cast<llvm::Function>(vam->getValue());
-    if (!fn)
-      return {};
-    return MDValueAttr::get(ctx, FlatSymbolRefAttr::get(ctx, fn->getName()));
+    if (isa<llvm::GlobalValue>(vam->getValue()))
+      llvm_unreachable("global values should be ConstantAsMetadata");
+    return {};
   }
   if (auto *node = dyn_cast<llvm::MDNode>(md)) {
     if (Attribute cached = attrMap.lookup(node))
@@ -190,8 +219,8 @@ static Attribute convertMetadataToAttrImpl(
     SmallVector<Attribute> operands;
     operands.reserve(node->getNumOperands());
     for (const llvm::MDOperand &op : node->operands()) {
-      Attribute opAttr =
-          convertMetadataToAttrImpl(ctx, op.get(), path, attrMap);
+      Attribute opAttr = convertMetadataToAttrImpl(
+          ctx, op.get(), path, attrMap, iface, getNamelessGlobalSymbol);
       if (!opAttr)
         return {};
       operands.push_back(opAttr);
@@ -208,11 +237,14 @@ static Attribute convertMetadataToAttrImpl(
 /// attribute. Returns a null attribute for shapes that the dialect's
 /// metadata-attribute hierarchy does not currently model, including cyclic
 /// metadata graphs that the immutable metadata attributes cannot express.
-static Attribute convertMetadataToAttr(MLIRContext *ctx,
-                                       const llvm::Metadata *md) {
+static Attribute convertMetadataToAttr(
+    MLIRContext *ctx, const llvm::Metadata *md, LLVMImportInterface &iface,
+    llvm::function_ref<FlatSymbolRefAttr(llvm::GlobalVariable *)>
+        getNamelessGlobalSymbol) {
   SmallPtrSet<const llvm::Metadata *, 8> path;
   DenseMap<const llvm::Metadata *, Attribute> attrMap;
-  return convertMetadataToAttrImpl(ctx, md, path, attrMap);
+  return convertMetadataToAttrImpl(ctx, md, path, attrMap, iface,
+                                   getNamelessGlobalSymbol);
 }
 
 /// Get a topologically sorted list of blocks for the given basic blocks.
@@ -1982,7 +2014,12 @@ FailureOr<Value> ModuleImport::convertValue(llvm::Value *value) {
   // attribute.
   if (auto *mdAsVal = dyn_cast<llvm::MetadataAsValue>(value)) {
     llvm::Metadata *md = mdAsVal->getMetadata();
-    Attribute mdAttr = convertMetadataToAttr(context, md);
+    auto getNamelessGlobalSymbol =
+        [this](llvm::GlobalVariable *globalVar) -> FlatSymbolRefAttr {
+      return getOrCreateNamelessSymbolName(globalVar);
+    };
+    Attribute mdAttr =
+        convertMetadataToAttr(context, md, iface, getNamelessGlobalSymbol);
     if (!mdAttr)
       return emitError(mlirModule.getLoc())
              << "unsupported metadata: " << diagMD(md, llvmModule.get());
diff --git a/mlir/test/Target/LLVMIR/Import/import-failure.ll b/mlir/test/Target/LLVMIR/Import/import-failure.ll
index 57c8438bfd362..04c26d571f2e9 100644
--- a/mlir/test/Target/LLVMIR/Import/import-failure.ll
+++ b/mlir/test/Target/LLVMIR/Import/import-failure.ll
@@ -468,3 +468,48 @@ define i32 @cyclic_metadata_as_value() {
 }
 
 !0 = distinct !{!0}
+
+; // -----
+
+; CHECK: error: unsupported metadata: ptr @llvm.memcpy.p0.p0.i64
+declare i32 @llvm.read_register.i32(metadata)
+declare void @llvm.memcpy.p0.p0.i64(ptr noalias writeonly, ptr noalias readonly, i64, i1 immarg)
+
+define i32 @skipped_intrinsic_metadata() {
+  %r = call i32 @llvm.read_register.i32(metadata !0)
+  ret i32 %r
+}
+
+!0 = !{ptr @llvm.memcpy.p0.p0.i64}
+
+; // -----
+
+; CHECK: error: unsupported metadata: ptr @llvm.global_ctors
+declare i32 @llvm.read_register.i32(metadata)
+define void @ctor() {
+  ret void
+}
+ at llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @ctor, ptr null }]
+
+define i32 @metadata_ref_global_ctors() {
+  %r = call i32 @llvm.read_register.i32(metadata !0)
+  ret i32 %r
+}
+
+!0 = !{ptr @llvm.global_ctors}
+
+; // -----
+
+; CHECK: error: unsupported metadata: ptr @llvm.global_dtors
+declare i32 @llvm.read_register.i32(metadata)
+define void @dtor() {
+  ret void
+}
+ at llvm.global_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @dtor, ptr null }]
+
+define i32 @metadata_ref_global_dtors() {
+  %r = call i32 @llvm.read_register.i32(metadata !0)
+  ret i32 %r
+}
+
+!0 = !{ptr @llvm.global_dtors}
diff --git a/mlir/test/Target/LLVMIR/Import/intrinsic-unregistered.ll b/mlir/test/Target/LLVMIR/Import/intrinsic-unregistered.ll
index da58d48d995be..eeabb313d106f 100644
--- a/mlir/test/Target/LLVMIR/Import/intrinsic-unregistered.ll
+++ b/mlir/test/Target/LLVMIR/Import/intrinsic-unregistered.ll
@@ -11,7 +11,6 @@ define dso_local void @t0(ptr %a) {
 ; CHECK-LABEL: llvm.func @t0
 ; CHECK:   llvm.call_intrinsic "llvm.aarch64.ldxr.p0"({{.*}}) : (!llvm.ptr {llvm.elementtype = i8}) -> i64
 ; CHECK:   llvm.return
-; CHECK: }
 
 ; // -----
 
@@ -22,10 +21,9 @@ define dso_local <8 x i8> @t1(<8 x i8> %lhs, <8 x i8> %rhs) {
   ret <8 x i8> %r
 }
 
-; CHECK: llvm.func @t1(%[[A0:.*]]: vector<8xi8>, %[[A1:.*]]: vector<8xi8>) -> vector<8xi8> {{.*}} {
+; CHECK: llvm.func @t1(%[[A0:.*]]: vector<8xi8>, %[[A1:.*]]: vector<8xi8>) -> vector<8xi8> {{.*}}
 ; CHECK:   %[[R:.*]] = llvm.call_intrinsic "llvm.aarch64.neon.uabd.v8i8"(%[[A0]], %[[A1]]) : (vector<8xi8>, vector<8xi8>) -> vector<8xi8>
 ; CHECK:   llvm.return %[[R]] : vector<8xi8>
-; CHECK: }
 
 ; // -----
 
@@ -36,10 +34,9 @@ define dso_local void @t2(<8 x i8> %lhs, <8 x i8> %rhs, ptr %a) {
   ret void
 }
 
-; CHECK: llvm.func @t2(%[[A0:.*]]: vector<8xi8>, %[[A1:.*]]: vector<8xi8>, %[[A2:.*]]: !llvm.ptr) {{.*}} {
+; CHECK: llvm.func @t2(%[[A0:.*]]: vector<8xi8>, %[[A1:.*]]: vector<8xi8>, %[[A2:.*]]: !llvm.ptr) {{.*}}
 ; CHECK:   llvm.call_intrinsic "llvm.aarch64.neon.st2.v8i8.p0"(%[[A0]], %[[A1]], %[[A2]]) : (vector<8xi8>, vector<8xi8>, !llvm.ptr) -> ()
 ; CHECK:   llvm.return
-; CHECK: }
 
 ; // -----
 
@@ -115,3 +112,76 @@ define i32 @read_named_register() {
 }
 
 !0 = !{!"sp"}
+
+; // -----
+
+declare i32 @llvm.read_register.i32(metadata)
+
+ at global = global i32 0
+
+; CHECK-LABEL: llvm.func @read_global_metadata
+define i32 @read_global_metadata() {
+  ; CHECK: %[[MD:.*]] = llvm.mlir.metadata_as_value #llvm.md_value<@global>
+  ; CHECK: llvm.call_intrinsic "llvm.read_register.i32"(%[[MD]]) : (!llvm.metadata) -> i32
+  %r = call i32 @llvm.read_register.i32(metadata !0)
+  ret i32 %r
+}
+
+!0 = !{ptr @global}
+
+; // -----
+
+declare i32 @llvm.read_register.i32(metadata)
+
+define void @alias_target() {
+  ret void
+}
+ at alias = alias void (), ptr @alias_target
+
+; CHECK-LABEL: llvm.func @read_alias_metadata
+define i32 @read_alias_metadata() {
+  ; CHECK: %[[MD:.*]] = llvm.mlir.metadata_as_value #llvm.md_value<@alias>
+  ; CHECK: llvm.call_intrinsic "llvm.read_register.i32"(%[[MD]]) : (!llvm.metadata) -> i32
+  %r = call i32 @llvm.read_register.i32(metadata !0)
+  ret i32 %r
+}
+
+!0 = !{ptr @alias}
+
+; // -----
+
+declare i32 @llvm.read_register.i32(metadata)
+
+ at ifunc = ifunc void (), ptr @ifunc_resolver
+define ptr @ifunc_resolver() {
+  ret ptr @ifunc_target
+}
+define void @ifunc_target() {
+  ret void
+}
+
+; CHECK-LABEL: llvm.func @read_ifunc_metadata
+define i32 @read_ifunc_metadata() {
+  ; CHECK: %[[MD:.*]] = llvm.mlir.metadata_as_value #llvm.md_value<@ifunc>
+  ; CHECK: llvm.call_intrinsic "llvm.read_register.i32"(%[[MD]]) : (!llvm.metadata) -> i32
+  %r = call i32 @llvm.read_register.i32(metadata !0)
+  ret i32 %r
+}
+
+!0 = !{ptr @ifunc}
+
+; // -----
+
+declare i32 @llvm.read_register.i32(metadata)
+
+ at 0 = global i32 0
+
+; CHECK-LABEL: llvm.func @read_nameless_global_metadata
+define i32 @read_nameless_global_metadata() {
+  ; CHECK: %[[MD:.*]] = llvm.mlir.metadata_as_value #llvm.md_value<@{{mlir\.llvm\.nameless_global_[0-9]+}}>
+  ; CHECK: llvm.call_intrinsic "llvm.read_register.i32"(%[[MD]]) : (!llvm.metadata) -> i32
+  %r = call i32 @llvm.read_register.i32(metadata !0)
+  ret i32 %r
+}
+
+!0 = !{ptr @0}



More information about the llvm-branch-commits mailing list