[Mlir-commits] [mlir] [mlir][LLVM] Preserve !associated and !absolute_symbol on llvm.mlir.global (PR #218839)
Tanishq Khurana
llvmlistbot at llvm.org
Sat Aug 29 18:40:41 PDT 2026
https://github.com/ktanishqk updated https://github.com/llvm/llvm-project/pull/218839
>From e4473d4ea20ef6e8b0e39049e14dd12dd76157ad Mon Sep 17 00:00:00 2001
From: ktanishqk <tanishqk0102 at gmail.com>
Date: Tue, 25 Aug 2026 22:27:03 -0700
Subject: [PATCH 1/5] tests + storage of metadata globals in dialect
---
mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td | 21 +++++++++
mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp | 21 +++++++++
mlir/lib/Target/LLVMIR/ModuleImport.cpp | 44 +++++++++++++++++++
mlir/lib/Target/LLVMIR/ModuleTranslation.cpp | 32 ++++++++++++++
mlir/test/Dialect/LLVMIR/global.mlir | 34 ++++++++++++++
.../Target/LLVMIR/Import/global-variables.ll | 42 ++++++++++++++++++
mlir/test/Target/LLVMIR/llvmir.mlir | 41 +++++++++++++++++
7 files changed, 235 insertions(+)
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
index 84f71054994f4..83bc0dad5d137 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
@@ -1393,6 +1393,8 @@ def LLVM_GlobalOp : LLVM_Op<"mlir.global",
DefaultValuedAttr<ConfinedAttr<I32Attr, [IntNonNegative]>, "0">:$addr_space,
OptionalAttr<UnnamedAddr>:$unnamed_addr,
OptionalAttr<StrAttr>:$section,
+ OptionalAttr<FlatSymbolRefAttr>:$associated,
+ OptionalAttr<ArrayAttr>:$absolute_symbol,
OptionalAttr<SymbolRefAttr>:$comdat,
OptionalAttr<DIGlobalVariableExpressionArrayAttr>:$dbg_exprs,
DefaultValuedAttr<Visibility, "mlir::LLVM::Visibility::Default">:$visibility_,
@@ -1494,6 +1496,25 @@ def LLVM_GlobalOp : LLVM_Op<"mlir.global",
llvm.mlir.global private constant @y(dense<1.0> : tensor<8xf32>) { alignment = 32 : i64 } : !llvm.array<8 x f32>
```
+ The optional `associated` attribute models LLVM IR `!associated` metadata
+ on a global. It is a symbol reference to another global object (or an
+ alias of one) and is used to emit `SHF_LINK_ORDER` on ELF.
+
+ The optional `absolute_symbol` attribute models LLVM IR `!absolute_symbol`
+ metadata. It is an array of integer attributes forming one or more
+ `[lower, upper)` range pairs for the global's address, using the same
+ encoding as LLVM `range` metadata. The pair `[-1, -1]` represents the
+ full set.
+
+ Examples:
+
+ ```mlir
+ llvm.mlir.global external @b(0 : i32) : i32
+ llvm.mlir.global external @a(0 : i32) {associated = @b} : i32
+
+ llvm.mlir.global external @abs_sym() {absolute_symbol = [0 : i64, 42 : i64]} : i8
+ ```
+
The `target_specific_attrs` attribute provides a mechanism to preserve
target-specific LLVM IR attributes that are not explicitly modeled in the
LLVM dialect.
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
index 6382dfcbc8ad2..3b2f7d129fb3a 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
@@ -2671,6 +2671,27 @@ LogicalResult GlobalOp::verify() {
return emitError() << "alignment attribute is not a power of 2";
}
+ if (FlatSymbolRefAttr associated = getAssociatedAttr()) {
+ if (associated.getValue() == getSymName())
+ return emitOpError("associated cannot refer to the global itself");
+ }
+
+ if (ArrayAttr absSym = getAbsoluteSymbolAttr()) {
+ if (absSym.empty() || absSym.size() % 2 != 0)
+ return emitOpError(
+ "absolute_symbol must contain one or more integer range pairs");
+ Type pairType;
+ for (Attribute attr : absSym) {
+ auto intAttr = dyn_cast<IntegerAttr>(attr);
+ if (!intAttr)
+ return emitOpError("absolute_symbol operands must be integers");
+ if (!pairType)
+ pairType = intAttr.getType();
+ else if (intAttr.getType() != pairType)
+ return emitOpError("absolute_symbol range pair types must match");
+ }
+ }
+
return success();
}
diff --git a/mlir/lib/Target/LLVMIR/ModuleImport.cpp b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
index 725d7cf6c8413..8730b5d67b901 100644
--- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
@@ -1648,6 +1648,50 @@ LogicalResult ModuleImport::convertGlobal(llvm::GlobalVariable *globalVar) {
if (globalVar->hasComdat())
globalOp.setComdatAttr(comdatMapping.lookup(globalVar->getComdat()));
+ if (llvm::MDNode *associatedMD =
+ globalVar->getMetadata(llvm::LLVMContext::MD_associated)) {
+ if (associatedMD->getNumOperands() == 1) {
+ if (auto *valueAsMD = dyn_cast_or_null<llvm::ValueAsMetadata>(
+ associatedMD->getOperand(0).get())) {
+ llvm::Value *value = valueAsMD->getValue();
+ llvm::GlobalValue *gv = dyn_cast<llvm::GlobalValue>(value);
+ if (!gv)
+ gv = dyn_cast<llvm::GlobalValue>(value->stripPointerCastsAndAliases());
+ if (gv) {
+ StringRef name = gv->getName();
+ FlatSymbolRefAttr symbolRef;
+ if (name.empty()) {
+ if (auto *namelessVar = dyn_cast<llvm::GlobalVariable>(gv))
+ symbolRef = getOrCreateNamelessSymbolName(namelessVar);
+ } else {
+ symbolRef = FlatSymbolRefAttr::get(context, name);
+ }
+ if (symbolRef)
+ globalOp.setAssociatedAttr(symbolRef);
+ }
+ }
+ }
+ }
+
+ if (llvm::MDNode *absSymMD =
+ globalVar->getMetadata(llvm::LLVMContext::MD_absolute_symbol)) {
+ SmallVector<Attribute> rangeAttrs;
+ rangeAttrs.reserve(absSymMD->getNumOperands());
+ bool valid = absSymMD->getNumOperands() >= 2 &&
+ absSymMD->getNumOperands() % 2 == 0;
+ for (const llvm::MDOperand &op : absSymMD->operands()) {
+ auto *constInt = llvm::mdconst::dyn_extract<llvm::ConstantInt>(op);
+ if (!constInt) {
+ valid = false;
+ break;
+ }
+ auto intType = IntegerType::get(context, constInt->getBitWidth());
+ rangeAttrs.push_back(IntegerAttr::get(intType, constInt->getValue()));
+ }
+ if (valid)
+ globalOp.setAbsoluteSymbolAttr(ArrayAttr::get(context, rangeAttrs));
+ }
+
processTargetSpecificAttrs(globalVar, globalOp);
return success();
diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
index 47e63e2aa279a..d6b5287d78bf2 100644
--- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
@@ -45,6 +45,7 @@
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/MDBuilder.h"
+#include "llvm/IR/Metadata.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
#include "llvm/Support/Debug.h"
@@ -1383,6 +1384,37 @@ LogicalResult ModuleTranslation::convertGlobalsAndAliases() {
aliasesMapping.try_emplace(op, var);
}
+ // Attach global metadata after all globals, aliases, and function signatures
+ // exist so symbol references can be resolved.
+ for (auto op : getModuleBody(mlirModule).getOps<LLVM::GlobalOp>()) {
+ auto *var = cast<llvm::GlobalVariable>(lookupGlobal(op));
+ if (FlatSymbolRefAttr associated = op.getAssociatedAttr()) {
+ auto mdAttr = MDGlobalValueAttr::get(op.getContext(), associated);
+ FailureOr<llvm::Metadata *> md = convertMetadataAttr(mdAttr, [&]() {
+ return op.emitError("failed to convert associated metadata");
+ });
+ if (failed(md))
+ return failure();
+ var->setMetadata(llvm::LLVMContext::MD_associated,
+ llvm::MDNode::get(var->getContext(), *md));
+ }
+
+ if (ArrayAttr absSym = op.getAbsoluteSymbolAttr()) {
+ SmallVector<llvm::Metadata *> mdOps;
+ llvm::LLVMContext &ctx = var->getContext();
+ mdOps.reserve(absSym.size());
+ for (Attribute attr : absSym) {
+ auto intAttr = llvm::cast<IntegerAttr>(attr);
+ llvm::IntegerType *ty = llvm::IntegerType::get(
+ ctx, intAttr.getType().getIntOrFloatBitWidth());
+ mdOps.push_back(llvm::ConstantAsMetadata::get(
+ llvm::ConstantInt::get(ty, intAttr.getValue())));
+ }
+ var->setMetadata(llvm::LLVMContext::MD_absolute_symbol,
+ llvm::MDNode::get(ctx, mdOps));
+ }
+ }
+
// Convert global variable bodies.
for (auto op : getModuleBody(mlirModule).getOps<LLVM::GlobalOp>()) {
if (Block *initializer = op.getInitializerBlock()) {
diff --git a/mlir/test/Dialect/LLVMIR/global.mlir b/mlir/test/Dialect/LLVMIR/global.mlir
index 193ab7987a2b6..a72dad1f796a5 100644
--- a/mlir/test/Dialect/LLVMIR/global.mlir
+++ b/mlir/test/Dialect/LLVMIR/global.mlir
@@ -292,3 +292,37 @@ llvm.mlir.global external @global_with_expr1() {addr_space = 0 : i32, dbg_expr =
llvm.mlir.global external @global_with_expr2() {addr_space = 0 : i32, dbg_expr = [#llvm.di_global_variable_expression<var = <scope = #di_compile_unit, name = "global_with_expr_2", linkageName = "global_with_expr_2", file = #di_file, line = 371, type = #di_basic_type, isLocalToUnit = true, isDefined = true, alignInBits = 8>, expr = <[DW_OP_push_object_address, DW_OP_deref]>>]} : i64
llvm.mlir.global external @global_with_expr3() {addr_space = 0 : i32, dbg_expr = [#llvm.di_global_variable_expression<var = <scope = #di_compile_unit, name = "global_with_expr_3", linkageName = "global_with_expr_3", file = #di_file, line = 372, type = #di_basic_type, isLocalToUnit = true, isDefined = true, alignInBits = 8>, expr = <[DW_OP_LLVM_arg(0), DW_OP_LLVM_arg(1), DW_OP_plus]>>]} : i64
llvm.mlir.global external @global_with_expr4() {addr_space = 0 : i32, dbg_expr = [#llvm.di_global_variable_expression<var = <scope = #di_compile_unit, name = "global_with_expr_4", linkageName = "global_with_expr_4", file = #di_file, line = 373, type = #di_basic_type, isLocalToUnit = true, isDefined = true, alignInBits = 8>, expr = <[DW_OP_LLVM_convert(16, DW_ATE_signed)]>>]} : i64
+
+// -----
+
+// CHECK: llvm.mlir.global external @associated_target(0 : i32) {addr_space = 0 : i32} : i32
+// CHECK: llvm.mlir.global external @associated_global(0 : i32) {addr_space = 0 : i32, associated = @associated_target} : i32
+llvm.mlir.global external @associated_target(0 : i32) : i32
+llvm.mlir.global external @associated_global(0 : i32) {associated = @associated_target} : i32
+
+// CHECK: llvm.mlir.global external @absolute_symbol_global() {absolute_symbol = [0, 42], addr_space = 0 : i32} : i8
+llvm.mlir.global external @absolute_symbol_global() {absolute_symbol = [0 : i64, 42 : i64]} : i8
+
+// CHECK: llvm.mlir.global external @absolute_symbol_full() {absolute_symbol = [-1, -1], addr_space = 0 : i32} : i8
+llvm.mlir.global external @absolute_symbol_full() {absolute_symbol = [-1 : i64, -1 : i64]} : i8
+
+// -----
+
+// expected-error @+1 {{associated cannot refer to the global itself}}
+llvm.mlir.global @self_associated(0 : i32) {associated = @self_associated} : i32
+
+// -----
+
+// expected-error @+1 {{absolute_symbol must contain one or more integer range pairs}}
+llvm.mlir.global @odd_absolute_symbol() {absolute_symbol = [0 : i64]} : i8
+
+// -----
+
+// expected-error @+1 {{absolute_symbol operands must be integers}}
+llvm.mlir.global @non_int_absolute_symbol() {absolute_symbol = ["foo", "bar"]} : i8
+
+// -----
+
+// expected-error @+1 {{absolute_symbol range pair types must match}}
+llvm.mlir.global @mixed_absolute_symbol() {absolute_symbol = [0 : i32, 42 : i64]} : i8
+
diff --git a/mlir/test/Target/LLVMIR/Import/global-variables.ll b/mlir/test/Target/LLVMIR/Import/global-variables.ll
index 2be36c4366304..1d49726fb8966 100644
--- a/mlir/test/Target/LLVMIR/Import/global-variables.ll
+++ b/mlir/test/Target/LLVMIR/Import/global-variables.ll
@@ -373,3 +373,45 @@ attributes #0 = { readnone "int-attr"="4" "no-enum-attr" "string-attr"="string"
; CHECK-SAME: target_specific_attrs = ["norecurse", ["bss-section", "my_bss.1"]]}
@target_specific_attrs_combined = global i32 2, align 4, section "mysection" #0
attributes #0 = { norecurse "bss-section"="my_bss.1" }
+
+; // -----
+
+; CHECK: llvm.mlir.global external @a
+; CHECK-SAME: {addr_space = 0 : i32, associated = @b} : i32
+; CHECK: llvm.mlir.global external @b
+; CHECK-SAME: {addr_space = 0 : i32} : i32
+ at a = global i32 0, !associated !0
+ at b = global i32 0
+!0 = !{ptr @b}
+
+; // -----
+
+; CHECK: llvm.mlir.global external @a
+; CHECK-SAME: {addr_space = 0 : i32, associated = @f} : i32
+ at a = global i32 0, !associated !0
+declare void @f()
+!0 = !{ptr @f}
+
+; // -----
+
+; CHECK: llvm.mlir.global external @associated_via_alias
+; CHECK-SAME: associated = @alias_of_target
+ at alias_target = global i32 1
+ at alias_of_target = alias i32, ptr @alias_target
+ at associated_via_alias = global i32 2, !associated !0
+!0 = !{ptr @alias_of_target}
+
+; // -----
+
+; CHECK: llvm.mlir.global external @a()
+; CHECK-SAME: {absolute_symbol = [0 : i64, 42 : i64], addr_space = 0 : i32} : i8
+ at a = external global i8, !absolute_symbol !0
+!0 = !{i64 0, i64 42}
+
+; // -----
+
+; CHECK: llvm.mlir.global external @a()
+; CHECK-SAME: {absolute_symbol = [-1 : i64, -1 : i64], addr_space = 0 : i32} : i8
+ at a = external global i8, !absolute_symbol !0
+!0 = !{i64 -1, i64 -1}
+
diff --git a/mlir/test/Target/LLVMIR/llvmir.mlir b/mlir/test/Target/LLVMIR/llvmir.mlir
index 5ffbb3eef7bb0..c00b69bdbeb3b 100644
--- a/mlir/test/Target/LLVMIR/llvmir.mlir
+++ b/mlir/test/Target/LLVMIR/llvmir.mlir
@@ -3633,6 +3633,47 @@ llvm.mlir.global external @target_specific_attrs_combined(2 : i32) {alignment =
// -----
+// CHECK: @associated_target = global i32 0
+// CHECK: @associated_global = global i32 0, !associated ![[ASSOC:[0-9]+]]
+// CHECK: ![[ASSOC]] = !{ptr @associated_target}
+llvm.mlir.global external @associated_target(0 : i32) {addr_space = 0 : i32} : i32
+llvm.mlir.global external @associated_global(0 : i32) {addr_space = 0 : i32, associated = @associated_target} : i32
+
+// -----
+
+// CHECK: @associated_fn_global = global i32 0, !associated ![[ASSOC_FN:[0-9]+]]
+// CHECK: declare void @associated_fn()
+// CHECK: ![[ASSOC_FN]] = !{ptr @associated_fn}
+llvm.mlir.global external @associated_fn_global(0 : i32) {associated = @associated_fn} : i32
+llvm.func @associated_fn()
+
+// -----
+
+// CHECK: @alias_target = global i32 1
+// CHECK: @associated_via_alias = global i32 2, !associated ![[ASSOC_ALIAS:[0-9]+]]
+// CHECK: @alias_of_target = alias i32, ptr @alias_target
+// CHECK: ![[ASSOC_ALIAS]] = !{ptr @alias_of_target}
+llvm.mlir.global @alias_target(1 : i32) : i32
+llvm.mlir.alias external @alias_of_target : i32 {
+ %0 = llvm.mlir.addressof @alias_target : !llvm.ptr
+ llvm.return %0 : !llvm.ptr
+}
+llvm.mlir.global @associated_via_alias(2 : i32) {associated = @alias_of_target} : i32
+
+// -----
+
+// CHECK: @absolute_symbol_global = external global i8, !absolute_symbol ![[ABS:[0-9]+]]
+// CHECK: ![[ABS]] = !{i64 0, i64 42}
+llvm.mlir.global external @absolute_symbol_global() {absolute_symbol = [0 : i64, 42 : i64]} : i8
+
+// -----
+
+// CHECK: @absolute_symbol_full = external global i8, !absolute_symbol ![[ABS_FULL:[0-9]+]]
+// CHECK: ![[ABS_FULL]] = !{i64 -1, i64 -1}
+llvm.mlir.global external @absolute_symbol_full() {absolute_symbol = [-1 : i64, -1 : i64]} : i8
+
+// -----
+
// CHECK-LABEL: define b8 @byte_type(b8 %0)
llvm.func @byte_type(%arg0: !llvm.byte<8>) -> !llvm.byte<8> {
llvm.return %arg0 : !llvm.byte<8>
>From 8c86d63c426d1ed6941a789ab0263de6fe36ccf1 Mon Sep 17 00:00:00 2001
From: ktanishqk <tanishqk0102 at gmail.com>
Date: Wed, 26 Aug 2026 08:55:43 -0700
Subject: [PATCH 2/5] export failure fix
---
.../mlir/Target/LLVMIR/ModuleTranslation.h | 7 ++
mlir/lib/Target/LLVMIR/ModuleImport.cpp | 7 +-
mlir/lib/Target/LLVMIR/ModuleTranslation.cpp | 68 ++++++++++---------
mlir/test/Dialect/LLVMIR/global.mlir | 9 +++
.../Target/LLVMIR/Import/global-variables.ll | 16 ++++-
mlir/test/Target/LLVMIR/llvmir.mlir | 12 ++++
6 files changed, 83 insertions(+), 36 deletions(-)
diff --git a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
index b23f78ff0f98a..59b48c6c1cc7c 100644
--- a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
+++ b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
@@ -427,7 +427,14 @@ class ModuleTranslation {
/// - Create named global variables that correspond to llvm.mlir.global
/// definitions, similarly Convert llvm.global_ctors and global_dtors ops.
/// - Create global alias that correspond to llvm.mlir.alias.
+ /// Global metadata that can reference other global objects (including
+ /// ifuncs) is converted later by `convertGlobalMetadata`.
LogicalResult convertGlobalsAndAliases();
+
+ /// Attach metadata on LLVM globals after all global objects exist so that
+ /// symbol references (globals, aliases, functions, and ifuncs) can be
+ /// resolved.
+ LogicalResult convertGlobalMetadata();
LogicalResult convertOneFunction(LLVMFuncOp func);
LogicalResult convertBlockImpl(Block &bb, bool ignoreArguments,
llvm::IRBuilderBase &builder,
diff --git a/mlir/lib/Target/LLVMIR/ModuleImport.cpp b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
index 8730b5d67b901..af93c0043da37 100644
--- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
@@ -1656,7 +1656,8 @@ LogicalResult ModuleImport::convertGlobal(llvm::GlobalVariable *globalVar) {
llvm::Value *value = valueAsMD->getValue();
llvm::GlobalValue *gv = dyn_cast<llvm::GlobalValue>(value);
if (!gv)
- gv = dyn_cast<llvm::GlobalValue>(value->stripPointerCastsAndAliases());
+ gv =
+ dyn_cast<llvm::GlobalValue>(value->stripPointerCastsAndAliases());
if (gv) {
StringRef name = gv->getName();
FlatSymbolRefAttr symbolRef;
@@ -1677,8 +1678,8 @@ LogicalResult ModuleImport::convertGlobal(llvm::GlobalVariable *globalVar) {
globalVar->getMetadata(llvm::LLVMContext::MD_absolute_symbol)) {
SmallVector<Attribute> rangeAttrs;
rangeAttrs.reserve(absSymMD->getNumOperands());
- bool valid = absSymMD->getNumOperands() >= 2 &&
- absSymMD->getNumOperands() % 2 == 0;
+ bool valid =
+ absSymMD->getNumOperands() >= 2 && absSymMD->getNumOperands() % 2 == 0;
for (const llvm::MDOperand &op : absSymMD->operands()) {
auto *constInt = llvm::mdconst::dyn_extract<llvm::ConstantInt>(op);
if (!constInt) {
diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
index d6b5287d78bf2..e0a6e704b2957 100644
--- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
@@ -1384,37 +1384,6 @@ LogicalResult ModuleTranslation::convertGlobalsAndAliases() {
aliasesMapping.try_emplace(op, var);
}
- // Attach global metadata after all globals, aliases, and function signatures
- // exist so symbol references can be resolved.
- for (auto op : getModuleBody(mlirModule).getOps<LLVM::GlobalOp>()) {
- auto *var = cast<llvm::GlobalVariable>(lookupGlobal(op));
- if (FlatSymbolRefAttr associated = op.getAssociatedAttr()) {
- auto mdAttr = MDGlobalValueAttr::get(op.getContext(), associated);
- FailureOr<llvm::Metadata *> md = convertMetadataAttr(mdAttr, [&]() {
- return op.emitError("failed to convert associated metadata");
- });
- if (failed(md))
- return failure();
- var->setMetadata(llvm::LLVMContext::MD_associated,
- llvm::MDNode::get(var->getContext(), *md));
- }
-
- if (ArrayAttr absSym = op.getAbsoluteSymbolAttr()) {
- SmallVector<llvm::Metadata *> mdOps;
- llvm::LLVMContext &ctx = var->getContext();
- mdOps.reserve(absSym.size());
- for (Attribute attr : absSym) {
- auto intAttr = llvm::cast<IntegerAttr>(attr);
- llvm::IntegerType *ty = llvm::IntegerType::get(
- ctx, intAttr.getType().getIntOrFloatBitWidth());
- mdOps.push_back(llvm::ConstantAsMetadata::get(
- llvm::ConstantInt::get(ty, intAttr.getValue())));
- }
- var->setMetadata(llvm::LLVMContext::MD_absolute_symbol,
- llvm::MDNode::get(ctx, mdOps));
- }
- }
-
// Convert global variable bodies.
for (auto op : getModuleBody(mlirModule).getOps<LLVM::GlobalOp>()) {
if (Block *initializer = op.getInitializerBlock()) {
@@ -2219,6 +2188,41 @@ LogicalResult ModuleTranslation::convertIFuncs() {
return success();
}
+// Attach global metadata after all globals, aliases, ifuncs, and function
+// signatures exist so symbol references can be resolved.
+LogicalResult ModuleTranslation::convertGlobalMetadata() {
+ for (auto op : getModuleBody(mlirModule).getOps<LLVM::GlobalOp>()) {
+ auto *var = cast<llvm::GlobalVariable>(lookupGlobal(op));
+ if (FlatSymbolRefAttr associated = op.getAssociatedAttr()) {
+ auto mdAttr = MDGlobalValueAttr::get(op.getContext(), associated);
+ FailureOr<llvm::Metadata *> md = convertMetadataAttr(mdAttr, [&]() {
+ return op.emitError("failed to convert associated metadata");
+ });
+ if (failed(md))
+ return failure();
+ var->setMetadata(llvm::LLVMContext::MD_associated,
+ llvm::MDNode::get(var->getContext(), *md));
+ }
+
+ if (ArrayAttr absSym = op.getAbsoluteSymbolAttr()) {
+ SmallVector<llvm::Metadata *> mdOps;
+ llvm::LLVMContext &ctx = var->getContext();
+ mdOps.reserve(absSym.size());
+ for (Attribute attr : absSym) {
+ auto intAttr = llvm::cast<IntegerAttr>(attr);
+ llvm::IntegerType *ty = llvm::IntegerType::get(
+ ctx, intAttr.getType().getIntOrFloatBitWidth());
+ mdOps.push_back(llvm::ConstantAsMetadata::get(
+ llvm::ConstantInt::get(ty, intAttr.getValue())));
+ }
+ var->setMetadata(llvm::LLVMContext::MD_absolute_symbol,
+ llvm::MDNode::get(ctx, mdOps));
+ }
+ }
+
+ return success();
+}
+
LogicalResult ModuleTranslation::convertComdats() {
for (auto comdatOp : getModuleBody(mlirModule).getOps<ComdatOp>()) {
for (auto selectorOp : comdatOp.getOps<ComdatSelectorOp>()) {
@@ -2678,6 +2682,8 @@ mlir::translateModuleToLLVMIR(Operation *module, llvm::LLVMContext &llvmContext,
return nullptr;
if (failed(translator.convertIFuncs()))
return nullptr;
+ if (failed(translator.convertGlobalMetadata()))
+ return nullptr;
if (failed(translator.createTBAAMetadata()))
return nullptr;
if (failed(translator.createIdentMetadata()))
diff --git a/mlir/test/Dialect/LLVMIR/global.mlir b/mlir/test/Dialect/LLVMIR/global.mlir
index a72dad1f796a5..37c7d433c5dd3 100644
--- a/mlir/test/Dialect/LLVMIR/global.mlir
+++ b/mlir/test/Dialect/LLVMIR/global.mlir
@@ -300,6 +300,15 @@ llvm.mlir.global external @global_with_expr4() {addr_space = 0 : i32, dbg_expr =
llvm.mlir.global external @associated_target(0 : i32) : i32
llvm.mlir.global external @associated_global(0 : i32) {associated = @associated_target} : i32
+// CHECK: llvm.mlir.global external @associated_ifunc_global(0 : i32) {addr_space = 0 : i32, associated = @associated_ifunc} : i32
+// CHECK: llvm.mlir.ifunc external @associated_ifunc : !llvm.func<i32 (i32)>, !llvm.ptr @associated_ifunc_resolver
+llvm.mlir.global external @associated_ifunc_global(0 : i32) {associated = @associated_ifunc} : i32
+llvm.mlir.ifunc external @associated_ifunc : !llvm.func<i32 (i32)>, !llvm.ptr @associated_ifunc_resolver
+llvm.func @associated_ifunc_resolver() -> !llvm.ptr {
+ %0 = llvm.mlir.zero : !llvm.ptr
+ llvm.return %0 : !llvm.ptr
+}
+
// CHECK: llvm.mlir.global external @absolute_symbol_global() {absolute_symbol = [0, 42], addr_space = 0 : i32} : i8
llvm.mlir.global external @absolute_symbol_global() {absolute_symbol = [0 : i64, 42 : i64]} : i8
diff --git a/mlir/test/Target/LLVMIR/Import/global-variables.ll b/mlir/test/Target/LLVMIR/Import/global-variables.ll
index 1d49726fb8966..5ca3c5a93e5ca 100644
--- a/mlir/test/Target/LLVMIR/Import/global-variables.ll
+++ b/mlir/test/Target/LLVMIR/Import/global-variables.ll
@@ -403,15 +403,27 @@ declare void @f()
; // -----
+; CHECK: llvm.mlir.global external @associated_ifunc_global
+; CHECK-SAME: associated = @associated_ifunc
+; CHECK: llvm.mlir.ifunc external @associated_ifunc
+ at associated_ifunc = ifunc i32 (i32), ptr @associated_ifunc_resolver
+ at associated_ifunc_global = global i32 0, !associated !0
+define ptr @associated_ifunc_resolver() {
+ ret ptr null
+}
+!0 = !{ptr @associated_ifunc}
+
+; // -----
+
; CHECK: llvm.mlir.global external @a()
-; CHECK-SAME: {absolute_symbol = [0 : i64, 42 : i64], addr_space = 0 : i32} : i8
+; CHECK-SAME: {absolute_symbol = [0, 42], addr_space = 0 : i32} : i8
@a = external global i8, !absolute_symbol !0
!0 = !{i64 0, i64 42}
; // -----
; CHECK: llvm.mlir.global external @a()
-; CHECK-SAME: {absolute_symbol = [-1 : i64, -1 : i64], addr_space = 0 : i32} : i8
+; CHECK-SAME: {absolute_symbol = [-1, -1], addr_space = 0 : i32} : i8
@a = external global i8, !absolute_symbol !0
!0 = !{i64 -1, i64 -1}
diff --git a/mlir/test/Target/LLVMIR/llvmir.mlir b/mlir/test/Target/LLVMIR/llvmir.mlir
index c00b69bdbeb3b..55447c9945537 100644
--- a/mlir/test/Target/LLVMIR/llvmir.mlir
+++ b/mlir/test/Target/LLVMIR/llvmir.mlir
@@ -3662,6 +3662,18 @@ llvm.mlir.global @associated_via_alias(2 : i32) {associated = @alias_of_target}
// -----
+// CHECK: @associated_ifunc_global = global i32 0, !associated ![[ASSOC_IFUNC:[0-9]+]]
+// CHECK: @associated_ifunc = ifunc i32 (i32), ptr @associated_ifunc_resolver
+// CHECK: ![[ASSOC_IFUNC]] = !{ptr @associated_ifunc}
+llvm.mlir.global @associated_ifunc_global(0 : i32) {associated = @associated_ifunc} : i32
+llvm.mlir.ifunc @associated_ifunc : !llvm.func<i32 (i32)>, !llvm.ptr @associated_ifunc_resolver
+llvm.func @associated_ifunc_resolver() -> !llvm.ptr {
+ %0 = llvm.mlir.zero : !llvm.ptr
+ llvm.return %0 : !llvm.ptr
+}
+
+// -----
+
// CHECK: @absolute_symbol_global = external global i8, !absolute_symbol ![[ABS:[0-9]+]]
// CHECK: ![[ABS]] = !{i64 0, i64 42}
llvm.mlir.global external @absolute_symbol_global() {absolute_symbol = [0 : i64, 42 : i64]} : i8
>From 019b7211064aa165c942c9044e3109f361c0ea44 Mon Sep 17 00:00:00 2001
From: ktanishqk <tanishqk0102 at gmail.com>
Date: Wed, 26 Aug 2026 18:35:54 -0700
Subject: [PATCH 3/5] worked on comments: code simplified + refactors
---
.../include/mlir/Target/LLVMIR/ModuleImport.h | 2 +
.../mlir/Target/LLVMIR/ModuleTranslation.h | 4 ++
mlir/lib/Target/LLVMIR/ModuleImport.cpp | 65 +++++++++----------
mlir/lib/Target/LLVMIR/ModuleTranslation.cpp | 45 +++++++------
4 files changed, 62 insertions(+), 54 deletions(-)
diff --git a/mlir/include/mlir/Target/LLVMIR/ModuleImport.h b/mlir/include/mlir/Target/LLVMIR/ModuleImport.h
index da6471a2e001d..3bb024a88f283 100644
--- a/mlir/include/mlir/Target/LLVMIR/ModuleImport.h
+++ b/mlir/include/mlir/Target/LLVMIR/ModuleImport.h
@@ -382,6 +382,8 @@ class ModuleImport {
/// Returns the symbol reference for a global value that has a corresponding
/// imported MLIR symbol, or a null attribute otherwise.
FlatSymbolRefAttr getMetadataGlobalValueSymbolRef(llvm::GlobalValue *global);
+ /// Returns a symbol ref if `md` refers to an imported global value.
+ FlatSymbolRefAttr getMetadataOperandSymbolRef(const llvm::Metadata *md);
/// Converts `md` to the matching LLVM dialect metadata attribute, or returns
/// a null attribute if the metadata cannot be represented.
Attribute convertMetadataToAttr(const llvm::Metadata *md);
diff --git a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
index 9fb4414ce159e..5f1f73dbb9f4f 100644
--- a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
+++ b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
@@ -436,6 +436,10 @@ class ModuleTranslation {
/// symbol references (globals, aliases, functions, and ifuncs) can be
/// resolved.
LogicalResult convertGlobalMetadata();
+ /// Converts a symbol ref to LLVM IR metadata, or fails if unresolved.
+ FailureOr<llvm::Metadata *>
+ convertSymbolRefToMetadata(FlatSymbolRefAttr name,
+ function_ref<InFlightDiagnostic()> emitError);
LogicalResult convertOneFunction(LLVMFuncOp func);
LogicalResult convertBlockImpl(Block &bb, bool ignoreArguments,
llvm::IRBuilderBase &builder,
diff --git a/mlir/lib/Target/LLVMIR/ModuleImport.cpp b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
index 9f26c3240d1ed..42ff6e236d7db 100644
--- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
@@ -173,6 +173,20 @@ ModuleImport::getMetadataGlobalValueSymbolRef(llvm::GlobalValue *global) {
return FlatSymbolRefAttr::get(context, global->getName());
}
+FlatSymbolRefAttr
+ModuleImport::getMetadataOperandSymbolRef(const llvm::Metadata *md) {
+ auto *valueAsMD = dyn_cast_or_null<llvm::ValueAsMetadata>(md);
+ if (!valueAsMD)
+ return {};
+ llvm::Value *value = valueAsMD->getValue();
+ llvm::GlobalValue *gv = dyn_cast<llvm::GlobalValue>(value);
+ if (!gv)
+ gv = dyn_cast<llvm::GlobalValue>(value->stripPointerCastsAndAliases());
+ if (!gv)
+ return {};
+ return getMetadataGlobalValueSymbolRef(gv);
+}
+
/// 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`
@@ -1688,46 +1702,31 @@ LogicalResult ModuleImport::convertGlobal(llvm::GlobalVariable *globalVar) {
if (llvm::MDNode *associatedMD =
globalVar->getMetadata(llvm::LLVMContext::MD_associated)) {
if (associatedMD->getNumOperands() == 1) {
- if (auto *valueAsMD = dyn_cast_or_null<llvm::ValueAsMetadata>(
- associatedMD->getOperand(0).get())) {
- llvm::Value *value = valueAsMD->getValue();
- llvm::GlobalValue *gv = dyn_cast<llvm::GlobalValue>(value);
- if (!gv)
- gv =
- dyn_cast<llvm::GlobalValue>(value->stripPointerCastsAndAliases());
- if (gv) {
- StringRef name = gv->getName();
- FlatSymbolRefAttr symbolRef;
- if (name.empty()) {
- if (auto *namelessVar = dyn_cast<llvm::GlobalVariable>(gv))
- symbolRef = getOrCreateNamelessSymbolName(namelessVar);
- } else {
- symbolRef = FlatSymbolRefAttr::get(context, name);
- }
- if (symbolRef)
- globalOp.setAssociatedAttr(symbolRef);
- }
- }
+ if (FlatSymbolRefAttr symbolRef =
+ getMetadataOperandSymbolRef(associatedMD->getOperand(0).get()))
+ globalOp.setAssociatedAttr(symbolRef);
}
}
if (llvm::MDNode *absSymMD =
globalVar->getMetadata(llvm::LLVMContext::MD_absolute_symbol)) {
- SmallVector<Attribute> rangeAttrs;
- rangeAttrs.reserve(absSymMD->getNumOperands());
- bool valid =
- absSymMD->getNumOperands() >= 2 && absSymMD->getNumOperands() % 2 == 0;
- for (const llvm::MDOperand &op : absSymMD->operands()) {
- auto *constInt = llvm::mdconst::dyn_extract<llvm::ConstantInt>(op);
- if (!constInt) {
- valid = false;
- break;
+ unsigned numOps = absSymMD->getNumOperands();
+ if (numOps >= 2 && numOps % 2 == 0) {
+ SmallVector<Attribute> rangeAttrs;
+ rangeAttrs.reserve(numOps);
+
+ for (const llvm::MDOperand &op : absSymMD->operands()) {
+ auto *constInt = llvm::mdconst::dyn_extract<llvm::ConstantInt>(op);
+ if (!constInt)
+ break;
+
+ auto intType = IntegerType::get(context, constInt->getBitWidth());
+ rangeAttrs.push_back(IntegerAttr::get(intType, constInt->getValue()));
}
- auto intType = IntegerType::get(context, constInt->getBitWidth());
- rangeAttrs.push_back(IntegerAttr::get(intType, constInt->getValue()));
+
+ if (rangeAttrs.size() == numOps)
+ globalOp.setAbsoluteSymbolAttr(ArrayAttr::get(context, rangeAttrs));
}
- if (valid)
- globalOp.setAbsoluteSymbolAttr(ArrayAttr::get(context, rangeAttrs));
}
processTargetSpecificAttrs(globalVar, globalOp);
diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
index 3c50a2349b78c..76fa43cd376cd 100644
--- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
@@ -1599,22 +1599,7 @@ FailureOr<llvm::Metadata *> ModuleTranslation::convertMetadataAttr(
intAttr.getValue()));
})
.Case([&](MDGlobalValueAttr a) -> FailureOr<llvm::Metadata *> {
- if (llvm::Function *fn = lookupFunction(a.getName().getValue()))
- return llvm::ValueAsMetadata::get(fn);
- if (llvm::GlobalValue *global = lookupGlobal(a.getName().getValue()))
- return llvm::ValueAsMetadata::get(global);
- Operation *symbol =
- symbolTable().lookupSymbolIn(mlirModule, a.getName());
- if (auto alias = dyn_cast_if_present<LLVM::AliasOp>(symbol)) {
- if (llvm::GlobalValue *global = lookupAlias(alias))
- return llvm::ValueAsMetadata::get(global);
- }
- if (auto ifunc = dyn_cast_if_present<LLVM::IFuncOp>(symbol)) {
- if (llvm::GlobalValue *global = lookupIFunc(ifunc))
- return llvm::ValueAsMetadata::get(global);
- }
- return emitError() << "could not resolve metadata reference '"
- << a.getName() << "'";
+ return convertSymbolRefToMetadata(a.getName(), emitError);
})
.Case([&](MDNullAttr a) -> FailureOr<llvm::Metadata *> {
return llvm::ConstantAsMetadata::get(llvm::ConstantPointerNull::get(
@@ -1649,6 +1634,24 @@ FailureOr<llvm::Metadata *> ModuleTranslation::convertMetadataAttr(
});
}
+FailureOr<llvm::Metadata *> ModuleTranslation::convertSymbolRefToMetadata(
+ FlatSymbolRefAttr name, function_ref<InFlightDiagnostic()> emitError) {
+ if (llvm::Function *fn = lookupFunction(name.getValue()))
+ return llvm::ValueAsMetadata::get(fn);
+ if (llvm::GlobalValue *global = lookupGlobal(name.getValue()))
+ return llvm::ValueAsMetadata::get(global);
+ Operation *symbol = symbolTable().lookupSymbolIn(mlirModule, name);
+ if (auto alias = dyn_cast_if_present<LLVM::AliasOp>(symbol)) {
+ if (llvm::GlobalValue *global = lookupAlias(alias))
+ return llvm::ValueAsMetadata::get(global);
+ }
+ if (auto ifunc = dyn_cast_if_present<LLVM::IFuncOp>(symbol)) {
+ if (llvm::GlobalValue *global = lookupIFunc(ifunc))
+ return llvm::ValueAsMetadata::get(global);
+ }
+ return emitError() << "could not resolve metadata reference '" << name << "'";
+}
+
LogicalResult ModuleTranslation::convertFunctionMetadata() {
for (auto function : getModuleBody(mlirModule).getOps<LLVMFuncOp>()) {
ArrayAttr metadata = function.getFunctionMetadataAttr();
@@ -2242,10 +2245,10 @@ LogicalResult ModuleTranslation::convertGlobalMetadata() {
for (auto op : getModuleBody(mlirModule).getOps<LLVM::GlobalOp>()) {
auto *var = cast<llvm::GlobalVariable>(lookupGlobal(op));
if (FlatSymbolRefAttr associated = op.getAssociatedAttr()) {
- auto mdAttr = MDGlobalValueAttr::get(op.getContext(), associated);
- FailureOr<llvm::Metadata *> md = convertMetadataAttr(mdAttr, [&]() {
- return op.emitError("failed to convert associated metadata");
- });
+ FailureOr<llvm::Metadata *> md =
+ convertSymbolRefToMetadata(associated, [&]() {
+ return op.emitError("failed to convert associated metadata");
+ });
if (failed(md))
return failure();
var->setMetadata(llvm::LLVMContext::MD_associated,
@@ -2257,7 +2260,7 @@ LogicalResult ModuleTranslation::convertGlobalMetadata() {
llvm::LLVMContext &ctx = var->getContext();
mdOps.reserve(absSym.size());
for (Attribute attr : absSym) {
- auto intAttr = llvm::cast<IntegerAttr>(attr);
+ auto intAttr = cast<IntegerAttr>(attr);
llvm::IntegerType *ty = llvm::IntegerType::get(
ctx, intAttr.getType().getIntOrFloatBitWidth());
mdOps.push_back(llvm::ConstantAsMetadata::get(
>From 014845bb9a1a5cef20052686c8a40e506b3de85b Mon Sep 17 00:00:00 2001
From: ktanishqk <tanishqk0102 at gmail.com>
Date: Sat, 29 Aug 2026 12:59:43 -0700
Subject: [PATCH 4/5] add warning + testing
---
mlir/lib/Target/LLVMIR/ModuleImport.cpp | 15 +++++++++++----
.../test/Target/LLVMIR/Import/global-variables.ll | 8 ++++++++
2 files changed, 19 insertions(+), 4 deletions(-)
diff --git a/mlir/lib/Target/LLVMIR/ModuleImport.cpp b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
index 42ff6e236d7db..30929c81d2330 100644
--- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
@@ -1701,10 +1701,17 @@ LogicalResult ModuleImport::convertGlobal(llvm::GlobalVariable *globalVar) {
if (llvm::MDNode *associatedMD =
globalVar->getMetadata(llvm::LLVMContext::MD_associated)) {
- if (associatedMD->getNumOperands() == 1) {
- if (FlatSymbolRefAttr symbolRef =
- getMetadataOperandSymbolRef(associatedMD->getOperand(0).get()))
- globalOp.setAssociatedAttr(symbolRef);
+ FlatSymbolRefAttr symbolRef;
+ if (associatedMD->getNumOperands() == 1)
+ symbolRef =
+ getMetadataOperandSymbolRef(associatedMD->getOperand(0).get());
+ if (symbolRef) {
+ globalOp.setAssociatedAttr(symbolRef);
+ } else {
+ emitWarning(globalOp.getLoc())
+ << "unhandled associated metadata: "
+ << diagMD(associatedMD, llvmModule.get()) << " on "
+ << diag(*globalVar);
}
}
diff --git a/mlir/test/Target/LLVMIR/Import/global-variables.ll b/mlir/test/Target/LLVMIR/Import/global-variables.ll
index 7772040830aac..905e9cf3982e5 100644
--- a/mlir/test/Target/LLVMIR/Import/global-variables.ll
+++ b/mlir/test/Target/LLVMIR/Import/global-variables.ll
@@ -1,4 +1,5 @@
; RUN: mlir-translate -import-llvm -split-input-file %s | FileCheck %s
+; RUN: mlir-translate -import-llvm -split-input-file %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=WARN
%sub_struct = type {}
%my_struct = type { %sub_struct, i64 }
@@ -430,6 +431,13 @@ define ptr @associated_ifunc_resolver() {
; // -----
+; WARN: warning: unhandled associated metadata: {{.*}}ptr null{{.*}} on @associated_null
+; CHECK: llvm.mlir.global external @associated_null() {addr_space = 0 : i32} : i8
+ at associated_null = external global i8, !associated !0
+!0 = !{ptr null}
+
+; // -----
+
; CHECK: llvm.mlir.global external @a()
; CHECK-SAME: {absolute_symbol = [0, 42], addr_space = 0 : i32} : i8
@a = external global i8, !absolute_symbol !0
>From 051161e6b9f4de4f87aec06e0cee02390a61027c Mon Sep 17 00:00:00 2001
From: ktanishqk <tanishqk0102 at gmail.com>
Date: Sat, 29 Aug 2026 18:40:23 -0700
Subject: [PATCH 5/5] formatting fix
---
mlir/lib/Target/LLVMIR/ModuleImport.cpp | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/mlir/lib/Target/LLVMIR/ModuleImport.cpp b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
index 30929c81d2330..49bd27b5da177 100644
--- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
@@ -1708,10 +1708,9 @@ LogicalResult ModuleImport::convertGlobal(llvm::GlobalVariable *globalVar) {
if (symbolRef) {
globalOp.setAssociatedAttr(symbolRef);
} else {
- emitWarning(globalOp.getLoc())
- << "unhandled associated metadata: "
- << diagMD(associatedMD, llvmModule.get()) << " on "
- << diag(*globalVar);
+ emitWarning(globalOp.getLoc()) << "unhandled associated metadata: "
+ << diagMD(associatedMD, llvmModule.get())
+ << " on " << diag(*globalVar);
}
}
More information about the Mlir-commits
mailing list