diff --git a/mlir/include/mlir/IR/Attributes.h b/mlir/include/mlir/IR/Attributes.h --- a/mlir/include/mlir/IR/Attributes.h +++ b/mlir/include/mlir/IR/Attributes.h @@ -1140,6 +1140,25 @@ 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 inRawData, + MutableArrayRef 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 --- a/mlir/lib/IR/AsmPrinter.cpp +++ b/mlir/lib/IR/AsmPrinter.cpp @@ -1506,8 +1506,22 @@ if (!attr.isSplat() && allowHex && shouldPrintElementsAttrWithHex(numElements)) { ArrayRef 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 outDataVec(rawData.size()); + MutableArrayRef 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 --- a/mlir/lib/IR/Attributes.cpp +++ b/mlir/lib/IR/Attributes.cpp @@ -1118,6 +1118,65 @@ 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(inRawData); + uint16_t *outDataPos = reinterpret_cast(outRawData); + std::copy_n(inRawDataPos, numElements, outDataPos); + break; + } + case 32: { + const ulittle32_t *inRawDataPos = + reinterpret_cast(inRawData); + uint32_t *outDataPos = reinterpret_cast(outRawData); + std::copy_n(inRawDataPos, numElements, outDataPos); + break; + } + case 64: { + const ulittle64_t *inRawDataPos = + reinterpret_cast(inRawData); + uint64_t *outDataPos = reinterpret_cast(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 inRawData, MutableArrayRef outRawData, + ShapedType type) { + size_t numElements = type.getNumElements(); + Type elementType = type.getElementType(); + if (ComplexType complexTy = elementType.dyn_cast()) { + 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 --- 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 @@ 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 outDataVec(rawData.size()); + MutableArrayRef 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 --- 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> +"foo.op"() {dense.attr = dense<"0x000020410000A040000020410000A040"> : tensor<2xcomplex>} : () -> () + // CHECK: dense<(1.000000e+01,5.000000e+00)> : tensor<2xcomplex> "foo.op"() {dense.attr = dense<"0x0000000000002440000000000000144000000000000024400000000000001440"> : tensor<2xcomplex>} : () -> ()