[Mlir-commits] [mlir] aa1058e - [mlir][LLVM] Preserve !associated and !absolute_symbol on llvm.mlir.global (#218839)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Sun Aug 30 01:45:45 PDT 2026


Author: Tanishq Khurana
Date: 2026-08-30T17:45:40+09:00
New Revision: aa1058e34a6127df91898829b0e60cbae3111cbf

URL: https://github.com/llvm/llvm-project/commit/aa1058e34a6127df91898829b0e60cbae3111cbf
DIFF: https://github.com/llvm/llvm-project/commit/aa1058e34a6127df91898829b0e60cbae3111cbf.diff

LOG: [mlir][LLVM] Preserve !associated and !absolute_symbol on llvm.mlir.global (#218839)

Add optional `associated` and `absolute_symbol` attributes on
`llvm.mlir.global` so the corresponding LLVM IR metadata is preserved
through import and export.

`associated` is a symbol ref to another global, alias, or function (used
for ELF `SHF_LINK_ORDER`). `absolute_symbol` is an array of `[lower,
upper)` integer range pairs, with `[-1, -1]` for the full set.

Verifier rejects a self-associated global and malformed range lists.
Translation attaches the metadata after all globals, aliases, and
function signatures exist so symbol refs can be resolved.

Fixes #215549

Assisted-by: Cursor

---------

Co-authored-by: Cursor <cursoragent at cursor.com>

Added: 
    

Modified: 
    mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
    mlir/include/mlir/Target/LLVMIR/ModuleImport.h
    mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
    mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
    mlir/lib/Target/LLVMIR/ModuleImport.cpp
    mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
    mlir/test/Dialect/LLVMIR/global.mlir
    mlir/test/Target/LLVMIR/Import/global-variables.ll
    mlir/test/Target/LLVMIR/llvmir.mlir

Removed: 
    


################################################################################
diff  --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
index d5373d4bc6186..42b10d3df6d2c 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
@@ -1416,6 +1416,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_,
@@ -1518,6 +1520,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/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 6db1951dbdd35..5f1f73dbb9f4f 100644
--- a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
+++ b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
@@ -428,7 +428,18 @@ 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();
+  /// 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/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
index 858425f80ee31..c58d5b07cd296 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
@@ -2724,6 +2724,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 02cdb6088b6ac..ef2363fb4dfd9 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`
@@ -1687,6 +1701,42 @@ 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)) {
+    FlatSymbolRefAttr symbolRef;
+    if (associatedMD->getNumOperands() == 1)
+      symbolRef =
+          getMetadataOperandSymbolRef(associatedMD->getOperand(0).get());
+    if (!symbolRef) {
+      emitWarning(globalOp.getLoc()) << "unhandled associated metadata: "
+                                     << diagMD(associatedMD, llvmModule.get())
+                                     << " on " << diag(*globalVar);
+    } else {
+      globalOp.setAssociatedAttr(symbolRef);
+    }
+  }
+
+  if (llvm::MDNode *absSymMD =
+          globalVar->getMetadata(llvm::LLVMContext::MD_absolute_symbol)) {
+    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()));
+      }
+
+      if (rangeAttrs.size() == numOps)
+        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 5bb42575a0955..76fa43cd376cd 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"
@@ -1598,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(
@@ -1648,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();
@@ -2235,6 +2239,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()) {
+      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,
+                       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 = 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>()) {
@@ -2694,6 +2733,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.convertFunctionMetadata()))
     return nullptr;
   if (failed(translator.createTBAAMetadata()))

diff  --git a/mlir/test/Dialect/LLVMIR/global.mlir b/mlir/test/Dialect/LLVMIR/global.mlir
index 2e6459386389e..69ccbb4eaac32 100644
--- a/mlir/test/Dialect/LLVMIR/global.mlir
+++ b/mlir/test/Dialect/LLVMIR/global.mlir
@@ -304,3 +304,46 @@ 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 @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
+
+// 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 bf2f48f26fdbc..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 }
@@ -388,3 +389,64 @@ 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 @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}
+
+; // -----
+
+; 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
+ at a = external global i8, !absolute_symbol !0
+!0 = !{i64 0, i64 42}
+
+; // -----
+
+; CHECK: llvm.mlir.global external @a()
+; CHECK-SAME: {absolute_symbol = [-1, -1], 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 718f19f32131d..5edc4a0fce9b4 100644
--- a/mlir/test/Target/LLVMIR/llvmir.mlir
+++ b/mlir/test/Target/LLVMIR/llvmir.mlir
@@ -3645,6 +3645,59 @@ 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: @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
+
+// -----
+
+// 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>


        


More information about the Mlir-commits mailing list