[llvm] r358584 - [Support] Add LEB128 support to BinaryStreamReader/Writer.

Lang Hames via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 17 08:38:27 PDT 2019


Author: lhames
Date: Wed Apr 17 08:38:27 2019
New Revision: 358584

URL: http://llvm.org/viewvc/llvm-project?rev=358584&view=rev
Log:
[Support] Add LEB128 support to BinaryStreamReader/Writer.

Summary:
This patch adds support for ULEB128 and SLEB128 encoding and decoding to
BinaryStreamWriter and BinaryStreamReader respectively.

Support for ULEB128/SLEB128 will be used for eh-frame parsing in the JITLink
library currently under development (see https://reviews.llvm.org/D58704).

Reviewers: zturner, dblaikie

Subscribers: kristina, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D60810

Modified:
    llvm/trunk/include/llvm/Support/BinaryStreamReader.h
    llvm/trunk/include/llvm/Support/BinaryStreamWriter.h
    llvm/trunk/lib/Support/BinaryStreamReader.cpp
    llvm/trunk/lib/Support/BinaryStreamWriter.cpp
    llvm/trunk/unittests/Support/BinaryStreamTest.cpp

Modified: llvm/trunk/include/llvm/Support/BinaryStreamReader.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/BinaryStreamReader.h?rev=358584&r1=358583&r2=358584&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/BinaryStreamReader.h (original)
+++ llvm/trunk/include/llvm/Support/BinaryStreamReader.h Wed Apr 17 08:38:27 2019
@@ -96,6 +96,18 @@ public:
     return Error::success();
   }
 
+  /// Read an unsigned LEB128 encoded value.
+  ///
+  /// \returns a success error code if the data was successfully read, otherwise
+  /// returns an appropriate error code.
+  Error readULEB128(uint64_t &Dest);
+
+  /// Read a signed LEB128 encoded value.
+  ///
+  /// \returns a success error code if the data was successfully read, otherwise
+  /// returns an appropriate error code.
+  Error readSLEB128(int64_t &Dest);
+
   /// Read a null terminated string from \p Dest.  Whether a copy occurs depends
   /// on the implementation of the underlying stream.  Updates the stream's
   /// offset to point after the newly read data.

Modified: llvm/trunk/include/llvm/Support/BinaryStreamWriter.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/BinaryStreamWriter.h?rev=358584&r1=358583&r2=358584&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/BinaryStreamWriter.h (original)
+++ llvm/trunk/include/llvm/Support/BinaryStreamWriter.h Wed Apr 17 08:38:27 2019
@@ -79,6 +79,20 @@ public:
     return writeInteger<U>(static_cast<U>(Num));
   }
 
+  /// Write the unsigned integer Value to the underlying stream using ULEB128
+  /// encoding.
+  ///
+  /// \returns a success error code if the data was successfully written,
+  /// otherwise returns an appropriate error code.
+  Error writeULEB128(uint64_t Value);
+
+  /// Write the unsigned integer Value to the underlying stream using ULEB128
+  /// encoding.
+  ///
+  /// \returns a success error code if the data was successfully written,
+  /// otherwise returns an appropriate error code.
+  Error writeSLEB128(int64_t Value);
+
   /// Write the string \p Str to the underlying stream followed by a null
   /// terminator.  On success, updates the offset so that subsequent writes
   /// occur at the next unwritten position.  \p Str need not be null terminated

Modified: llvm/trunk/lib/Support/BinaryStreamReader.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/BinaryStreamReader.cpp?rev=358584&r1=358583&r2=358584&view=diff
==============================================================================
--- llvm/trunk/lib/Support/BinaryStreamReader.cpp (original)
+++ llvm/trunk/lib/Support/BinaryStreamReader.cpp Wed Apr 17 08:38:27 2019
@@ -10,6 +10,7 @@
 
 #include "llvm/Support/BinaryStreamError.h"
 #include "llvm/Support/BinaryStreamRef.h"
+#include "llvm/Support/LEB128.h"
 
 using namespace llvm;
 using endianness = llvm::support::endianness;
@@ -40,6 +41,36 @@ Error BinaryStreamReader::readBytes(Arra
   return Error::success();
 }
 
+Error BinaryStreamReader::readULEB128(uint64_t &Dest) {
+  SmallVector<uint8_t, 10> EncodedBytes;
+  ArrayRef<uint8_t> NextByte;
+
+  // Copy the encoded ULEB into the buffer.
+  do {
+    if (auto Err = readBytes(NextByte, 1))
+      return Err;
+    EncodedBytes.push_back(NextByte[0]);
+  } while (NextByte[0] & 0x80);
+
+  Dest = decodeULEB128(EncodedBytes.begin(), nullptr, EncodedBytes.end());
+  return Error::success();
+}
+
+Error BinaryStreamReader::readSLEB128(int64_t &Dest) {
+  SmallVector<uint8_t, 10> EncodedBytes;
+  ArrayRef<uint8_t> NextByte;
+
+  // Copy the encoded ULEB into the buffer.
+  do {
+    if (auto Err = readBytes(NextByte, 1))
+      return Err;
+    EncodedBytes.push_back(NextByte[0]);
+  } while (NextByte[0] & 0x80);
+
+  Dest = decodeSLEB128(EncodedBytes.begin(), nullptr, EncodedBytes.end());
+  return Error::success();
+}
+
 Error BinaryStreamReader::readCString(StringRef &Dest) {
   uint32_t OriginalOffset = getOffset();
   uint32_t FoundOffset = 0;
@@ -145,4 +176,4 @@ BinaryStreamReader::split(uint32_t Off)
   BinaryStreamReader W1{First};
   BinaryStreamReader W2{Second};
   return std::make_pair(W1, W2);
-}
\ No newline at end of file
+}

Modified: llvm/trunk/lib/Support/BinaryStreamWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/BinaryStreamWriter.cpp?rev=358584&r1=358583&r2=358584&view=diff
==============================================================================
--- llvm/trunk/lib/Support/BinaryStreamWriter.cpp (original)
+++ llvm/trunk/lib/Support/BinaryStreamWriter.cpp Wed Apr 17 08:38:27 2019
@@ -11,6 +11,7 @@
 #include "llvm/Support/BinaryStreamError.h"
 #include "llvm/Support/BinaryStreamReader.h"
 #include "llvm/Support/BinaryStreamRef.h"
+#include "llvm/Support/LEB128.h"
 
 using namespace llvm;
 
@@ -31,6 +32,18 @@ Error BinaryStreamWriter::writeBytes(Arr
   return Error::success();
 }
 
+Error BinaryStreamWriter::writeULEB128(uint64_t Value) {
+  uint8_t EncodedBytes[10] = {0};
+  unsigned Size = encodeULEB128(Value, &EncodedBytes[0]);
+  return writeBytes({EncodedBytes, Size});
+}
+
+Error BinaryStreamWriter::writeSLEB128(int64_t Value) {
+  uint8_t EncodedBytes[10] = {0};
+  unsigned Size = encodeSLEB128(Value, &EncodedBytes[0]);
+  return writeBytes({EncodedBytes, Size});
+}
+
 Error BinaryStreamWriter::writeCString(StringRef Str) {
   if (auto EC = writeFixedString(Str))
     return EC;

Modified: llvm/trunk/unittests/Support/BinaryStreamTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/BinaryStreamTest.cpp?rev=358584&r1=358583&r2=358584&view=diff
==============================================================================
--- llvm/trunk/unittests/Support/BinaryStreamTest.cpp (original)
+++ llvm/trunk/unittests/Support/BinaryStreamTest.cpp Wed Apr 17 08:38:27 2019
@@ -610,6 +610,77 @@ TEST_F(BinaryStreamTest, StreamReaderEnu
   }
 }
 
+TEST_F(BinaryStreamTest, StreamReaderULEB128) {
+  std::vector<uint64_t> TestValues = {
+      0,                  // Zero
+      0x7F,               // One byte
+      0xFF,               // One byte, all-ones
+      0xAAAA,             // Two bytes
+      0xAAAAAAAA,         // Four bytes
+      0xAAAAAAAAAAAAAAAA, // Eight bytes
+      0xffffffffffffffff  // Eight bytess, all-ones
+  };
+
+  // Conservatively assume a 10-byte encoding for each of our LEB128s, with no
+  // alignment requirement.
+  initializeOutput(10 * TestValues.size(), 1);
+  initializeInputFromOutput(1);
+
+  for (auto &Stream : Streams) {
+    // Write fields.
+    BinaryStreamWriter Writer(*Stream.Output);
+    for (const auto &Value : TestValues)
+      ASSERT_THAT_ERROR(Writer.writeULEB128(Value), Succeeded());
+
+    // Read fields.
+    BinaryStreamReader Reader(*Stream.Input);
+    std::vector<uint64_t> Results;
+    Results.resize(TestValues.size());
+    for (unsigned I = 0; I != TestValues.size(); ++I)
+      ASSERT_THAT_ERROR(Reader.readULEB128(Results[I]), Succeeded());
+
+    for (unsigned I = 0; I != TestValues.size(); ++I)
+      EXPECT_EQ(TestValues[I], Results[I]);
+  }
+}
+
+TEST_F(BinaryStreamTest, StreamReaderSLEB128) {
+  std::vector<int64_t> TestValues = {
+      0,                  // Zero
+      0x7F,               // One byte
+      -0x7F,              // One byte, negative
+      0xFF,               // One byte, all-ones
+      0xAAAA,             // Two bytes
+      -0xAAAA,            // Two bytes, negative
+      0xAAAAAAAA,         // Four bytes
+      -0xAAAAAAAA,        // Four bytes, negative
+      0x2AAAAAAAAAAAAAAA, // Eight bytes
+      -0x7ffffffffffffff  // Eight bytess, negative
+  };
+
+  // Conservatively assume a 10-byte encoding for each of our LEB128s, with no
+  // alignment requirement.
+  initializeOutput(10 * TestValues.size(), 1);
+  initializeInputFromOutput(1);
+
+  for (auto &Stream : Streams) {
+    // Write fields.
+    BinaryStreamWriter Writer(*Stream.Output);
+    for (const auto &Value : TestValues)
+      ASSERT_THAT_ERROR(Writer.writeSLEB128(Value), Succeeded());
+
+    // Read fields.
+    BinaryStreamReader Reader(*Stream.Input);
+    std::vector<int64_t> Results;
+    Results.resize(TestValues.size());
+    for (unsigned I = 0; I != TestValues.size(); ++I)
+      ASSERT_THAT_ERROR(Reader.readSLEB128(Results[I]), Succeeded());
+
+    for (unsigned I = 0; I != TestValues.size(); ++I)
+      EXPECT_EQ(TestValues[I], Results[I]);
+  }
+}
+
 TEST_F(BinaryStreamTest, StreamReaderObject) {
   struct Foo {
     int X;




More information about the llvm-commits mailing list