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 @@ -17,6 +17,7 @@ #include "llvm/ADT/Sequence.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/Endian.h" +#include using namespace mlir; using namespace mlir::detail; @@ -555,25 +556,66 @@ /// Get start position of actual data in `value`. Actual data is /// stored in last `bitWidth`/CHAR_BIT bytes in big endian. -static char *getAPIntDataPos(APInt &value, size_t bitWidth) { +static char *getAPIntDataPos(APInt &value, size_t bitWidth, size_t wordNum) { char *dataPos = const_cast(reinterpret_cast(value.getRawData())); - if (llvm::support::endian::system_endianness() == - llvm::support::endianness::big) - dataPos = dataPos + 8 - llvm::divideCeil(bitWidth, CHAR_BIT); + unsigned apintBytesPerWord = APInt::APINT_BITS_PER_WORD / CHAR_BIT; + + dataPos = dataPos + apintBytesPerWord * wordNum - + llvm::divideCeil(bitWidth, CHAR_BIT); return dataPos; } +/// Get parameters for copying APInt in big-endian. `numFilledWords` is the +/// number of words which filled with 8 bytes(64 bits). `resBits` is the rest of +/// bit. `filledWordsElements` is the elements of `numFiiledWords` +static std::tuple +getAPIntCopyParam(size_t bitWidth) { + unsigned numFilledWords = bitWidth / APInt::APINT_BITS_PER_WORD; + unsigned resBits = bitWidth - numFilledWords * APInt::APINT_BITS_PER_WORD; + unsigned filledWordsElements = + numFilledWords * APInt::APINT_BITS_PER_WORD / CHAR_BIT; + return std::forward_as_tuple(numFilledWords, resBits, filledWordsElements); +} + /// Read APInt `value` from appropriate position. static void readAPInt(APInt &value, size_t bitWidth, char *outData) { - char *dataPos = getAPIntDataPos(value, bitWidth); - std::copy_n(dataPos, llvm::divideCeil(bitWidth, CHAR_BIT), outData); + char *dataPos = + const_cast(reinterpret_cast(value.getRawData())); + if (llvm::support::endian::system_endianness() == + llvm::support::endianness::big) { + unsigned numFilledWords, resBits, filledWordsElements; + std::tie(numFilledWords, resBits, filledWordsElements) = + getAPIntCopyParam(bitWidth); + // Read words filled with 8 bytes data + std::copy_n(dataPos, filledWordsElements, outData); + // Then, read the rest bits from apropriate position in big endian + dataPos = getAPIntDataPos(value, resBits, numFilledWords + 1); + std::copy_n(dataPos, llvm::divideCeil(resBits, CHAR_BIT), + outData + filledWordsElements); + } else { + std::copy_n(dataPos, llvm::divideCeil(bitWidth, CHAR_BIT), outData); + } } /// Write `inData` to appropriate position of APInt `value`. static void writeAPInt(const char *inData, size_t bitWidth, APInt &value) { - char *dataPos = getAPIntDataPos(value, bitWidth); - std::copy_n(inData, llvm::divideCeil(bitWidth, CHAR_BIT), dataPos); + char *dataPos = + const_cast(reinterpret_cast(value.getRawData())); + if (llvm::support::endian::system_endianness() == + llvm::support::endianness::big) { + unsigned numFilledWords, resBits, filledWordsElements; + std::tie(numFilledWords, resBits, filledWordsElements) = + getAPIntCopyParam(bitWidth); + // Write words filled with 8 bytes data + std::copy_n(inData, filledWordsElements, dataPos); + // Then, write the rest bits from apropriate position in big endian + dataPos = getAPIntDataPos(value, resBits, numFilledWords + 1); + std::copy_n(inData + filledWordsElements, + llvm::divideCeil(resBits, CHAR_BIT), dataPos); + } else { + std::copy_n(inData, llvm::divideCeil(bitWidth, CHAR_BIT), dataPos); + } } /// Writes value to the bit position `bitPos` in array `rawData`.