summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLang Hames <lhames@gmail.com>2019-04-17 15:38:27 +0000
committerLang Hames <lhames@gmail.com>2019-04-17 15:38:27 +0000
commitc1106c9b1161a120ccc0c44b0dcab0b403860ad2 (patch)
tree9f5874fc27cd96942ad4fa5f933b3570c1a11dae
parent258a425c69f0f611ae237ad507252ad18048d2ab (diff)
downloadbcm5719-llvm-c1106c9b1161a120ccc0c44b0dcab0b403860ad2.tar.gz
bcm5719-llvm-c1106c9b1161a120ccc0c44b0dcab0b403860ad2.zip
[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 llvm-svn: 358584
-rw-r--r--llvm/include/llvm/Support/BinaryStreamReader.h12
-rw-r--r--llvm/include/llvm/Support/BinaryStreamWriter.h14
-rw-r--r--llvm/lib/Support/BinaryStreamReader.cpp33
-rw-r--r--llvm/lib/Support/BinaryStreamWriter.cpp13
-rw-r--r--llvm/unittests/Support/BinaryStreamTest.cpp71
5 files changed, 142 insertions, 1 deletions
diff --git a/llvm/include/llvm/Support/BinaryStreamReader.h b/llvm/include/llvm/Support/BinaryStreamReader.h
index 32e57284482..d8fddde66bf 100644
--- a/llvm/include/llvm/Support/BinaryStreamReader.h
+++ b/llvm/include/llvm/Support/BinaryStreamReader.h
@@ -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.
diff --git a/llvm/include/llvm/Support/BinaryStreamWriter.h b/llvm/include/llvm/Support/BinaryStreamWriter.h
index ae019c81e15..86d2389d918 100644
--- a/llvm/include/llvm/Support/BinaryStreamWriter.h
+++ b/llvm/include/llvm/Support/BinaryStreamWriter.h
@@ -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
diff --git a/llvm/lib/Support/BinaryStreamReader.cpp b/llvm/lib/Support/BinaryStreamReader.cpp
index 6f691bf4dcd..b17786593bd 100644
--- a/llvm/lib/Support/BinaryStreamReader.cpp
+++ b/llvm/lib/Support/BinaryStreamReader.cpp
@@ -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(ArrayRef<uint8_t> &Buffer, uint32_t Size) {
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) const {
BinaryStreamReader W1{First};
BinaryStreamReader W2{Second};
return std::make_pair(W1, W2);
-} \ No newline at end of file
+}
diff --git a/llvm/lib/Support/BinaryStreamWriter.cpp b/llvm/lib/Support/BinaryStreamWriter.cpp
index 929968bf2e4..986e18da281 100644
--- a/llvm/lib/Support/BinaryStreamWriter.cpp
+++ b/llvm/lib/Support/BinaryStreamWriter.cpp
@@ -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(ArrayRef<uint8_t> Buffer) {
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;
diff --git a/llvm/unittests/Support/BinaryStreamTest.cpp b/llvm/unittests/Support/BinaryStreamTest.cpp
index fe574072a11..5291a31013c 100644
--- a/llvm/unittests/Support/BinaryStreamTest.cpp
+++ b/llvm/unittests/Support/BinaryStreamTest.cpp
@@ -610,6 +610,77 @@ TEST_F(BinaryStreamTest, StreamReaderEnum) {
}
}
+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;
OpenPOWER on IntegriCloud