[Mlir-commits] [mlir] a66e334 - [mlir] Convert raw data in dense element attributes for big-endian machines.

River Riddle llvmlistbot at llvm.org
Wed Oct 28 17:13:12 PDT 2020


Author: Haruki Imai
Date: 2020-10-28T17:06:16-07:00
New Revision: a66e334cebec0c54ec357436563ddf78e3caab72

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

LOG: [mlir] Convert raw data in dense element attributes for big-endian machines.

This patch fixes a bug [[ https://bugs.llvm.org/show_bug.cgi?id=46091 | 46091 ]]

Raw data for the `dense-element attribute` is written in little endian (LE) format.
This commit converts the format to big endian (BE) in ʻAttribute Parser` on the
 BE machine. Also, when outputting on a BE machine, the BE format is converted
 to LE in "AsmPrinter".

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

Added: 
    

Modified: 
    mlir/include/mlir/IR/Attributes.h
    mlir/lib/IR/AsmPrinter.cpp
    mlir/lib/IR/Attributes.cpp
    mlir/lib/Parser/AttributeParser.cpp
    mlir/test/IR/dense-elements-hex.mlir

Removed: 
    


################################################################################
diff  --git a/mlir/include/mlir/IR/Attributes.h b/mlir/include/mlir/IR/Attributes.h
index 263b35e22e92..b4a1473e1479 100644
--- a/mlir/include/mlir/IR/Attributes.h
+++ b/mlir/include/mlir/IR/Attributes.h
@@ -1140,6 +1140,25 @@ class DenseIntOrFPElementsAttr
 public:
   using Base::Base;
 
+  /// Convert endianess of input ArrayRef for big-endian(BE) machines. All of
+  /// the elements of `inRawData` has `type`. If `inRawData` is little endian
+  /// (LE), it is converted to big endian (BE). Conversely, if `inRawData` is
+  /// BE, converted to LE.
+  static void
+  convertEndianOfArrayRefForBEmachine(ArrayRef<char> inRawData,
+                                      MutableArrayRef<char> outRawData,
+                                      ShapedType type);
+
+  /// Convert endianess of input for big-endian(BE) machines. The number of
+  /// elements of `inRawData` is `numElements`, and each element has
+  /// `elementBitWidth` bits. If `inRawData` is little endian (LE), it is
+  /// converted to big endian (BE) and saved in `outRawData`. Conversely, if
+  /// `inRawData` is BE, converted to LE.
+  static void convertEndianOfCharForBEmachine(const char *inRawData,
+                                              char *outRawData,
+                                              size_t elementBitWidth,
+                                              size_t numElements);
+
 protected:
   friend DenseElementsAttr;
 

diff  --git a/mlir/lib/IR/AsmPrinter.cpp b/mlir/lib/IR/AsmPrinter.cpp
index 602138d3ada7..aa221fa37dbd 100644
--- a/mlir/lib/IR/AsmPrinter.cpp
+++ b/mlir/lib/IR/AsmPrinter.cpp
@@ -1506,8 +1506,22 @@ void ModulePrinter::printDenseIntOrFPElementsAttr(DenseIntOrFPElementsAttr attr,
   if (!attr.isSplat() && allowHex &&
       shouldPrintElementsAttrWithHex(numElements)) {
     ArrayRef<char> rawData = attr.getRawData();
-    os << '"' << "0x" << llvm::toHex(StringRef(rawData.data(), rawData.size()))
-       << "\"";
+    if (llvm::support::endian::system_endianness() ==
+        llvm::support::endianness::big) {
+      // Convert endianess in big-endian(BE) machines. `rawData` is BE in BE
+      // machines. It is converted here to print in LE format.
+      SmallVector<char, 64> outDataVec(rawData.size());
+      MutableArrayRef<char> convRawData(outDataVec);
+      DenseIntOrFPElementsAttr::convertEndianOfArrayRefForBEmachine(
+          rawData, convRawData, type);
+      os << '"' << "0x"
+         << llvm::toHex(StringRef(convRawData.data(), convRawData.size()))
+         << "\"";
+    } else {
+      os << '"' << "0x"
+         << llvm::toHex(StringRef(rawData.data(), rawData.size())) << "\"";
+    }
+
     return;
   }
 

diff  --git a/mlir/lib/IR/Attributes.cpp b/mlir/lib/IR/Attributes.cpp
index 9aa6bd820072..59a66d0c3425 100644
--- a/mlir/lib/IR/Attributes.cpp
+++ b/mlir/lib/IR/Attributes.cpp
@@ -1118,6 +1118,65 @@ DenseIntOrFPElementsAttr::getRawIntOrFloat(ShapedType type, ArrayRef<char> data,
   return getRaw(type, data, /*isSplat=*/numElements == 1);
 }
 
+void DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
+    const char *inRawData, char *outRawData, size_t elementBitWidth,
+    size_t numElements) {
+  using llvm::support::ulittle16_t;
+  using llvm::support::ulittle32_t;
+  using llvm::support::ulittle64_t;
+
+  assert(llvm::support::endian::system_endianness() == // NOLINT
+         llvm::support::endianness::big);              // NOLINT
+  // NOLINT to avoid warning message about replacing by static_assert()
+
+  // Following std::copy_n always converts endianness on BE machine.
+  switch (elementBitWidth) {
+  case 16: {
+    const ulittle16_t *inRawDataPos =
+        reinterpret_cast<const ulittle16_t *>(inRawData);
+    uint16_t *outDataPos = reinterpret_cast<uint16_t *>(outRawData);
+    std::copy_n(inRawDataPos, numElements, outDataPos);
+    break;
+  }
+  case 32: {
+    const ulittle32_t *inRawDataPos =
+        reinterpret_cast<const ulittle32_t *>(inRawData);
+    uint32_t *outDataPos = reinterpret_cast<uint32_t *>(outRawData);
+    std::copy_n(inRawDataPos, numElements, outDataPos);
+    break;
+  }
+  case 64: {
+    const ulittle64_t *inRawDataPos =
+        reinterpret_cast<const ulittle64_t *>(inRawData);
+    uint64_t *outDataPos = reinterpret_cast<uint64_t *>(outRawData);
+    std::copy_n(inRawDataPos, numElements, outDataPos);
+    break;
+  }
+  default: {
+    size_t nBytes = elementBitWidth / CHAR_BIT;
+    for (size_t i = 0; i < nBytes; i++)
+      std::copy_n(inRawData + (nBytes - 1 - i), numElements, outRawData + i);
+    break;
+  }
+  }
+}
+
+void DenseIntOrFPElementsAttr::convertEndianOfArrayRefForBEmachine(
+    ArrayRef<char> inRawData, MutableArrayRef<char> outRawData,
+    ShapedType type) {
+  size_t numElements = type.getNumElements();
+  Type elementType = type.getElementType();
+  if (ComplexType complexTy = elementType.dyn_cast<ComplexType>()) {
+    elementType = complexTy.getElementType();
+    numElements = numElements * 2;
+  }
+  size_t elementBitWidth = getDenseElementStorageWidth(elementType);
+  assert(numElements * elementBitWidth == inRawData.size() * CHAR_BIT &&
+         inRawData.size() <= outRawData.size());
+  convertEndianOfCharForBEmachine(inRawData.begin(), outRawData.begin(),
+                                  elementBitWidth, numElements);
+}
+
 //===----------------------------------------------------------------------===//
 // DenseFPElementsAttr
 //===----------------------------------------------------------------------===//

diff  --git a/mlir/lib/Parser/AttributeParser.cpp b/mlir/lib/Parser/AttributeParser.cpp
index 606b46bf32d5..ef060d481f2a 100644
--- a/mlir/lib/Parser/AttributeParser.cpp
+++ b/mlir/lib/Parser/AttributeParser.cpp
@@ -16,6 +16,7 @@
 #include "mlir/IR/IntegerSet.h"
 #include "mlir/IR/StandardTypes.h"
 #include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Endian.h"
 
 using namespace mlir;
 using namespace mlir::detail;
@@ -696,6 +697,20 @@ DenseElementsAttr TensorLiteralParser::getHexAttr(llvm::SMLoc loc,
     return nullptr;
   }
 
+  if (llvm::support::endian::system_endianness() ==
+      llvm::support::endianness::big) {
+    // Convert endianess in big-endian(BE) machines. `rawData` is
+    // little-endian(LE) because HEX in raw data of dense element attribute
+    // is always LE format. It is converted into BE here to be used in BE
+    // machines.
+    SmallVector<char, 64> outDataVec(rawData.size());
+    MutableArrayRef<char> convRawData(outDataVec);
+    DenseIntOrFPElementsAttr::convertEndianOfArrayRefForBEmachine(
+        rawData, convRawData, type);
+    return DenseElementsAttr::getFromRawBuffer(type, convRawData,
+                                               detectedSplat);
+  }
+
   return DenseElementsAttr::getFromRawBuffer(type, rawData, detectedSplat);
 }
 

diff  --git a/mlir/test/IR/dense-elements-hex.mlir b/mlir/test/IR/dense-elements-hex.mlir
index ff6d39d1f034..bd2a0276bce0 100644
--- a/mlir/test/IR/dense-elements-hex.mlir
+++ b/mlir/test/IR/dense-elements-hex.mlir
@@ -1,12 +1,21 @@
 // RUN: mlir-opt -allow-unregistered-dialect %s -verify-diagnostics -split-input-file -mlir-print-elementsattrs-with-hex-if-larger=1 | FileCheck %s --check-prefix=HEX
 // RUN: mlir-opt -allow-unregistered-dialect %s -verify-diagnostics -split-input-file | FileCheck %s
 
+// HEX: dense<"0x000020410000A040"> : tensor<2xf32>
+"foo.op"() {dense.attr = dense<[10.0, 5.0]> : tensor<2xf32>} : () -> ()
+
 // HEX: dense<"0x00000000000024400000000000001440"> : tensor<2xf64>
 "foo.op"() {dense.attr = dense<[10.0, 5.0]> : tensor<2xf64>} : () -> ()
 
+// CHECK: dense<[1.000000e+01, 5.000000e+00]> : tensor<2xf32>
+"foo.op"() {dense.attr = dense<"0x000020410000A040"> : tensor<2xf32>} : () -> ()
+
 // CHECK: dense<[1.000000e+01, 5.000000e+00]> : tensor<2xf64>
 "foo.op"() {dense.attr = dense<"0x00000000000024400000000000001440"> : tensor<2xf64>} : () -> ()
 
+// CHECK: dense<(1.000000e+01,5.000000e+00)> : tensor<2xcomplex<f32>>
+"foo.op"() {dense.attr = dense<"0x000020410000A040000020410000A040"> : tensor<2xcomplex<f32>>} : () -> ()
+
 // CHECK: dense<(1.000000e+01,5.000000e+00)> : tensor<2xcomplex<f64>>
 "foo.op"() {dense.attr = dense<"0x0000000000002440000000000000144000000000000024400000000000001440"> : tensor<2xcomplex<f64>>} : () -> ()
 


        


More information about the Mlir-commits mailing list