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,11 @@ public: using Base::Base; + /// Convert endianess of raw data for big-endian(BE) machines. + /// `inRawData` LE -> `outRawData` BE, `inRawData` BE -> `outRawData` LE + static void convEndianBE(ArrayRef inRawData, + MutableArrayRef outRawData, ShapedType type); + 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 @@ -1505,7 +1505,14 @@ auto numElements = type.getNumElements(); if (!attr.isSplat() && allowHex && shouldPrintElementsAttrWithHex(numElements)) { - ArrayRef rawData = attr.getRawData(); + ArrayRef inRawData = attr.getRawData(); + // Convert endianess in big-endian(BE) machines. `inRawData` is BE in BE + // machines. It is converted here to print in LE format. Not converted + // in little-endian(LE) machines. + SmallVector outDataVec; + MutableArrayRef rawData = + llvm::makeMutableArrayRef((char *)outDataVec.data(), inRawData.size()); + DenseIntOrFPElementsAttr::convEndianBE(inRawData, rawData, type); 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 @@ -21,6 +21,9 @@ using namespace mlir; using namespace mlir::detail; +using llvm::support::ulittle16_t; +using llvm::support::ulittle32_t; +using llvm::support::ulittle64_t; //===----------------------------------------------------------------------===// // AttributeStorage @@ -1118,6 +1121,44 @@ return getRaw(type, data, /*isSplat=*/numElements == 1); } +void DenseIntOrFPElementsAttr::convEndianBE(ArrayRef inRawData, + MutableArrayRef outRawData, + ShapedType type) { + uint64_t numElements = type.getNumElements(); + Type elementType = type.getElementType(); + if (ComplexType complexTy = elementType.dyn_cast()) { + elementType = complexTy.getElementType(); + numElements = numElements * 2; + } + size_t storageBitWidth = getDenseElementStorageWidth(elementType); + assert(numElements * storageBitWidth == inRawData.size() * CHAR_BIT && + inRawData.size() <= outRawData.size()); + switch (storageBitWidth) { + case 16: { + const ulittle16_t *inRawDataPos = + reinterpret_cast(inRawData.begin()); + uint16_t *outDataPos = reinterpret_cast(outRawData.begin()); + std::copy_n(inRawDataPos, numElements, outDataPos); + break; + } + case 32: { + const ulittle32_t *inRawDataPos = + reinterpret_cast(inRawData.begin()); + uint32_t *outDataPos = reinterpret_cast(outRawData.begin()); + std::copy_n(inRawDataPos, numElements, outDataPos); + break; + } + case 64: { + const ulittle64_t *inRawDataPos = + reinterpret_cast(inRawData.begin()); + uint64_t *outDataPos = reinterpret_cast(outRawData.begin()); + std::copy_n(inRawDataPos, numElements, outDataPos); + break; + } + } + return; +} + //===----------------------------------------------------------------------===// // 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 @@ -12,10 +12,12 @@ #include "Parser.h" #include "mlir/IR/AffineMap.h" +#include "mlir/IR/Attributes.h" #include "mlir/IR/Dialect.h" #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; @@ -694,14 +696,23 @@ if (parseElementAttrHexValues(p, hexStorage.getValue(), data)) return nullptr; - ArrayRef rawData(data.data(), data.size()); + ArrayRef inRawData(data.data(), data.size()); bool detectedSplat = false; - if (!DenseElementsAttr::isValidRawBuffer(type, rawData, detectedSplat)) { + if (!DenseElementsAttr::isValidRawBuffer(type, inRawData, detectedSplat)) { p.emitError(loc) << "elements hex data size is invalid for provided type: " << type; return nullptr; } + // Convert endianess in big-endian(BE) machines. `inRawData` 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. Not converted in LE machines. + SmallVector outDataVec; + MutableArrayRef rawData = + llvm::makeMutableArrayRef((char *)outDataVec.data(), inRawData.size()); + DenseIntOrFPElementsAttr::convEndianBE(inRawData, rawData, type); + 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>} : () -> ()