[Mlir-commits] [mlir] [MLIR][LLVM][DLTI] Handle data layout token 'Fn32' (PR #141167)

Bruno Cardoso Lopes llvmlistbot at llvm.org
Fri May 23 10:51:22 PDT 2025


https://github.com/bcardosolopes updated https://github.com/llvm/llvm-project/pull/141167

>From 7c05f1f22f80d111e00964f7d9c0a2c268730836 Mon Sep 17 00:00:00 2001
From: Bruno Cardoso Lopes <bruno.cardoso at gmail.com>
Date: Thu, 22 May 2025 10:52:38 -0700
Subject: [PATCH 1/4] [MLIR][LLVM][DLTI] Handle data layout token 'Fn32'

---
 mlir/include/mlir/Dialect/DLTI/DLTIAttrs.td   | 34 ++++++++++++++++++
 mlir/include/mlir/Dialect/DLTI/DLTIBase.td    |  5 ++-
 .../mlir/Interfaces/DataLayoutInterfaces.h    | 12 +++++++
 .../mlir/Interfaces/DataLayoutInterfaces.td   | 18 ++++++++++
 mlir/lib/Dialect/DLTI/DLTI.cpp                |  7 ++++
 mlir/lib/Interfaces/DataLayoutInterfaces.cpp  | 27 ++++++++++++++
 mlir/lib/Target/LLVMIR/DataLayoutImporter.cpp | 36 +++++++++++++++++++
 mlir/lib/Target/LLVMIR/DataLayoutImporter.h   |  5 +++
 mlir/lib/Target/LLVMIR/ModuleTranslation.cpp  | 10 ++++++
 mlir/test/Dialect/LLVMIR/layout.mlir          | 18 +++++++++-
 mlir/test/Target/LLVMIR/Import/data-layout.ll |  3 +-
 mlir/test/Target/LLVMIR/data-layout.mlir      |  8 ++++-
 .../lib/Dialect/DLTI/TestDataLayoutQuery.cpp  | 12 ++++++-
 .../Interfaces/DataLayoutInterfacesTest.cpp   | 13 ++++++-
 14 files changed, 202 insertions(+), 6 deletions(-)

diff --git a/mlir/include/mlir/Dialect/DLTI/DLTIAttrs.td b/mlir/include/mlir/Dialect/DLTI/DLTIAttrs.td
index cf3a72633587d..d53fbe3a60fa6 100644
--- a/mlir/include/mlir/Dialect/DLTI/DLTIAttrs.td
+++ b/mlir/include/mlir/Dialect/DLTI/DLTIAttrs.td
@@ -92,6 +92,9 @@ def DLTI_DataLayoutSpecAttr :
     /// Returns the stack alignment identifier.
     StringAttr getStackAlignmentIdentifier(MLIRContext *context) const;
 
+    /// Returns the function poinrter alignment identifier.
+    StringAttr getFunctionPointerAlignmentIdentifier(MLIRContext *context) const;
+
     /// Returns the attribute associated with the key.
     FailureOr<Attribute> query(DataLayoutEntryKey key) {
       return ::llvm::cast<mlir::DataLayoutSpecInterface>(*this).queryHelper(key);
@@ -249,4 +252,35 @@ def DLTI_TargetDeviceSpecAttr :
   }];
 }
 
+//===----------------------------------------------------------------------===//
+// FunctionPointerAlignmentAttr
+//===----------------------------------------------------------------------===//
+
+def DLTI_FunctionPointerAlignmentAttr :
+    DLTIAttr<"FunctionPointerAlignment", []> {
+  let summary = "An attribute to represent function pointer alignment.";
+  let description = [{
+    Function pointer alignment specifies the minimum alignment of function
+    pointers, it's a multiple of `alignment`. This alignment can also depend
+    on the target function, indicated by `function_dependent`.
+    Example:
+    ```
+    #dlti.dl_entry<"dlti.function_pointer_alignment",
+               #dlti.function_pointer_alignment<64, function_dependent = false>>
+    ```
+  }];
+  let parameters = (ins
+    "uint64_t":$alignment,
+    "bool":$function_dependent
+  );
+  let assemblyFormat = [{
+    `<`
+    $alignment `,`
+    `function_dependent` `=` $function_dependent
+    `>`
+  }];
+  let mnemonic = "function_pointer_alignment";
+}
+
+
 #endif  // MLIR_DIALECT_DLTI_DLTIATTRS_TD
diff --git a/mlir/include/mlir/Dialect/DLTI/DLTIBase.td b/mlir/include/mlir/Dialect/DLTI/DLTIBase.td
index 1a08bafda54ee..ad5f9dc611c79 100644
--- a/mlir/include/mlir/Dialect/DLTI/DLTIBase.td
+++ b/mlir/include/mlir/Dialect/DLTI/DLTIBase.td
@@ -58,7 +58,7 @@ def DLTI_Dialect : Dialect {
 
     constexpr const static ::llvm::StringLiteral
     kDataLayoutAllocaMemorySpaceKey = "dlti.alloca_memory_space";
-    
+
     constexpr const static ::llvm::StringLiteral
     kDataLayoutProgramMemorySpaceKey = "dlti.program_memory_space";
 
@@ -67,6 +67,9 @@ def DLTI_Dialect : Dialect {
 
     constexpr const static ::llvm::StringLiteral
     kDataLayoutStackAlignmentKey = "dlti.stack_alignment";
+
+    constexpr const static ::llvm::StringLiteral
+    kDataLayoutFunctionPointerAlignmentKey = "dlti.function_pointer_alignment";
   }];
 
   let useDefaultAttributePrinterParser = 1;
diff --git a/mlir/include/mlir/Interfaces/DataLayoutInterfaces.h b/mlir/include/mlir/Interfaces/DataLayoutInterfaces.h
index ff40bfc4bee41..89ae6d8877f14 100644
--- a/mlir/include/mlir/Interfaces/DataLayoutInterfaces.h
+++ b/mlir/include/mlir/Interfaces/DataLayoutInterfaces.h
@@ -101,6 +101,10 @@ Attribute getDefaultGlobalMemorySpace(DataLayoutEntryInterface entry);
 /// DataLayoutInterface if specified, otherwise returns the default.
 uint64_t getDefaultStackAlignment(DataLayoutEntryInterface entry);
 
+/// Default handler for the stack alignment request. Dispatches to the
+/// DataLayoutInterface if specified, otherwise returns the default.
+Attribute getDefaultFunctionPointerAlignment(DataLayoutEntryInterface entry);
+
 /// Returns the value of the property from the specified DataLayoutEntry. If the
 /// property is missing from the entry, returns std::nullopt.
 std::optional<Attribute> getDevicePropertyValue(DataLayoutEntryInterface entry);
@@ -259,6 +263,12 @@ class DataLayout {
   /// unspecified.
   uint64_t getStackAlignment() const;
 
+  /// Returns the natural alignment of the stack in bits. Alignment promotion of
+  /// stack variables should be limited to the natural stack alignment to
+  /// prevent dynamic stack alignment. Returns zero if the stack alignment is
+  /// unspecified.
+  Attribute getFunctionPointerAlignment() const;
+
   /// Returns the value of the specified property if the property is defined for
   /// the given device ID, otherwise returns std::nullopt.
   std::optional<Attribute>
@@ -303,6 +313,8 @@ class DataLayout {
 
   /// Cache for stack alignment.
   mutable std::optional<uint64_t> stackAlignment;
+  /// Cache for function pointer alignment.
+  mutable std::optional<Attribute> functionPointerAlignment;
 };
 
 } // namespace mlir
diff --git a/mlir/include/mlir/Interfaces/DataLayoutInterfaces.td b/mlir/include/mlir/Interfaces/DataLayoutInterfaces.td
index c5973d4252b0a..d10a2fd9dc8e4 100644
--- a/mlir/include/mlir/Interfaces/DataLayoutInterfaces.td
+++ b/mlir/include/mlir/Interfaces/DataLayoutInterfaces.td
@@ -171,6 +171,12 @@ def DataLayoutSpecInterface : AttrInterface<"DataLayoutSpecInterface", [DLTIQuer
       /*methodName=*/"getStackAlignmentIdentifier",
       /*args=*/(ins "::mlir::MLIRContext *":$context)
     >,
+    InterfaceMethod<
+      /*description=*/"Returns the function pointer alignment identifier.",
+      /*retTy=*/"::mlir::StringAttr",
+      /*methodName=*/"getFunctionPointerAlignmentIdentifier",
+      /*args=*/(ins "::mlir::MLIRContext *":$context)
+    >,
     // Implementations may override this if they have an efficient lookup
     // mechanism.
     InterfaceMethod<
@@ -553,6 +559,18 @@ def DataLayoutOpInterface : OpInterface<"DataLayoutOpInterface"> {
         return ::mlir::detail::getDefaultStackAlignment(entry);
       }]
     >,
+    StaticInterfaceMethod<
+      /*description=*/"Returns the function pointer alignment in bits computed "
+                      "using the relevant entries. The data layout object "
+                      "can be used for recursive queries.",
+      /*retTy=*/"Attribute",
+      /*methodName=*/"getFunctionPointerAlignment",
+      /*args=*/(ins "::mlir::DataLayoutEntryInterface":$entry),
+      /*methodBody=*/"",
+      /*defaultImplementation=*/[{
+        return ::mlir::detail::getDefaultFunctionPointerAlignment(entry);
+      }]
+    >,
     StaticInterfaceMethod<
       /*description=*/"Returns the value of the property, if the property is "
                       "defined. Otherwise, it returns std::nullopt.",
diff --git a/mlir/lib/Dialect/DLTI/DLTI.cpp b/mlir/lib/Dialect/DLTI/DLTI.cpp
index 5d7dd2f8443df..ae8f016c3d1a5 100644
--- a/mlir/lib/Dialect/DLTI/DLTI.cpp
+++ b/mlir/lib/Dialect/DLTI/DLTI.cpp
@@ -420,6 +420,12 @@ DataLayoutSpecAttr::getStackAlignmentIdentifier(MLIRContext *context) const {
       DLTIDialect::kDataLayoutStackAlignmentKey);
 }
 
+StringAttr DataLayoutSpecAttr::getFunctionPointerAlignmentIdentifier(
+    MLIRContext *context) const {
+  return Builder(context).getStringAttr(
+      DLTIDialect::kDataLayoutFunctionPointerAlignmentKey);
+}
+
 /// Parses an attribute with syntax:
 ///   dl-spec-attr ::= `#dlti.` `dl_spec` `<` entry-list `>`
 ///   entry-list ::= | entry | entry `,` entry-list
@@ -625,6 +631,7 @@ class TargetDataLayoutInterface : public DataLayoutDialectInterface {
         entryName == DLTIDialect::kDataLayoutProgramMemorySpaceKey ||
         entryName == DLTIDialect::kDataLayoutGlobalMemorySpaceKey ||
         entryName == DLTIDialect::kDataLayoutStackAlignmentKey ||
+        entryName == DLTIDialect::kDataLayoutFunctionPointerAlignmentKey ||
         entryName == DLTIDialect::kDataLayoutManglingModeKey)
       return success();
     return emitError(loc) << "unknown data layout entry name: " << entryName;
diff --git a/mlir/lib/Interfaces/DataLayoutInterfaces.cpp b/mlir/lib/Interfaces/DataLayoutInterfaces.cpp
index 4ac66c3107384..839db6d718dd5 100644
--- a/mlir/lib/Interfaces/DataLayoutInterfaces.cpp
+++ b/mlir/lib/Interfaces/DataLayoutInterfaces.cpp
@@ -312,6 +312,16 @@ mlir::detail::getDefaultStackAlignment(DataLayoutEntryInterface entry) {
   return value.getValue().getZExtValue();
 }
 
+// Returns the function pointer alignment if specified in the given entry. If
+// the entry is empty the default alignment zero is returned.
+Attribute mlir::detail::getDefaultFunctionPointerAlignment(
+    DataLayoutEntryInterface entry) {
+  if (entry == DataLayoutEntryInterface()) {
+    return Attribute();
+  }
+  return entry.getValue();
+}
+
 std::optional<Attribute>
 mlir::detail::getDevicePropertyValue(DataLayoutEntryInterface entry) {
   if (entry == DataLayoutEntryInterface())
@@ -710,6 +720,23 @@ uint64_t mlir::DataLayout::getStackAlignment() const {
   return *stackAlignment;
 }
 
+Attribute mlir::DataLayout::getFunctionPointerAlignment() const {
+  checkValid();
+  if (functionPointerAlignment)
+    return *functionPointerAlignment;
+  DataLayoutEntryInterface entry;
+  if (originalLayout)
+    entry = originalLayout.getSpecForIdentifier(
+        originalLayout.getFunctionPointerAlignmentIdentifier(
+            originalLayout.getContext()));
+  if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
+    functionPointerAlignment = iface.getFunctionPointerAlignment(entry);
+  else
+    functionPointerAlignment =
+        detail::getDefaultFunctionPointerAlignment(entry);
+  return *functionPointerAlignment;
+}
+
 std::optional<Attribute> mlir::DataLayout::getDevicePropertyValue(
     TargetSystemSpecInterface::DeviceID deviceID,
     StringAttr propertyName) const {
diff --git a/mlir/lib/Target/LLVMIR/DataLayoutImporter.cpp b/mlir/lib/Target/LLVMIR/DataLayoutImporter.cpp
index a5307d8e4c1ab..4e0ecfc8401a7 100644
--- a/mlir/lib/Target/LLVMIR/DataLayoutImporter.cpp
+++ b/mlir/lib/Target/LLVMIR/DataLayoutImporter.cpp
@@ -221,6 +221,34 @@ DataLayoutImporter::tryToEmplaceStackAlignmentEntry(StringRef token) {
   return success();
 }
 
+LogicalResult DataLayoutImporter::tryToEmplaceFunctionPointerAlignmentEntry(
+    StringRef fnPtrString, StringRef token) {
+  auto key = StringAttr::get(
+      context, DLTIDialect::kDataLayoutFunctionPointerAlignmentKey);
+  if (keyEntries.count(key))
+    return success();
+
+  // i: The alignment of function pointers is independent of the alignment of
+  // functions, and is a multiple of <abi>.
+  // n: The alignment of function pointers is a multiple of the explicit
+  // alignment specified on the function, and is a multiple of <abi>.
+  bool functionDependent = false;
+  if (fnPtrString == "n")
+    functionDependent = true;
+  else if (fnPtrString != "i")
+    return failure();
+
+  FailureOr<uint64_t> alignment = tryToParseInt(token);
+  if (failed(alignment))
+    return failure();
+
+  keyEntries.try_emplace(
+      key, DataLayoutEntryAttr::get(
+               key, FunctionPointerAlignmentAttr::get(
+                        key.getContext(), *alignment, functionDependent)));
+  return success();
+}
+
 void DataLayoutImporter::translateDataLayout(
     const llvm::DataLayout &llvmDataLayout) {
   dataLayout = {};
@@ -330,6 +358,14 @@ void DataLayoutImporter::translateDataLayout(
         return;
       continue;
     }
+    // Parse function pointer alignment specifications.
+    // Note that prefix here is "Fn" or "Fi", not a single character.
+    if (prefix->starts_with("F")) {
+      StringRef nextPrefix = prefix->drop_front(1);
+      if (failed(tryToEmplaceFunctionPointerAlignmentEntry(nextPrefix, token)))
+        return;
+      continue;
+    }
 
     // Store all tokens that have not been handled.
     unhandledTokens.push_back(lastToken);
diff --git a/mlir/lib/Target/LLVMIR/DataLayoutImporter.h b/mlir/lib/Target/LLVMIR/DataLayoutImporter.h
index 491ff65f17a41..501cff89d4738 100644
--- a/mlir/lib/Target/LLVMIR/DataLayoutImporter.h
+++ b/mlir/lib/Target/LLVMIR/DataLayoutImporter.h
@@ -108,6 +108,11 @@ class DataLayoutImporter {
   /// Adds a stack alignment entry if there is none yet.
   LogicalResult tryToEmplaceStackAlignmentEntry(StringRef token);
 
+  /// Adds a function pointer alignment entry if there is none yet.
+  LogicalResult
+  tryToEmplaceFunctionPointerAlignmentEntry(StringRef fnPtrAlignEntry,
+                                            StringRef token);
+
   std::string layoutStr = {};
   StringRef lastToken = {};
   SmallVector<StringRef> unhandledTokens;
diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
index 9b5c93171abfd..047e870b7dcd8 100644
--- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
@@ -240,6 +240,16 @@ translateDataLayout(DataLayoutSpecInterface attribute,
       layoutStream << "-S" << alignment;
       continue;
     }
+    if (key.getValue() == DLTIDialect::kDataLayoutFunctionPointerAlignmentKey) {
+      auto value = cast<FunctionPointerAlignmentAttr>(entry.getValue());
+      uint64_t alignment = value.getAlignment();
+      // Skip the default function pointer alignment.
+      if (alignment == 0)
+        continue;
+      layoutStream << "-F" << (value.getFunctionDependent() ? "n" : "i")
+                   << alignment;
+      continue;
+    }
     emitError(*loc) << "unsupported data layout key " << key;
     return failure();
   }
diff --git a/mlir/test/Dialect/LLVMIR/layout.mlir b/mlir/test/Dialect/LLVMIR/layout.mlir
index 4e60f991f1bf5..d7392deea67bc 100644
--- a/mlir/test/Dialect/LLVMIR/layout.mlir
+++ b/mlir/test/Dialect/LLVMIR/layout.mlir
@@ -8,6 +8,8 @@ module {
     // CHECK: bitsize = 64
     // CHECK: default_memory_space = 0
     // CHECK: endianness = ""
+    // CHECK: function_pointer_alignment =
+    // CHECK-SAME: #dlti.function_pointer_alignment<0, function_dependent = false>,
     // CHECK: global_memory_space = 0
     // CHECK: index = 64
     // CHECK: mangling_mode = ""
@@ -21,6 +23,8 @@ module {
     // CHECK: bitsize = 64
     // CHECK: default_memory_space = 0
     // CHECK: endianness = ""
+    // CHECK: function_pointer_alignment =
+    // CHECK-SAME: #dlti.function_pointer_alignment<0, function_dependent = false>,
     // CHECK: global_memory_space = 0
     // CHECK: index = 64
     // CHECK: mangling_mode = ""
@@ -34,6 +38,8 @@ module {
     // CHECK: bitsize = 64
     // CHECK: default_memory_space = 0
     // CHECK: endianness = ""
+    // CHECK: function_pointer_alignment =
+    // CHECK-SAME: #dlti.function_pointer_alignment<0, function_dependent = false>,
     // CHECK: global_memory_space = 0
     // CHECK: index = 64
     // CHECK: mangling_mode = ""
@@ -58,7 +64,9 @@ module attributes { dlti.dl_spec = #dlti.dl_spec<
   #dlti.dl_entry<"dlti.global_memory_space", 2 : ui64>,
   #dlti.dl_entry<"dlti.program_memory_space", 3 : ui64>,
   #dlti.dl_entry<"dlti.stack_alignment", 128 : i64>,
-  #dlti.dl_entry<"dlti.mangling_mode", "e">
+  #dlti.dl_entry<"dlti.mangling_mode", "e">,
+  #dlti.dl_entry<"dlti.function_pointer_alignment",
+                 "#dlti.function_pointer_alignment<32, function_dependent = true>">
 >} {
   // CHECK: @spec
   func.func @spec() {
@@ -67,6 +75,8 @@ module attributes { dlti.dl_spec = #dlti.dl_spec<
     // CHECK: bitsize = 32
     // CHECK: default_memory_space = 7
     // CHECK: endianness = "little"
+    // CHECK: function_pointer_alignment =
+    // CHECK-SAME: "#dlti.function_pointer_alignment<32, function_dependent = true>",
     // CHECK: global_memory_space = 2
     // CHECK: index = 32
     // CHECK: mangling_mode = "e"
@@ -80,6 +90,8 @@ module attributes { dlti.dl_spec = #dlti.dl_spec<
     // CHECK: bitsize = 32
     // CHECK: default_memory_space = 7
     // CHECK: endianness = "little"
+    // CHECK: function_pointer_alignment =
+    // CHECK-SAME: "#dlti.function_pointer_alignment<32, function_dependent = true>",
     // CHECK: global_memory_space = 2
     // CHECK: index = 32
     // CHECK: preferred = 8
@@ -92,6 +104,8 @@ module attributes { dlti.dl_spec = #dlti.dl_spec<
     // CHECK: bitsize = 64
     // CHECK: default_memory_space = 7
     // CHECK: endianness = "little"
+    // CHECK: function_pointer_alignment =
+    // CHECK-SAME: "#dlti.function_pointer_alignment<32, function_dependent = true>",
     // CHECK: global_memory_space = 2
     // CHECK: index = 64
     // CHECK: mangling_mode = "e"
@@ -105,6 +119,8 @@ module attributes { dlti.dl_spec = #dlti.dl_spec<
     // CHECK: bitsize = 32
     // CHECK: default_memory_space = 7
     // CHECK: endianness = "little"
+    // CHECK: function_pointer_alignment =
+    // CHECK-SAME: "#dlti.function_pointer_alignment<32, function_dependent = true>",
     // CHECK: global_memory_space = 2
     // CHECK: index = 24
     // CHECK: mangling_mode = "e"
diff --git a/mlir/test/Target/LLVMIR/Import/data-layout.ll b/mlir/test/Target/LLVMIR/Import/data-layout.ll
index d6f7719b3ca01..55e3f4dea5ff4 100644
--- a/mlir/test/Target/LLVMIR/Import/data-layout.ll
+++ b/mlir/test/Target/LLVMIR/Import/data-layout.ll
@@ -30,7 +30,8 @@ target datalayout = ""
 ; CHECK-SAME:   "dlti.endianness" = "little"
 ; CHECK-SAME:   "dlti.mangling_mode" = "e"
 ; CHECK-SAME:   "dlti.stack_alignment" = 128 : i64
-target datalayout = "e-m:e-p270:32:64-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+; CHECK-SAME:   "dlti.function_pointer_alignment" = #dlti.function_pointer_alignment<32, function_dependent = true>
+target datalayout = "e-m:e-p270:32:64-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128-Fn32"
 
 ; // -----
 
diff --git a/mlir/test/Target/LLVMIR/data-layout.mlir b/mlir/test/Target/LLVMIR/data-layout.mlir
index 3576461cd01f1..30b9b03de3dbb 100644
--- a/mlir/test/Target/LLVMIR/data-layout.mlir
+++ b/mlir/test/Target/LLVMIR/data-layout.mlir
@@ -5,6 +5,7 @@
 // CHECK: A4-
 // CHECK: S128-
 // CHECK: m:e-
+// CHECK: Fn32
 // CHECK: i64:64:128
 // CHECK: f80:128:256
 // CHECK: p0:32:64:128:32
@@ -14,6 +15,8 @@ module attributes {dlti.dl_spec = #dlti.dl_spec<
 #dlti.dl_entry<"dlti.alloca_memory_space", 4 : ui32>,
 #dlti.dl_entry<"dlti.stack_alignment", 128 : i32>,
 #dlti.dl_entry<"dlti.mangling_mode", "e">,
+#dlti.dl_entry<"dlti.function_pointer_alignment",
+               #dlti.function_pointer_alignment<32, function_dependent = true>>,
 #dlti.dl_entry<index, 64>,
 #dlti.dl_entry<i64, dense<[64,128]> : vector<2xi64>>,
 #dlti.dl_entry<f80, dense<[128,256]> : vector<2xi64>>,
@@ -29,12 +32,15 @@ module attributes {dlti.dl_spec = #dlti.dl_spec<
 
 // CHECK: target datalayout
 // CHECK: e
+// CHECK: Fi64
 // CHECK-NOT: A0
 // CHECK-NOT: S0
 module attributes {dlti.dl_spec = #dlti.dl_spec<
 #dlti.dl_entry<"dlti.endianness", "little">,
 #dlti.dl_entry<"dlti.alloca_memory_space", 0 : ui32>,
-#dlti.dl_entry<"dlti.stack_alignment", 0 : i32>
+#dlti.dl_entry<"dlti.stack_alignment", 0 : i32>,
+#dlti.dl_entry<"dlti.function_pointer_alignment",
+               #dlti.function_pointer_alignment<64, function_dependent = false>>
 >} {
   llvm.func @bar() {
     llvm.return
diff --git a/mlir/test/lib/Dialect/DLTI/TestDataLayoutQuery.cpp b/mlir/test/lib/Dialect/DLTI/TestDataLayoutQuery.cpp
index 41a2fe5e4ee75..08c8042f71a95 100644
--- a/mlir/test/lib/Dialect/DLTI/TestDataLayoutQuery.cpp
+++ b/mlir/test/lib/Dialect/DLTI/TestDataLayoutQuery.cpp
@@ -48,6 +48,7 @@ struct TestDataLayoutQuery
       Attribute programMemorySpace = layout.getProgramMemorySpace();
       Attribute globalMemorySpace = layout.getGlobalMemorySpace();
       uint64_t stackAlignment = layout.getStackAlignment();
+      Attribute functionPointerAlignment = layout.getFunctionPointerAlignment();
 
       auto convertTypeSizeToAttr = [&](llvm::TypeSize typeSize) -> Attribute {
         if (!typeSize.isScalable())
@@ -90,7 +91,16 @@ struct TestDataLayoutQuery
                                     ? builder.getUI32IntegerAttr(0)
                                     : globalMemorySpace),
            builder.getNamedAttr("stack_alignment",
-                                builder.getIndexAttr(stackAlignment))});
+                                builder.getIndexAttr(stackAlignment)),
+           builder.getNamedAttr("function_pointer_alignment",
+                                functionPointerAlignment == Attribute()
+                                    ? FunctionPointerAlignmentAttr::get(
+                                          builder.getContext(), 0,
+                                          /*function_dependent=*/false)
+                                    : functionPointerAlignment)
+
+          });
+
     });
   }
 };
diff --git a/mlir/unittests/Interfaces/DataLayoutInterfacesTest.cpp b/mlir/unittests/Interfaces/DataLayoutInterfacesTest.cpp
index fd81f3021aa9b..48bc2076055f8 100644
--- a/mlir/unittests/Interfaces/DataLayoutInterfacesTest.cpp
+++ b/mlir/unittests/Interfaces/DataLayoutInterfacesTest.cpp
@@ -35,6 +35,8 @@ constexpr static llvm::StringLiteral kGlobalKeyName =
     "dltest.global_memory_space";
 constexpr static llvm::StringLiteral kStackAlignmentKeyName =
     "dltest.stack_alignment";
+constexpr static llvm::StringLiteral kFunctionPointerAlignmentKeyName =
+    "dltest.function_pointer_alignment";
 
 constexpr static llvm::StringLiteral kTargetSystemDescAttrName =
     "dl_target_sys_desc_test.target_system_spec";
@@ -102,6 +104,9 @@ struct CustomDataLayoutSpec
   StringAttr getStackAlignmentIdentifier(MLIRContext *context) const {
     return Builder(context).getStringAttr(kStackAlignmentKeyName);
   }
+  StringAttr getFunctionPointerAlignmentIdentifier(MLIRContext *context) const {
+    return Builder(context).getStringAttr(kFunctionPointerAlignmentKeyName);
+  }
   FailureOr<Attribute> query(DataLayoutEntryKey key) const {
     return llvm::cast<mlir::DataLayoutSpecInterface>(*this).queryHelper(key);
   }
@@ -494,6 +499,7 @@ module {}
   EXPECT_EQ(layout.getProgramMemorySpace(), Attribute());
   EXPECT_EQ(layout.getGlobalMemorySpace(), Attribute());
   EXPECT_EQ(layout.getStackAlignment(), 0u);
+  EXPECT_EQ(layout.getFunctionPointerAlignment(), Attribute());
   EXPECT_EQ(layout.getManglingMode(), Attribute());
 }
 
@@ -594,7 +600,9 @@ TEST(DataLayout, SpecWithEntries) {
   #dlti.dl_entry<"dltest.program_memory_space", 3 : i32>,
   #dlti.dl_entry<"dltest.global_memory_space", 2 : i32>,
   #dlti.dl_entry<"dltest.stack_alignment", 128 : i32>,
-  #dlti.dl_entry<"dltest.mangling_mode", "o">
+  #dlti.dl_entry<"dltest.mangling_mode", "o">,
+  #dlti.dl_entry<"dltest.function_pointer_alignment",
+                 #dlti.function_pointer_alignment<64, function_dependent = true>>
 > } : () -> ()
   )MLIR";
 
@@ -633,6 +641,9 @@ TEST(DataLayout, SpecWithEntries) {
   EXPECT_EQ(layout.getGlobalMemorySpace(), Builder(&ctx).getI32IntegerAttr(2));
   EXPECT_EQ(layout.getStackAlignment(), 128u);
   EXPECT_EQ(layout.getManglingMode(), Builder(&ctx).getStringAttr("o"));
+  EXPECT_EQ(
+      layout.getFunctionPointerAlignment(),
+      FunctionPointerAlignmentAttr::get(&ctx, 64, /*function_dependent=*/true));
 }
 
 TEST(DataLayout, SpecWithTargetSystemDescEntries) {

>From 0acf751d5f04ef5dcfbfc8d90ab557a375c36327 Mon Sep 17 00:00:00 2001
From: Bruno Cardoso Lopes <bruno.cardoso at gmail.com>
Date: Thu, 22 May 2025 17:32:43 -0700
Subject: [PATCH 2/4] Fix comments

---
 mlir/include/mlir/Dialect/DLTI/DLTIAttrs.td         |  2 +-
 mlir/include/mlir/Interfaces/DataLayoutInterfaces.h |  5 +----
 mlir/lib/Target/LLVMIR/DataLayoutImporter.cpp       | 10 ++++++----
 3 files changed, 8 insertions(+), 9 deletions(-)

diff --git a/mlir/include/mlir/Dialect/DLTI/DLTIAttrs.td b/mlir/include/mlir/Dialect/DLTI/DLTIAttrs.td
index d53fbe3a60fa6..2aa58ea014caa 100644
--- a/mlir/include/mlir/Dialect/DLTI/DLTIAttrs.td
+++ b/mlir/include/mlir/Dialect/DLTI/DLTIAttrs.td
@@ -92,7 +92,7 @@ def DLTI_DataLayoutSpecAttr :
     /// Returns the stack alignment identifier.
     StringAttr getStackAlignmentIdentifier(MLIRContext *context) const;
 
-    /// Returns the function poinrter alignment identifier.
+    /// Returns the function pointer alignment identifier.
     StringAttr getFunctionPointerAlignmentIdentifier(MLIRContext *context) const;
 
     /// Returns the attribute associated with the key.
diff --git a/mlir/include/mlir/Interfaces/DataLayoutInterfaces.h b/mlir/include/mlir/Interfaces/DataLayoutInterfaces.h
index 89ae6d8877f14..50f75c1ad9d40 100644
--- a/mlir/include/mlir/Interfaces/DataLayoutInterfaces.h
+++ b/mlir/include/mlir/Interfaces/DataLayoutInterfaces.h
@@ -263,10 +263,7 @@ class DataLayout {
   /// unspecified.
   uint64_t getStackAlignment() const;
 
-  /// Returns the natural alignment of the stack in bits. Alignment promotion of
-  /// stack variables should be limited to the natural stack alignment to
-  /// prevent dynamic stack alignment. Returns zero if the stack alignment is
-  /// unspecified.
+  /// Returns function pointer alignment.
   Attribute getFunctionPointerAlignment() const;
 
   /// Returns the value of the specified property if the property is defined for
diff --git a/mlir/lib/Target/LLVMIR/DataLayoutImporter.cpp b/mlir/lib/Target/LLVMIR/DataLayoutImporter.cpp
index 4e0ecfc8401a7..1fc36d24094bd 100644
--- a/mlir/lib/Target/LLVMIR/DataLayoutImporter.cpp
+++ b/mlir/lib/Target/LLVMIR/DataLayoutImporter.cpp
@@ -228,10 +228,12 @@ LogicalResult DataLayoutImporter::tryToEmplaceFunctionPointerAlignmentEntry(
   if (keyEntries.count(key))
     return success();
 
-  // i: The alignment of function pointers is independent of the alignment of
-  // functions, and is a multiple of <abi>.
-  // n: The alignment of function pointers is a multiple of the explicit
-  // alignment specified on the function, and is a multiple of <abi>.
+  // The data layout entry for "F<type><abi>". <abi> is the aligment value,
+  // preceded by one of the two possible <types>:
+  // "i": The alignment of function pointers is independent of the alignment of
+  //      functions, and is a multiple of <abi>.
+  // "n": The alignment of function pointers is a multiple of the explicit
+  //      alignment specified on the function, and is a multiple of <abi>.
   bool functionDependent = false;
   if (fnPtrString == "n")
     functionDependent = true;

>From 77f5e70d9d9bb1bd6e3bb14b5291d882e62eeae2 Mon Sep 17 00:00:00 2001
From: Bruno Cardoso Lopes <bruno.cardoso at gmail.com>
Date: Thu, 22 May 2025 17:45:58 -0700
Subject: [PATCH 3/4] Add one more test

---
 mlir/unittests/Interfaces/DataLayoutInterfacesTest.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/mlir/unittests/Interfaces/DataLayoutInterfacesTest.cpp b/mlir/unittests/Interfaces/DataLayoutInterfacesTest.cpp
index 48bc2076055f8..ea173cdad7cce 100644
--- a/mlir/unittests/Interfaces/DataLayoutInterfacesTest.cpp
+++ b/mlir/unittests/Interfaces/DataLayoutInterfacesTest.cpp
@@ -577,6 +577,7 @@ TEST(DataLayout, EmptySpec) {
   EXPECT_EQ(layout.getGlobalMemorySpace(), Attribute());
   EXPECT_EQ(layout.getStackAlignment(), 0u);
   EXPECT_EQ(layout.getManglingMode(), Attribute());
+  EXPECT_EQ(layout.getFunctionPointerAlignment(), Attribute());
 
   EXPECT_EQ(layout.getDevicePropertyValue(
                 Builder(&ctx).getStringAttr("CPU" /* device ID*/),

>From b71db67dc557dd72cc3a600bd2b905adfa2c93b3 Mon Sep 17 00:00:00 2001
From: Bruno Cardoso Lopes <bruno.cardoso at gmail.com>
Date: Fri, 23 May 2025 10:48:58 -0700
Subject: [PATCH 4/4] address reviews

---
 mlir/include/mlir/Interfaces/DataLayoutInterfaces.h | 4 ++--
 mlir/lib/Interfaces/DataLayoutInterfaces.cpp        | 3 +--
 2 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/mlir/include/mlir/Interfaces/DataLayoutInterfaces.h b/mlir/include/mlir/Interfaces/DataLayoutInterfaces.h
index 50f75c1ad9d40..55d169df1c009 100644
--- a/mlir/include/mlir/Interfaces/DataLayoutInterfaces.h
+++ b/mlir/include/mlir/Interfaces/DataLayoutInterfaces.h
@@ -101,8 +101,8 @@ Attribute getDefaultGlobalMemorySpace(DataLayoutEntryInterface entry);
 /// DataLayoutInterface if specified, otherwise returns the default.
 uint64_t getDefaultStackAlignment(DataLayoutEntryInterface entry);
 
-/// Default handler for the stack alignment request. Dispatches to the
-/// DataLayoutInterface if specified, otherwise returns the default.
+/// Default handler for the function pointer alignment request. Dispatches to
+/// the DataLayoutInterface if specified, otherwise returns the default.
 Attribute getDefaultFunctionPointerAlignment(DataLayoutEntryInterface entry);
 
 /// Returns the value of the property from the specified DataLayoutEntry. If the
diff --git a/mlir/lib/Interfaces/DataLayoutInterfaces.cpp b/mlir/lib/Interfaces/DataLayoutInterfaces.cpp
index 839db6d718dd5..fbbe28ce9b4cc 100644
--- a/mlir/lib/Interfaces/DataLayoutInterfaces.cpp
+++ b/mlir/lib/Interfaces/DataLayoutInterfaces.cpp
@@ -316,9 +316,8 @@ mlir::detail::getDefaultStackAlignment(DataLayoutEntryInterface entry) {
 // the entry is empty the default alignment zero is returned.
 Attribute mlir::detail::getDefaultFunctionPointerAlignment(
     DataLayoutEntryInterface entry) {
-  if (entry == DataLayoutEntryInterface()) {
+  if (entry == DataLayoutEntryInterface())
     return Attribute();
-  }
   return entry.getValue();
 }
 



More information about the Mlir-commits mailing list