[llvm] Clean up / speed up ULEB128 decoding (PR #73585)

via llvm-commits llvm-commits at lists.llvm.org
Mon Nov 27 14:54:22 PST 2023


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-binary-utilities

Author: Adrian Prantl (adrian-prantl)

<details>
<summary>Changes</summary>

This series of patches simplifies the two [U]LEB128 decoder functions in LLVM and makes them ever so slightly faster in the process.

As a quick performance test decoding DWARF I instructed dwarfdump to print all DIEs with the name "end" in clang.dSYM  without using the accelerator tables:
```
_build.ninja.noassert$ time bin/llvm-dwarfdump-old -n end -o /dev/null bin/clang-18.dSYM ; time bin/llvm-dwarfdump-new -n end -o /dev/null bin/clang-18.dSYM
bin/llvm-dwarfdump-old -n end -o /dev/null bin/clang-18.dSYM  20.34s user 0.51s system 98% cpu 21.151 total
bin/llvm-dwarfdump-new -n end -o /dev/null bin/clang-18.dSYM  20.15s user 0.50s system 98% cpu 20.950 total
_build.ninja.noassert$ time bin/llvm-dwarfdump-old -n end -o /dev/null bin/clang-18.dSYM ; time bin/llvm-dwarfdump-new -n end -o /dev/null bin/clang-18.dSYM
bin/llvm-dwarfdump-old -n end -o /dev/null bin/clang-18.dSYM  20.33s user 0.50s system 98% cpu 21.178 total
bin/llvm-dwarfdump-new -n end -o /dev/null bin/clang-18.dSYM  20.21s user 0.50s system 98% cpu 21.027 total
_build.ninja.noassert$ time bin/llvm-dwarfdump-old -n end -o /dev/null bin/clang-18.dSYM ; time bin/llvm-dwarfdump-new -n end -o /dev/null bin/clang-18.dSYM
bin/llvm-dwarfdump-old -n end -o /dev/null bin/clang-18.dSYM  20.35s user 0.53s system 98% cpu 21.224 total
bin/llvm-dwarfdump-new -n end -o /dev/null bin/clang-18.dSYM  20.27s user 0.49s system 98% cpu 21.057 total
```

---
Full diff: https://github.com/llvm/llvm-project/pull/73585.diff


2 Files Affected:

- (modified) llvm/include/llvm/Support/LEB128.h (+18-15) 
- (modified) llvm/lib/Object/MachOObjectFile.cpp (+1-1) 


``````````diff
diff --git a/llvm/include/llvm/Support/LEB128.h b/llvm/include/llvm/Support/LEB128.h
index a5d367279aefe64..3d5e98c4b2cddee 100644
--- a/llvm/include/llvm/Support/LEB128.h
+++ b/llvm/include/llvm/Support/LEB128.h
@@ -125,29 +125,30 @@ inline unsigned encodeULEB128(uint64_t Value, uint8_t *p,
 }
 
 /// Utility function to decode a ULEB128 value.
+///
+/// If \p error is non-null, it will point to a static error message,
+/// if an error occured. It will not be modified on success.
 inline uint64_t decodeULEB128(const uint8_t *p, unsigned *n = nullptr,
                               const uint8_t *end = nullptr,
                               const char **error = nullptr) {
   const uint8_t *orig_p = p;
   uint64_t Value = 0;
   unsigned Shift = 0;
-  if (error)
-    *error = nullptr;
   do {
-    if (p == end) {
+    if (LLVM_UNLIKELY(p == end)) {
       if (error)
         *error = "malformed uleb128, extends past end";
-      if (n)
-        *n = (unsigned)(p - orig_p);
-      return 0;
+      Value = 0;
+      break;
     }
     uint64_t Slice = *p & 0x7f;
-    if ((Shift >= 64 && Slice != 0) || Slice << Shift >> Shift != Slice) {
+    if (LLVM_UNLIKELY(Shift >= 63) &&
+        ((Shift == 63 && ((Slice << Shift) >> Shift) != Slice) ||
+         (Shift > 63 && Slice != 0))) {
       if (error)
         *error = "uleb128 too big for uint64";
-      if (n)
-        *n = (unsigned)(p - orig_p);
-      return 0;
+      Value = 0;
+      break;
     }
     Value += Slice << Shift;
     Shift += 7;
@@ -158,6 +159,9 @@ inline uint64_t decodeULEB128(const uint8_t *p, unsigned *n = nullptr,
 }
 
 /// Utility function to decode a SLEB128 value.
+///
+/// If \p error is non-null, it will point to a static error message,
+/// if an error occured. It will not be modified on success.
 inline int64_t decodeSLEB128(const uint8_t *p, unsigned *n = nullptr,
                              const uint8_t *end = nullptr,
                              const char **error = nullptr) {
@@ -165,10 +169,8 @@ inline int64_t decodeSLEB128(const uint8_t *p, unsigned *n = nullptr,
   int64_t Value = 0;
   unsigned Shift = 0;
   uint8_t Byte;
-  if (error)
-    *error = nullptr;
   do {
-    if (p == end) {
+    if (LLVM_UNLIKELY(p == end)) {
       if (error)
         *error = "malformed sleb128, extends past end";
       if (n)
@@ -177,8 +179,9 @@ inline int64_t decodeSLEB128(const uint8_t *p, unsigned *n = nullptr,
     }
     Byte = *p;
     uint64_t Slice = Byte & 0x7f;
-    if ((Shift >= 64 && Slice != (Value < 0 ? 0x7f : 0x00)) ||
-        (Shift == 63 && Slice != 0 && Slice != 0x7f)) {
+    if (LLVM_UNLIKELY(Shift >= 63) &&
+        ((Shift == 63 && Slice != 0 && Slice != 0x7f) ||
+         (Shift > 63 && Slice != (Value < 0 ? 0x7f : 0x00)))) {
       if (error)
         *error = "sleb128 too big for int64";
       if (n)
diff --git a/llvm/lib/Object/MachOObjectFile.cpp b/llvm/lib/Object/MachOObjectFile.cpp
index aa57de16ed18f44..11ad8aeae65da5d 100644
--- a/llvm/lib/Object/MachOObjectFile.cpp
+++ b/llvm/lib/Object/MachOObjectFile.cpp
@@ -2996,7 +2996,7 @@ void ExportEntry::pushNode(uint64_t offset) {
   ErrorAsOutParameter ErrAsOutParam(E);
   const uint8_t *Ptr = Trie.begin() + offset;
   NodeState State(Ptr);
-  const char *error;
+  const char *error = nullptr;
   uint64_t ExportInfoSize = readULEB128(State.Current, &error);
   if (error) {
     *E = malformedError("export info size " + Twine(error) +

``````````

</details>


https://github.com/llvm/llvm-project/pull/73585


More information about the llvm-commits mailing list