From 6e212847acdbd046790cf0da60376e5adfed41be Mon Sep 17 00:00:00 2001 From: Andrew Noyes Date: Sat, 9 Mar 2024 19:45:54 -0800 Subject: [PATCH] Add assume macro Validated with cachegrind that this reduces instructions executed --- ConflictSet.cpp | 48 +++++++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/ConflictSet.cpp b/ConflictSet.cpp index ac83c01..08a67af 100644 --- a/ConflictSet.cpp +++ b/ConflictSet.cpp @@ -39,6 +39,22 @@ limitations under the License. #include +// Use assert for checking potentially complex properties during tests. +// Use assume to hint simple properties to the optimizer. + +// TODO use the c++23 version when that's available +#ifdef NDEBUG +#if __has_builtin(__builtin_assume) +#define assume(e) __builtin_assume(e) +#else +#define assume(e) \ + if (!(e)) \ + __builtin_unreachable() +#endif +#else +#define assume assert +#endif + // ==================== BEGIN IMPLEMENTATION ==================== struct Entry { @@ -129,25 +145,25 @@ private: }; bool BitSet::test(int i) const { - assert(0 <= i); - assert(i < 256); + assume(0 <= i); + assume(i < 256); return words[i >> 6] & (uint64_t(1) << (i & 63)); } void BitSet::set(int i) { - assert(0 <= i); - assert(i < 256); + assume(0 <= i); + assume(i < 256); words[i >> 6] |= uint64_t(1) << (i & 63); } void BitSet::reset(int i) { - assert(0 <= i); - assert(i < 256); + assume(0 <= i); + assume(i < 256); words[i >> 6] &= ~(uint64_t(1) << (i & 63)); } int BitSet::firstSetGeq(int i) const { - assert(0 <= i); + assume(0 <= i); // i may be >= 256 uint64_t mask = uint64_t(-1) << (i & 63); for (int j = i >> 6; j < 4; ++j) { @@ -860,9 +876,7 @@ int firstNeqStride(const uint8_t *ap, const uint8_t *bp) { } int longestCommonPrefix(const uint8_t *ap, const uint8_t *bp, int cl) { - if (cl < 0) { - __builtin_unreachable(); // GCOVR_EXCL_LINE - } + assume(cl >= 0); int i = 0; int end; @@ -944,7 +958,7 @@ struct SearchStepWise { SearchStepWise() {} SearchStepWise(Node *n, std::span remaining) : n(n), remaining(remaining) { - assert(n->partialKeyLen == 0); + assume(n->partialKeyLen == 0); } bool step() { @@ -1049,11 +1063,11 @@ downLeftSpine: // Return the max version among all keys starting with the search path of n + // [child], where child in (begin, end) int64_t maxBetweenExclusive(Node *n, int begin, int end) { - assert(-1 <= begin); - assert(begin <= 256); - assert(-1 <= end); - assert(end <= 256); - assert(begin < end); + assume(-1 <= begin); + assume(begin <= 256); + assume(-1 <= end); + assume(end <= 256); + assume(begin < end); int64_t result = std::numeric_limits::lowest(); { int c = getChildGeq(n, begin + 1); @@ -1503,7 +1517,7 @@ bool checkRangeRead(Node *n, std::span begin, 0); const int consumed = lcp - search.remaining.size(); - assert(consumed >= 0); + assume(consumed >= 0); begin = begin.subspan(consumed, int(begin.size()) - consumed); end = end.subspan(consumed, int(end.size()) - consumed);