[PATCH] D80272: [mlir] Support big-endian systems in DenseElementsAttr (multiple word)

Haruki Imai via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Tue May 19 23:57:46 PDT 2020


imaihal created this revision.
Herald added subscribers: llvm-commits, jurahul, Kayjukh, frgossen, grosul1, Joonsoo, stephenneuendorffer, liufengdb, lucyrfox, mgester, arpith-jacob, nicolasvasilache, antiagainst, shauheen, jpienaar, rriddle, mehdi_amini.
Herald added a reviewer: rriddle.
Herald added a project: LLVM.

D78076 <https://reviews.llvm.org/D78076> supports big endian in DenseElementsAttr, but does not work when
APInt has multiple words(the number of bits > 64). This patch updates
D78076 <https://reviews.llvm.org/D78076> to support it.
 std::copy_n copies APInt raw data of multiple words by 1 byte from the
beginning of char array. This is no problem in little endian, but the
data is not copied correctly in big endian because the data in last word
is in the end of the char array.

- Example of APInt raw data of i67 included in "mlir/test/IR/parser.mlir". (Need 2 words)

Little endian (8 bytes from first word + first 1 bytes from second word):
Address(first word) |0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08|
Data                |0xfb 0xff 0xff 0xff 0xff 0xff 0xff 0xff|
Address(second word)|0x09 0x10 0x11 0x12 0x13 0x14 0x15 0x16|
Data                |0x07 0x00 0x00 0x00 0x00 0x00 0x00 0x00|

Big endian (8 bytes from first word + last 1 bytes from second word):
Address(first word) |0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08|
Data                |0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xfb|
Address(second word)|0x09 0x10 0x11 0x12 0x13 0x14 0x15 0x16|
Data                |0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x07|

  Therefore, first std::copy in this patch copies words which filled

with 8 bytes (first word in above example), then second std::copy copies
from last bytes in the last word (copy last 1 bytes of second word in
above example)


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D80272

Files:
  mlir/lib/IR/Attributes.cpp


Index: mlir/lib/IR/Attributes.cpp
===================================================================
--- mlir/lib/IR/Attributes.cpp
+++ mlir/lib/IR/Attributes.cpp
@@ -546,25 +546,57 @@
 
 /// 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 *getAPIntDataPosBE(APInt &value, size_t bitWidth, size_t wordNum) {
   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);
+  unsigned APIntBytesPerWord = APInt::APINT_BITS_PER_WORD / CHAR_BIT;
+
+  dataPos = dataPos + APIntBytesPerWord * wordNum -
+            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);
+  char *dataPos =
+      const_cast<char *>(reinterpret_cast<const char *>(value.getRawData()));
+  if (llvm::support::endian::system_endianness() ==
+      llvm::support::endianness::big) {
+    unsigned numFilledWords = bitWidth / APInt::APINT_BITS_PER_WORD;
+    unsigned resBits = bitWidth - numFilledWords * APInt::APINT_BITS_PER_WORD;
+    unsigned APIntBytesPerWord = APInt::APINT_BITS_PER_WORD / CHAR_BIT;
+    // Read words filled with 8 bytes data (multiple of `APINT_BITS_PER_WORD`
+    // bits)
+    std::copy_n(dataPos, APIntBytesPerWord * numFilledWords, outData);
+    // Then, read the rest bits from apropriate position in big endian
+    dataPos = getAPIntDataPosBE(value, resBits, numFilledWords + 1);
+    std::copy_n(dataPos, llvm::divideCeil(resBits, CHAR_BIT),
+                outData + APIntBytesPerWord * numFilledWords);
+  } 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<char *>(reinterpret_cast<const char *>(value.getRawData()));
+  if (llvm::support::endian::system_endianness() ==
+      llvm::support::endianness::big) {
+    unsigned numFilledWords = bitWidth / APInt::APINT_BITS_PER_WORD;
+    unsigned resBits = bitWidth - numFilledWords * APInt::APINT_BITS_PER_WORD;
+    unsigned APIntBytesPerWord = APInt::APINT_BITS_PER_WORD / CHAR_BIT;
+    // Write words filled with 8 bytes data (multiple of `APINT_BITS_PER_WORD`
+    // bits)
+    std::copy_n(inData, APIntBytesPerWord * numFilledWords, dataPos);
+    // Then, write the rest bits from apropriate position in big endian
+    dataPos = getAPIntDataPosBE(value, resBits, numFilledWords + 1);
+    std::copy_n(inData + APIntBytesPerWord * numFilledWords,
+                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`.


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D80272.265149.patch
Type: text/x-patch
Size: 3385 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20200520/a842e1e9/attachment.bin>


More information about the llvm-commits mailing list