[Mlir-commits] [mlir] 9d2b84e - [mlir][llvm] Import pointer data layout specification.

Tobias Gysi llvmlistbot at llvm.org
Fri Mar 31 05:00:38 PDT 2023


Author: Tobias Gysi
Date: 2023-03-31T11:53:04Z
New Revision: 9d2b84ef6232c7aa75963526ff4092fb8d8a3b50

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

LOG: [mlir][llvm] Import pointer data layout specification.

The revision moves the data layout parsing into a separate file
and extends it to support pointer data layout specifications.
Additionally, it also produces more precise warnings and error
messages.

Reviewed By: Dinistro, definelicht

Differential Revision: https://reviews.llvm.org/D147170

Added: 
    mlir/lib/Target/LLVMIR/DataLayoutImporter.cpp
    mlir/lib/Target/LLVMIR/DataLayoutImporter.h

Modified: 
    mlir/include/mlir/Target/LLVMIR/ModuleImport.h
    mlir/lib/Target/LLVMIR/CMakeLists.txt
    mlir/lib/Target/LLVMIR/DebugImporter.h
    mlir/lib/Target/LLVMIR/ModuleImport.cpp
    mlir/test/Dialect/LLVMIR/layout.mlir
    mlir/test/Target/LLVMIR/Import/data-layout.ll
    mlir/test/Target/LLVMIR/Import/import-failure.ll

Removed: 
    


################################################################################
diff  --git a/mlir/include/mlir/Target/LLVMIR/ModuleImport.h b/mlir/include/mlir/Target/LLVMIR/ModuleImport.h
index e1a94d6b80cc9..61413c5ced201 100644
--- a/mlir/include/mlir/Target/LLVMIR/ModuleImport.h
+++ b/mlir/include/mlir/Target/LLVMIR/ModuleImport.h
@@ -32,6 +32,7 @@ namespace mlir {
 namespace LLVM {
 
 namespace detail {
+class DataLayoutImporter;
 class DebugImporter;
 class LoopAnnotationImporter;
 } // namespace detail
@@ -58,6 +59,10 @@ class ModuleImport {
   /// Converts all global variables of the LLVM module to MLIR global variables.
   LogicalResult convertGlobals();
 
+  /// Converts the data layout of the LLVM module to an MLIR data layout
+  /// specification.
+  LogicalResult convertDataLayout();
+
   /// Stores the mapping between an LLVM value and its MLIR counterpart.
   void mapValue(llvm::Value *llvm, Value mlir) { mapValue(llvm) = mlir; }
 

diff  --git a/mlir/lib/Target/LLVMIR/CMakeLists.txt b/mlir/lib/Target/LLVMIR/CMakeLists.txt
index da28c36394248..f2d95949a9740 100644
--- a/mlir/lib/Target/LLVMIR/CMakeLists.txt
+++ b/mlir/lib/Target/LLVMIR/CMakeLists.txt
@@ -3,6 +3,7 @@ add_subdirectory(Dialect)
 set(LLVM_OPTIONAL_SOURCES
   ConvertFromLLVMIR.cpp
   ConvertToLLVMIR.cpp
+  DataLayoutImporter.cpp
   DebugTranslation.cpp
   DebugImporter.cpp
   LoopAnnotationImporter.cpp
@@ -58,6 +59,7 @@ add_mlir_translation_library(MLIRToLLVMIRTranslationRegistration
   )
 
 add_mlir_translation_library(MLIRTargetLLVMIRImport
+  DataLayoutImporter.cpp
   DebugImporter.cpp
   LoopAnnotationImporter.cpp
   ModuleImport.cpp

diff  --git a/mlir/lib/Target/LLVMIR/DataLayoutImporter.cpp b/mlir/lib/Target/LLVMIR/DataLayoutImporter.cpp
new file mode 100644
index 0000000000000..af480c597a97f
--- /dev/null
+++ b/mlir/lib/Target/LLVMIR/DataLayoutImporter.cpp
@@ -0,0 +1,286 @@
+//===- DataLayoutImporter.cpp - LLVM to MLIR data layout conversion -------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "DataLayoutImporter.h"
+#include "mlir/Dialect/DLTI/DLTI.h"
+#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
+#include "mlir/IR/Builders.h"
+#include "mlir/IR/BuiltinAttributes.h"
+#include "mlir/IR/BuiltinTypes.h"
+#include "mlir/Interfaces/DataLayoutInterfaces.h"
+#include "mlir/Target/LLVMIR/Import.h"
+#include "llvm/IR/DataLayout.h"
+
+using namespace mlir;
+using namespace mlir::LLVM;
+using namespace mlir::LLVM::detail;
+
+/// The default data layout used during the translation.
+static constexpr StringRef kDefaultDataLayout =
+    "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-"
+    "f16:16:16-f64:64:64-f128:128:128";
+
+FloatType mlir::LLVM::detail::getFloatType(MLIRContext *context,
+                                           unsigned width) {
+  switch (width) {
+  case 16:
+    return FloatType::getF16(context);
+  case 32:
+    return FloatType::getF32(context);
+  case 64:
+    return FloatType::getF64(context);
+  case 80:
+    return FloatType::getF80(context);
+  case 128:
+    return FloatType::getF128(context);
+  default:
+    return {};
+  }
+}
+
+FailureOr<StringRef>
+DataLayoutImporter::tryToParseAlphaPrefix(StringRef &token) const {
+  if (token.empty())
+    return failure();
+
+  StringRef prefix = token.take_while(isalpha);
+  if (prefix.empty())
+    return failure();
+
+  token.consume_front(prefix);
+  return prefix;
+}
+
+FailureOr<unsigned> DataLayoutImporter::tryToParseInt(StringRef &token) const {
+  unsigned parameter;
+  if (token.consumeInteger(/*Radix=*/10, parameter))
+    return failure();
+  return parameter;
+}
+
+FailureOr<SmallVector<unsigned>>
+DataLayoutImporter::tryToParseIntList(StringRef token) const {
+  SmallVector<StringRef> tokens;
+  token.consume_front(":");
+  token.split(tokens, ':');
+
+  // Parse an integer list.
+  SmallVector<unsigned> results(tokens.size());
+  for (auto [result, token] : llvm::zip(results, tokens))
+    if (token.getAsInteger(/*Radix=*/10, result))
+      return failure();
+  return results;
+}
+
+FailureOr<DenseIntElementsAttr>
+DataLayoutImporter::tryToParseAlignment(StringRef token) const {
+  FailureOr<SmallVector<unsigned>> alignment = tryToParseIntList(token);
+  if (failed(alignment))
+    return failure();
+  if (alignment->empty() || alignment->size() > 2)
+    return failure();
+
+  // Alignment specifications (such as 32 or 32:64) are of the
+  // form <abi>[:<pref>], where abi specifies the minimal alignment and pref the
+  // optional preferred alignment. The preferred alignment is set to the minimal
+  // alignment if not available.
+  unsigned minimal = (*alignment)[0];
+  unsigned preferred = alignment->size() == 1 ? minimal : (*alignment)[1];
+  return DenseIntElementsAttr::get(
+      VectorType::get({2}, IntegerType::get(context, 32)),
+      {minimal, preferred});
+}
+
+FailureOr<DenseIntElementsAttr>
+DataLayoutImporter::tryToParsePointerAlignment(StringRef token) const {
+  FailureOr<SmallVector<unsigned>> alignment = tryToParseIntList(token);
+  if (failed(alignment))
+    return failure();
+  if (alignment->size() < 2 || alignment->size() > 4)
+    return failure();
+
+  // Pointer alignment specifications (such as 64:32:64:32 or 32:32) are of
+  // the form <size>:<abi>[:<pref>][:<idx>], where size is the pointer size, abi
+  // specifies the minimal alignment, pref the optional preferred alignment, and
+  // idx the optional index computation bit width. The preferred alignment is
+  // set to the minimal alignment if not available and the index computation
+  // width is set to the pointer size if not available.
+  unsigned size = (*alignment)[0];
+  unsigned minimal = (*alignment)[1];
+  unsigned preferred = alignment->size() < 3 ? minimal : (*alignment)[2];
+  unsigned idx = alignment->size() < 4 ? size : (*alignment)[3];
+  return DenseIntElementsAttr::get(
+      VectorType::get({4}, IntegerType::get(context, 32)),
+      {size, minimal, preferred, idx});
+}
+
+LogicalResult DataLayoutImporter::tryToEmplaceAlignmentEntry(Type type,
+                                                             StringRef token) {
+  auto key = TypeAttr::get(type);
+  if (typeEntries.count(key))
+    return success();
+
+  FailureOr<DenseIntElementsAttr> params = tryToParseAlignment(token);
+  if (failed(params))
+    return failure();
+
+  typeEntries.try_emplace(key, DataLayoutEntryAttr::get(type, *params));
+  return success();
+}
+
+LogicalResult
+DataLayoutImporter::tryToEmplacePointerAlignmentEntry(LLVMPointerType type,
+                                                      StringRef token) {
+  auto key = TypeAttr::get(type);
+  if (typeEntries.count(key))
+    return success();
+
+  FailureOr<DenseIntElementsAttr> params = tryToParsePointerAlignment(token);
+  if (failed(params))
+    return failure();
+
+  typeEntries.try_emplace(key, DataLayoutEntryAttr::get(type, *params));
+  return success();
+}
+
+LogicalResult
+DataLayoutImporter::tryToEmplaceEndiannessEntry(StringRef endianness,
+                                                StringRef token) {
+  auto key = StringAttr::get(context, DLTIDialect::kDataLayoutEndiannessKey);
+  if (keyEntries.count(key))
+    return success();
+
+  if (!token.empty())
+    return failure();
+
+  keyEntries.try_emplace(
+      key, DataLayoutEntryAttr::get(key, StringAttr::get(context, endianness)));
+  return success();
+}
+
+LogicalResult
+DataLayoutImporter::tryToEmplaceAllocaAddrSpaceEntry(StringRef token) {
+  auto key =
+      StringAttr::get(context, DLTIDialect::kDataLayoutAllocaMemorySpaceKey);
+  if (keyEntries.count(key))
+    return success();
+
+  FailureOr<unsigned> space = tryToParseInt(token);
+  if (failed(space))
+    return failure();
+
+  // Only store the address space if it has a non-default value.
+  if (*space == 0)
+    return success();
+  OpBuilder builder(context);
+  keyEntries.try_emplace(
+      key, DataLayoutEntryAttr::get(key, builder.getUI32IntegerAttr(*space)));
+  return success();
+}
+
+void DataLayoutImporter::translateDataLayout(
+    const llvm::DataLayout &llvmDataLayout) {
+  dataLayout = {};
+
+  // Transform the data layout to its string representation and append the
+  // default data layout string specified in the language reference
+  // (https://llvm.org/docs/LangRef.html#data-layout). The translation then
+  // parses the string and ignores the default value if a specific kind occurs
+  // in both strings. Additionally, the following default values exist:
+  // - non-default address space pointer specifications default to the default
+  //   address space pointer specification
+  // - the alloca address space defaults to the default address space.
+  layoutStr = llvmDataLayout.getStringRepresentation();
+  if (!layoutStr.empty())
+    layoutStr += "-";
+  layoutStr += kDefaultDataLayout;
+  StringRef layout(layoutStr);
+
+  // Split the data layout string into tokens separated by a dash.
+  SmallVector<StringRef> tokens;
+  layout.split(tokens, '-');
+
+  for (StringRef token : tokens) {
+    lastToken = token;
+    FailureOr<StringRef> prefix = tryToParseAlphaPrefix(token);
+    if (failed(prefix))
+      return;
+
+    // Parse the endianness.
+    if (*prefix == "e") {
+      if (failed(tryToEmplaceEndiannessEntry(
+              DLTIDialect::kDataLayoutEndiannessLittle, token)))
+        return;
+      continue;
+    }
+    if (*prefix == "E") {
+      if (failed(tryToEmplaceEndiannessEntry(
+              DLTIDialect::kDataLayoutEndiannessBig, token)))
+        return;
+      continue;
+    }
+    // Parse the alloca address space.
+    if (*prefix == "A") {
+      if (failed(tryToEmplaceAllocaAddrSpaceEntry(token)))
+        return;
+      continue;
+    }
+    // Parse integer alignment specifications.
+    if (*prefix == "i") {
+      FailureOr<unsigned> width = tryToParseInt(token);
+      if (failed(width))
+        return;
+
+      Type type = IntegerType::get(context, *width);
+      if (failed(tryToEmplaceAlignmentEntry(type, token)))
+        return;
+      continue;
+    }
+    // Parse float alignment specifications.
+    if (*prefix == "f") {
+      FailureOr<unsigned> width = tryToParseInt(token);
+      if (failed(width))
+        return;
+
+      Type type = getFloatType(context, *width);
+      if (failed(tryToEmplaceAlignmentEntry(type, token)))
+        return;
+      continue;
+    }
+    // Parse pointer alignment specifications.
+    if (*prefix == "p") {
+      FailureOr<unsigned> space =
+          token.starts_with(":") ? 0 : tryToParseInt(token);
+      if (failed(space))
+        return;
+
+      auto type = LLVMPointerType::get(context, *space);
+      if (failed(tryToEmplacePointerAlignmentEntry(type, token)))
+        return;
+      continue;
+    }
+
+    // Store all tokens that have not been handled.
+    unhandledTokens.push_back(lastToken);
+  }
+
+  // Assemble all entries to a data layout specification.
+  SmallVector<DataLayoutEntryInterface> entries;
+  entries.reserve(typeEntries.size() + keyEntries.size());
+  for (const auto &it : typeEntries)
+    entries.push_back(it.second);
+  for (const auto &it : keyEntries)
+    entries.push_back(it.second);
+  dataLayout = DataLayoutSpecAttr::get(context, entries);
+}
+
+DataLayoutSpecInterface
+mlir::translateDataLayout(const llvm::DataLayout &dataLayout,
+                          MLIRContext *context) {
+  return DataLayoutImporter(context, dataLayout).getDataLayout();
+}

diff  --git a/mlir/lib/Target/LLVMIR/DataLayoutImporter.h b/mlir/lib/Target/LLVMIR/DataLayoutImporter.h
new file mode 100644
index 0000000000000..2b2fa663a63fb
--- /dev/null
+++ b/mlir/lib/Target/LLVMIR/DataLayoutImporter.h
@@ -0,0 +1,115 @@
+//===- DataLayoutImporter.h - LLVM to MLIR data layout conversion -*- C++ -*-=//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the translation between the LLVMIR data layout and the
+// corresponding MLIR representation.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_LIB_TARGET_LLVMIR_DATALAYOUTIMPORTER_H_
+#define MLIR_LIB_TARGET_LLVMIR_DATALAYOUTIMPORTER_H_
+
+#include "mlir/Dialect/LLVMIR/LLVMTypes.h"
+#include "mlir/IR/BuiltinAttributes.h"
+#include "mlir/Interfaces/DataLayoutInterfaces.h"
+
+namespace llvm {
+class StringRef;
+class DataLayout;
+} // namespace llvm
+
+namespace mlir {
+class FloatType;
+class MLIRContext;
+class Operation;
+
+namespace LLVM {
+class LLVMFuncOp;
+
+namespace detail {
+
+/// Returns a supported MLIR floating point type of the given bit width or
+/// null if the bit width is not supported.
+FloatType getFloatType(MLIRContext *context, unsigned width);
+
+/// Helper class that translates an LLVM data layout to an MLIR data layout
+/// specification. Only integer, float, pointer, alloca memory space, and
+/// endianness entries are translated. The class also returns all entries from
+/// the default data layout specification found in the language reference
+/// (https://llvm.org/docs/LangRef.html#data-layout) if they are not overwritten
+/// by the provided data layout.
+class DataLayoutImporter {
+public:
+  DataLayoutImporter(MLIRContext *context,
+                     const llvm::DataLayout &llvmDataLayout)
+      : context(context) {
+    translateDataLayout(llvmDataLayout);
+  }
+
+  /// Returns the MLIR data layout specification translated from the LLVM
+  /// data layout.
+  DataLayoutSpecInterface getDataLayout() const { return dataLayout; }
+
+  /// Returns the last data layout token that has been processed before
+  /// the data layout translation failed.
+  StringRef getLastToken() const { return lastToken; }
+
+  /// Returns the data layout tokens that have not been handled during the
+  /// data layout translation.
+  ArrayRef<StringRef> getUnhandledTokens() const { return unhandledTokens; }
+
+private:
+  /// Translates the LLVM `dataLayout` to an MLIR data layout specification.
+  void translateDataLayout(const llvm::DataLayout &llvmDataLayout);
+
+  /// Tries to parse the letter only prefix that identifies the specification
+  /// and removes the consumed characters from the beginning of the string.
+  FailureOr<StringRef> tryToParseAlphaPrefix(StringRef &token) const;
+
+  /// Tries to parse an integer parameter and removes the integer from the
+  /// beginning of the string.
+  FailureOr<unsigned> tryToParseInt(StringRef &token) const;
+
+  /// Tries to parse an integer parameter array.
+  FailureOr<SmallVector<unsigned>> tryToParseIntList(StringRef token) const;
+
+  /// Tries to parse the parameters of a type alignment entry.
+  FailureOr<DenseIntElementsAttr> tryToParseAlignment(StringRef token) const;
+
+  /// Tries to parse the parameters of a pointer alignment entry.
+  FailureOr<DenseIntElementsAttr>
+  tryToParsePointerAlignment(StringRef token) const;
+
+  /// Adds a type alignment entry if there is none yet.
+  LogicalResult tryToEmplaceAlignmentEntry(Type type, StringRef token);
+
+  /// Adds a pointer alignment entry if there is none yet.
+  LogicalResult tryToEmplacePointerAlignmentEntry(LLVMPointerType type,
+                                                  StringRef token);
+
+  /// Adds an endianness entry if there is none yet.
+  LogicalResult tryToEmplaceEndiannessEntry(StringRef endianness,
+                                            StringRef token);
+
+  /// Adds an alloca address space entry if there is none yet.
+  LogicalResult tryToEmplaceAllocaAddrSpaceEntry(StringRef token);
+
+  std::string layoutStr = {};
+  StringRef lastToken = {};
+  SmallVector<StringRef> unhandledTokens;
+  DenseMap<StringAttr, DataLayoutEntryInterface> keyEntries;
+  DenseMap<TypeAttr, DataLayoutEntryInterface> typeEntries;
+  MLIRContext *context;
+  DataLayoutSpecInterface dataLayout;
+};
+
+} // namespace detail
+} // namespace LLVM
+} // namespace mlir
+
+#endif // MLIR_LIB_TARGET_LLVMIR_DATALAYOUTIMPORTER_H_

diff  --git a/mlir/lib/Target/LLVMIR/DebugImporter.h b/mlir/lib/Target/LLVMIR/DebugImporter.h
index e7f2332ff436d..6f7e59eb60117 100644
--- a/mlir/lib/Target/LLVMIR/DebugImporter.h
+++ b/mlir/lib/Target/LLVMIR/DebugImporter.h
@@ -11,8 +11,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef MLIR_LIB_TARGET_LLVMIR_DEBUGIMPORT_H_
-#define MLIR_LIB_TARGET_LLVMIR_DEBUGIMPORT_H_
+#ifndef MLIR_LIB_TARGET_LLVMIR_DEBUGIMPORTER_H_
+#define MLIR_LIB_TARGET_LLVMIR_DEBUGIMPORTER_H_
 
 #include "mlir/Dialect/LLVMIR/LLVMDialect.h"
 #include "mlir/IR/BuiltinOps.h"
@@ -86,4 +86,4 @@ class DebugImporter {
 } // namespace LLVM
 } // namespace mlir
 
-#endif // MLIR_LIB_TARGET_LLVMIR_DEBUIMPORTN_H_
+#endif // MLIR_LIB_TARGET_LLVMIR_DEBUGIMPORTER_H_

diff  --git a/mlir/lib/Target/LLVMIR/ModuleImport.cpp b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
index 1405606b1f57d..c5f9d0d0a80d3 100644
--- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
@@ -15,6 +15,7 @@
 #include "mlir/Target/LLVMIR/Import.h"
 
 #include "AttrKindDetail.h"
+#include "DataLayoutImporter.h"
 #include "DebugImporter.h"
 #include "LoopAnnotationImporter.h"
 
@@ -80,25 +81,6 @@ static constexpr StringRef getGlobalMetadataOpName() {
   return "__llvm_global_metadata";
 }
 
-/// Returns a supported MLIR floating point type of the given bit width or null
-/// if the bit width is not supported.
-static FloatType getDLFloatType(MLIRContext &ctx, int32_t bitwidth) {
-  switch (bitwidth) {
-  case 16:
-    return FloatType::getF16(&ctx);
-  case 32:
-    return FloatType::getF32(&ctx);
-  case 64:
-    return FloatType::getF64(&ctx);
-  case 80:
-    return FloatType::getF80(&ctx);
-  case 128:
-    return FloatType::getF128(&ctx);
-  default:
-    return nullptr;
-  }
-}
-
 /// Converts the sync scope identifier of `inst` to the string representation
 /// necessary to build an atomic LLVM dialect operation. Returns the empty
 /// string if the operation has either no sync scope or the default system-level
@@ -148,105 +130,6 @@ static LogicalResult convertInstructionImpl(OpBuilder &odsBuilder,
   return failure();
 }
 
-/// Creates an attribute containing ABI and preferred alignment numbers parsed
-/// a string. The string may be either "abi:preferred" or just "abi". In the
-/// latter case, the preferred alignment is considered equal to ABI alignment.
-static DenseIntElementsAttr parseDataLayoutAlignment(MLIRContext &ctx,
-                                                     StringRef spec) {
-  auto i32 = IntegerType::get(&ctx, 32);
-
-  StringRef abiString, preferredString;
-  std::tie(abiString, preferredString) = spec.split(':');
-  int abi, preferred;
-  if (abiString.getAsInteger(/*Radix=*/10, abi))
-    return nullptr;
-
-  if (preferredString.empty())
-    preferred = abi;
-  else if (preferredString.getAsInteger(/*Radix=*/10, preferred))
-    return nullptr;
-
-  return DenseIntElementsAttr::get(VectorType::get({2}, i32), {abi, preferred});
-}
-
-/// Translate the given LLVM data layout into an MLIR equivalent using the DLTI
-/// dialect.
-DataLayoutSpecInterface
-mlir::translateDataLayout(const llvm::DataLayout &dataLayout,
-                          MLIRContext *context) {
-  assert(context && "expected MLIR context");
-  std::string layoutstr = dataLayout.getStringRepresentation();
-
-  // Remaining unhandled default layout defaults
-  // e (little endian if not set)
-  // p[n]:64:64:64 (non zero address spaces have 64-bit properties)
-  // Alloca address space defaults to 0.
-  std::string append =
-      "p:64:64:64-S0-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f16:16:16-f64:"
-      "64:64-f128:128:128-v64:64:64-v128:128:128-a:0:64-A0";
-  if (layoutstr.empty())
-    layoutstr = append;
-  else
-    layoutstr = layoutstr + "-" + append;
-
-  StringRef layout(layoutstr);
-
-  SmallVector<DataLayoutEntryInterface> entries;
-  StringSet<> seen;
-  while (!layout.empty()) {
-    // Split at '-'.
-    std::pair<StringRef, StringRef> split = layout.split('-');
-    StringRef current;
-    std::tie(current, layout) = split;
-
-    // Split at ':'.
-    StringRef kind, spec;
-    std::tie(kind, spec) = current.split(':');
-    if (seen.contains(kind))
-      continue;
-    seen.insert(kind);
-
-    char symbol = kind.front();
-    StringRef parameter = kind.substr(1);
-
-    if (symbol == 'i' || symbol == 'f') {
-      unsigned bitwidth;
-      if (parameter.getAsInteger(/*Radix=*/10, bitwidth))
-        return nullptr;
-      DenseIntElementsAttr params = parseDataLayoutAlignment(*context, spec);
-      if (!params)
-        return nullptr;
-      auto entry = DataLayoutEntryAttr::get(
-          symbol == 'i' ? static_cast<Type>(IntegerType::get(context, bitwidth))
-                        : getDLFloatType(*context, bitwidth),
-          params);
-      entries.emplace_back(entry);
-    } else if (symbol == 'e' || symbol == 'E') {
-      auto value = StringAttr::get(
-          context, symbol == 'e' ? DLTIDialect::kDataLayoutEndiannessLittle
-                                 : DLTIDialect::kDataLayoutEndiannessBig);
-      auto entry = DataLayoutEntryAttr::get(
-          StringAttr::get(context, DLTIDialect::kDataLayoutEndiannessKey),
-          value);
-      entries.emplace_back(entry);
-    } else if (symbol == 'A') {
-      unsigned addressSpace;
-      if (parameter.getAsInteger(/*Radix=*/10, addressSpace))
-        return nullptr;
-      // Skip storing if generic address space is defined.
-      if (addressSpace != 0) {
-        auto entry = DataLayoutEntryAttr::get(
-            StringAttr::get(context,
-                            DLTIDialect::kDataLayoutAllocaMemorySpaceKey),
-            mlir::Builder(context).getUI32IntegerAttr(addressSpace));
-        entries.emplace_back(entry);
-      }
-    }
-  }
-
-  return DataLayoutSpecAttr::get(context, entries);
-}
-
 /// Get a topologically sorted list of blocks for the given function.
 static SetVector<llvm::BasicBlock *>
 getTopologicallySortedBlocks(llvm::Function *func) {
@@ -675,6 +558,21 @@ LogicalResult ModuleImport::convertGlobals() {
   return success();
 }
 
+LogicalResult ModuleImport::convertDataLayout() {
+  Location loc = mlirModule.getLoc();
+  DataLayoutImporter dataLayoutImporter(context, llvmModule->getDataLayout());
+  if (!dataLayoutImporter.getDataLayout())
+    return emitError(loc, "cannot translate data layout: ")
+           << dataLayoutImporter.getLastToken();
+
+  for (StringRef token : dataLayoutImporter.getUnhandledTokens())
+    emitWarning(loc, "unhandled data layout token: ") << token;
+
+  mlirModule->setAttr(DLTIDialect::kDataLayoutAttrName,
+                      dataLayoutImporter.getDataLayout());
+  return success();
+}
+
 LogicalResult ModuleImport::convertFunctions() {
   for (llvm::Function &func : llvmModule->functions())
     if (failed(processFunction(&func)))
@@ -802,7 +700,7 @@ Attribute ModuleImport::getConstantAsAttr(llvm::Constant *value) {
     if (type->isBFloatTy())
       floatTy = FloatType::getBF16(context);
     else
-      floatTy = getDLFloatType(*context, type->getScalarSizeInBits());
+      floatTy = detail::getFloatType(context, type->getScalarSizeInBits());
     assert(floatTy && "unsupported floating point type");
     return builder.getFloatAttr(floatTy, c->getValueAPF());
   }
@@ -1736,17 +1634,11 @@ mlir::translateLLVMIRToModule(std::unique_ptr<llvm::Module> llvmModule,
       StringAttr::get(context, llvmModule->getSourceFileName()), /*line=*/0,
       /*column=*/0)));
 
-  DataLayoutSpecInterface dlSpec =
-      translateDataLayout(llvmModule->getDataLayout(), context);
-  if (!dlSpec) {
-    emitError(UnknownLoc::get(context), "can't translate data layout");
-    return {};
-  }
-  module.get()->setAttr(DLTIDialect::kDataLayoutAttrName, dlSpec);
-
   ModuleImport moduleImport(module.get(), std::move(llvmModule));
   if (failed(moduleImport.initializeImportInterface()))
     return {};
+  if (failed(moduleImport.convertDataLayout()))
+    return {};
   if (failed(moduleImport.convertMetadata()))
     return {};
   if (failed(moduleImport.convertGlobals()))

diff  --git a/mlir/test/Dialect/LLVMIR/layout.mlir b/mlir/test/Dialect/LLVMIR/layout.mlir
index d6e2013cc86ca..ba388c134682b 100644
--- a/mlir/test/Dialect/LLVMIR/layout.mlir
+++ b/mlir/test/Dialect/LLVMIR/layout.mlir
@@ -3,6 +3,11 @@
 module {
   // CHECK: @no_spec
   func.func @no_spec() {
+    // CHECK: alignment = 8
+    // CHECK: alloca_memory_space = 0
+    // CHECK: bitsize = 64
+    // CHECK: preferred = 8
+    // CHECK: size = 8
     "test.data_layout_query"() : () -> !llvm.ptr
     // CHECK: alignment = 8
     // CHECK: alloca_memory_space = 0

diff  --git a/mlir/test/Target/LLVMIR/Import/data-layout.ll b/mlir/test/Target/LLVMIR/Import/data-layout.ll
index 9bcd689e2ea3d..e29e1744c562a 100644
--- a/mlir/test/Target/LLVMIR/Import/data-layout.ll
+++ b/mlir/test/Target/LLVMIR/Import/data-layout.ll
@@ -1,11 +1,48 @@
-; RUN: mlir-translate -import-llvm %s | FileCheck %s
+; RUN: mlir-translate -import-llvm -split-input-file %s | FileCheck %s
 
-; CHECK: dlti.dl_spec = 
+; Test the default data layout import.
+
+; CHECK: dlti.dl_spec =
 ; CHECK: #dlti.dl_spec<
-; CHECK:   #dlti.dl_entry<"dlti.endianness", "little">
-; CHECK:   #dlti.dl_entry<i64, dense<64> : vector<2xi32>>
-; CHECK:   #dlti.dl_entry<f80, dense<128> : vector<2xi32>>
-; CHECK:   #dlti.dl_entry<i8, dense<8> : vector<2xi32>>
-target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+; CHECK-DAG:   #dlti.dl_entry<"dlti.endianness", "little">
+; CHECK-DAG:   #dlti.dl_entry<i1, dense<8> : vector<2xi32>>
+; CHECK-DAG:   #dlti.dl_entry<i8, dense<8> : vector<2xi32>>
+; CHECK-DAG:   #dlti.dl_entry<i16, dense<16> : vector<2xi32>>
+; CHECK-DAG:   #dlti.dl_entry<i32, dense<32> : vector<2xi32>>
+; CHECK-DAG:   #dlti.dl_entry<i64, dense<[32, 64]> : vector<2xi32>>
+; CHECK-DAG:   #dlti.dl_entry<!llvm.ptr, dense<64> : vector<4xi32>>
+; CHECK-DAG:   #dlti.dl_entry<f16, dense<16> : vector<2xi32>>
+; CHECK-DAG:   #dlti.dl_entry<f64, dense<64> : vector<2xi32>>
+; CHECK-DAG:   #dlti.dl_entry<f128, dense<128> : vector<2xi32>>
+; CHECK: >
+target datalayout = ""
+
+; // -----
+
+; CHECK: dlti.dl_spec =
+; CHECK: #dlti.dl_spec<
+; CHECK-DAG:   #dlti.dl_entry<"dlti.endianness", "little">
+; CHECK-DAG:   #dlti.dl_entry<i64, dense<64> : vector<2xi32>>
+; CHECK-DAG:   #dlti.dl_entry<f80, dense<128> : vector<2xi32>>
+; CHECK-DAG:   #dlti.dl_entry<i8, dense<8> : vector<2xi32>>
+; CHECK-DAG:   #dlti.dl_entry<!llvm.ptr<270>, dense<[32, 64, 64, 32]> : vector<4xi32>>
+; CHECK-DAG:   #dlti.dl_entry<!llvm.ptr<271>, dense<32> : vector<4xi32>>
+; CHECK-DAG:   #dlti.dl_entry<!llvm.ptr<272>, dense<64> : vector<4xi32>>
+target datalayout = "e-m:e-p270:32:64-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+
+; // -----
 
-declare void @foo()
+; CHECK: dlti.dl_spec =
+; CHECK: #dlti.dl_spec<
+; CHECK-DAG:   #dlti.dl_entry<"dlti.endianness", "big">
+; CHECK-DAG:   #dlti.dl_entry<!llvm.ptr<270>, dense<[16, 32, 64, 128]> : vector<4xi32>>
+; CHECK-DAG:   #dlti.dl_entry<"dlti.alloca_memory_space", 1 : ui32>
+; CHECK-DAG:   #dlti.dl_entry<i64, dense<[64, 128]> : vector<2xi32>>
+target datalayout = "E-p270:16:32:64:128-A1-i64:64:128"
+
+; // -----
+
+; CHECK: dlti.dl_spec =
+; CHECK: #dlti.dl_spec<
+; CHECK-NOT:   #dlti.dl_entry<"dlti.alloca_memory_space"
+target datalayout = "E-A0"

diff  --git a/mlir/test/Target/LLVMIR/Import/import-failure.ll b/mlir/test/Target/LLVMIR/Import/import-failure.ll
index 6ad38f80cc6ba..0db585ed846b7 100644
--- a/mlir/test/Target/LLVMIR/Import/import-failure.ll
+++ b/mlir/test/Target/LLVMIR/Import/import-failure.ll
@@ -337,3 +337,15 @@ declare void @llvm.experimental.noalias.scope.decl(metadata)
 !0 = !{!1}
 !1 = !{!1, !2}
 !2 = distinct !{!2, !"The domain"}
+
+; // -----
+
+; CHECK:      import-failure.ll
+; CHECK-SAME: error: cannot translate data layout: i8:8:8:8
+target datalayout = "e-i8:8:8:8"
+
+; // -----
+
+; CHECK:      import-failure.ll
+; CHECK-SAME: warning: unhandled data layout token: ni:42
+target datalayout = "e-ni:42-i64:64"


        


More information about the Mlir-commits mailing list