[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