[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