[Mlir-commits] [mlir] fbfbfa5 - [mlir] Support big-endian systems in DenseElementsAttr (multiple word)
Mehdi Amini
llvmlistbot at llvm.org
Thu Nov 19 21:33:16 PST 2020
Author: Haruki Imai
Date: 2020-11-20T05:09:33Z
New Revision: fbfbfa5c713f4b98f174f9ff3416eaf42d133bc0
URL: https://github.com/llvm/llvm-project/commit/fbfbfa5c713f4b98f174f9ff3416eaf42d133bc0
DIFF: https://github.com/llvm/llvm-project/commit/fbfbfa5c713f4b98f174f9ff3416eaf42d133bc0.diff
LOG: [mlir] Support big-endian systems in DenseElementsAttr (multiple word)
D78076 supports big endian in DenseElementsAttr, but does not work when
APInt has multiple words(the number of bits > 64). This patch updates
D78076 to support it.
This patch removed the fix in D78076 and re-implemented to support multiple words.
Reviewed By: rriddle
Differential Revision: https://reviews.llvm.org/D80272
Added:
Modified:
mlir/lib/IR/Attributes.cpp
Removed:
################################################################################
diff --git a/mlir/lib/IR/Attributes.cpp b/mlir/lib/IR/Attributes.cpp
index 354f6cc32c80..277607a5ab54 100644
--- a/mlir/lib/IR/Attributes.cpp
+++ b/mlir/lib/IR/Attributes.cpp
@@ -567,27 +567,70 @@ static bool getBit(const char *rawData, size_t bitPos) {
return (rawData[bitPos / CHAR_BIT] & (1 << (bitPos % CHAR_BIT))) != 0;
}
-/// 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) {
- char *dataPos =
- const_cast<char *>(reinterpret_cast<const char *>(value.getRawData()));
- if (llvm::support::endian::system_endianness() ==
- llvm::support::endianness::big)
- dataPos = dataPos + 8 - llvm::divideCeil(bitWidth, CHAR_BIT);
- return dataPos;
-}
-
-/// 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);
-}
-
-/// 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);
+/// Copy actual `numBytes` data from `value` (APInt) to char array(`result`) for
+/// BE format.
+static void copyAPIntToArrayForBEmachine(APInt value, size_t numBytes,
+ char *result) {
+ assert(llvm::support::endian::system_endianness() == // NOLINT
+ llvm::support::endianness::big); // NOLINT
+ assert(value.getNumWords() * APInt::APINT_WORD_SIZE >= numBytes);
+
+ // Copy the words filled with data.
+ // For example, when `value` has 2 words, the first word is filled with data.
+ // `value` (10 bytes, BE):|abcdefgh|------ij| ==> `result` (BE):|abcdefgh|--|
+ size_t numFilledWords = (value.getNumWords() - 1) * APInt::APINT_WORD_SIZE;
+ std::copy_n(reinterpret_cast<const char *>(value.getRawData()),
+ numFilledWords, result);
+ // Convert last word of APInt to LE format and store it in char
+ // array(`valueLE`).
+ // ex. last word of `value` (BE): |------ij| ==> `valueLE` (LE): |ji------|
+ size_t lastWordPos = numFilledWords;
+ SmallVector<char, 8> valueLE(APInt::APINT_WORD_SIZE);
+ DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
+ reinterpret_cast<const char *>(value.getRawData()) + lastWordPos,
+ valueLE.begin(), APInt::APINT_BITS_PER_WORD, 1);
+ // Extract actual APInt data from `valueLE`, convert endianness to BE format,
+ // and store it in `result`.
+ // ex. `valueLE` (LE): |ji------| ==> `result` (BE): |abcdefgh|ij|
+ DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
+ valueLE.begin(), result + lastWordPos,
+ (numBytes - lastWordPos) * CHAR_BIT, 1);
+}
+
+/// Copy `numBytes` data from `inArray`(char array) to `result`(APINT) for BE
+/// format.
+static void copyArrayToAPIntForBEmachine(const char *inArray, size_t numBytes,
+ APInt &result) {
+ assert(llvm::support::endian::system_endianness() == // NOLINT
+ llvm::support::endianness::big); // NOLINT
+ assert(result.getNumWords() * APInt::APINT_WORD_SIZE >= numBytes);
+
+ // Copy the data that fills the word of `result` from `inArray`.
+ // For example, when `result` has 2 words, the first word will be filled with
+ // data. So, the first 8 bytes are copied from `inArray` here.
+ // `inArray` (10 bytes, BE): |abcdefgh|ij|
+ // ==> `result` (2 words, BE): |abcdefgh|--------|
+ size_t numFilledWords = (result.getNumWords() - 1) * APInt::APINT_WORD_SIZE;
+ std::copy_n(
+ inArray, numFilledWords,
+ const_cast<char *>(reinterpret_cast<const char *>(result.getRawData())));
+
+ // Convert array data which will be last word of `result` to LE format, and
+ // store it in char array(`inArrayLE`).
+ // ex. `inArray` (last two bytes, BE): |ij| ==> `inArrayLE` (LE): |ji------|
+ size_t lastWordPos = numFilledWords;
+ SmallVector<char, 8> inArrayLE(APInt::APINT_WORD_SIZE);
+ DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
+ inArray + lastWordPos, inArrayLE.begin(),
+ (numBytes - lastWordPos) * CHAR_BIT, 1);
+
+ // Convert `inArrayLE` to BE format, and store it in last word of `result`.
+ // ex. `inArrayLE` (LE): |ji------| ==> `result` (BE): |abcdefgh|------ij|
+ DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
+ inArrayLE.begin(),
+ const_cast<char *>(reinterpret_cast<const char *>(result.getRawData())) +
+ lastWordPos,
+ APInt::APINT_BITS_PER_WORD, 1);
}
/// Writes value to the bit position `bitPos` in array `rawData`.
@@ -600,7 +643,20 @@ static void writeBits(char *rawData, size_t bitPos, APInt value) {
// Otherwise, the bit position is guaranteed to be byte aligned.
assert((bitPos % CHAR_BIT) == 0 && "expected bitPos to be 8-bit aligned");
- readAPInt(value, bitWidth, rawData + (bitPos / CHAR_BIT));
+ if (llvm::support::endian::system_endianness() ==
+ llvm::support::endianness::big) {
+ // Copy from `value` to `rawData + (bitPos / CHAR_BIT)`.
+ // Copying the first `llvm::divideCeil(bitWidth, CHAR_BIT)` bytes doesn't
+ // work correctly in BE format.
+ // ex. `value` (2 words including 10 bytes)
+ // ==> BE: |abcdefgh|------ij|, LE: |hgfedcba|ji------|
+ copyAPIntToArrayForBEmachine(value, llvm::divideCeil(bitWidth, CHAR_BIT),
+ rawData + (bitPos / CHAR_BIT));
+ } else {
+ std::copy_n(reinterpret_cast<const char *>(value.getRawData()),
+ llvm::divideCeil(bitWidth, CHAR_BIT),
+ rawData + (bitPos / CHAR_BIT));
+ }
}
/// Reads the next `bitWidth` bits from the bit position `bitPos` in array
@@ -613,7 +669,21 @@ static APInt readBits(const char *rawData, size_t bitPos, size_t bitWidth) {
// Otherwise, the bit position must be 8-bit aligned.
assert((bitPos % CHAR_BIT) == 0 && "expected bitPos to be 8-bit aligned");
APInt result(bitWidth, 0);
- writeAPInt(rawData + (bitPos / CHAR_BIT), bitWidth, result);
+ if (llvm::support::endian::system_endianness() ==
+ llvm::support::endianness::big) {
+ // Copy from `rawData + (bitPos / CHAR_BIT)` to `result`.
+ // Copying the first `llvm::divideCeil(bitWidth, CHAR_BIT)` bytes doesn't
+ // work correctly in BE format.
+ // ex. `result` (2 words including 10 bytes)
+ // ==> BE: |abcdefgh|------ij|, LE: |hgfedcba|ji------| This function
+ copyArrayToAPIntForBEmachine(rawData + (bitPos / CHAR_BIT),
+ llvm::divideCeil(bitWidth, CHAR_BIT), result);
+ } else {
+ std::copy_n(rawData + (bitPos / CHAR_BIT),
+ llvm::divideCeil(bitWidth, CHAR_BIT),
+ const_cast<char *>(
+ reinterpret_cast<const char *>(result.getRawData())));
+ }
return result;
}
@@ -1175,7 +1245,7 @@ void DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
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);
+ std::copy_n(inRawData + (nBytes - 1 - i), 1, outRawData + i);
break;
}
}
More information about the Mlir-commits
mailing list