Make checkMaxBetweenExclusive a multi-version function

This introduces more branches but reduces code size
This commit is contained in:
2024-08-02 21:09:55 -07:00
parent 493a6572ad
commit 0e574856be

View File

@@ -2114,8 +2114,9 @@ scan16(const InternalVersionT *vs, int begin, int end, // GCOVR_EXCL_LINE
// path of n + [child], where child in (begin, end) is <= readVersion. Does not
// account for the range version of firstGt(searchpath(n) + [end - 1])
template <bool kAVX512>
bool checkMaxBetweenExclusive(Node *n, int begin, int end,
InternalVersionT readVersion, ReadContext *tls) {
bool checkMaxBetweenExclusiveImpl(Node *n, int begin, int end,
InternalVersionT readVersion,
ReadContext *tls) {
++tls->range_read_node_scan_accum;
assume(-1 <= begin);
assume(begin <= 256);
@@ -2363,6 +2364,22 @@ bool checkMaxBetweenExclusive(Node *n, int begin, int end,
}
}
#if defined(HAS_AVX) && !defined(__SANITIZE_THREAD__)
// This gets covered in local development
// GCOVR_EXCL_START
__attribute__((target("avx512f"))) bool
checkMaxBetweenExclusive(Node *n, int begin, int end,
InternalVersionT readVersion, ReadContext *tls) {
return checkMaxBetweenExclusiveImpl<true>(n, begin, end, readVersion, tls);
}
// GCOVR_EXCL_STOP
__attribute__((target("default")))
#endif
bool checkMaxBetweenExclusive(Node *n, int begin, int end,
InternalVersionT readVersion, ReadContext *tls) {
return checkMaxBetweenExclusiveImpl<false>(n, begin, end, readVersion, tls);
}
Vector<uint8_t> getSearchPath(Arena &arena, Node *n) {
assert(n != nullptr);
auto result = vector<uint8_t>(arena);
@@ -2385,7 +2402,6 @@ Vector<uint8_t> getSearchPath(Arena &arena, Node *n) {
//
// Precondition: transitively, no child of n has a search path that's a longer
// prefix of key than n
template <bool kAVX512>
bool checkRangeStartsWith(Node *n, std::span<const uint8_t> key, int begin,
int end, InternalVersionT readVersion,
ReadContext *tls) {
@@ -2395,7 +2411,7 @@ bool checkRangeStartsWith(Node *n, std::span<const uint8_t> key, int begin,
auto remaining = key;
auto *impl = tls->impl;
if (remaining.size() == 0) {
return checkMaxBetweenExclusive<kAVX512>(n, begin, end, readVersion, tls);
return checkMaxBetweenExclusive(n, begin, end, readVersion, tls);
}
auto *child = getChild(n, remaining[0]);
@@ -2454,7 +2470,7 @@ downLeftSpine:
namespace {
// Return true if the max version among all keys that start with key[:prefixLen]
// that are >= key is <= readVersion
template <bool kAVX512> struct CheckRangeLeftSide {
struct CheckRangeLeftSide {
CheckRangeLeftSide(Node *n, std::span<const uint8_t> key, int prefixLen,
InternalVersionT readVersion, ReadContext *tls)
: n(n), remaining(key), prefixLen(prefixLen), readVersion(readVersion),
@@ -2487,8 +2503,7 @@ template <bool kAVX512> struct CheckRangeLeftSide {
}
if (searchPathLen >= prefixLen) {
if (!checkMaxBetweenExclusive<kAVX512>(n, remaining[0], 256, readVersion,
tls)) {
if (!checkMaxBetweenExclusive(n, remaining[0], 256, readVersion, tls)) {
ok = false;
return true;
}
@@ -2570,7 +2585,7 @@ template <bool kAVX512> struct CheckRangeLeftSide {
// Return true if the max version among all keys that start with key[:prefixLen]
// that are < key is <= readVersion
template <bool kAVX512> struct CheckRangeRightSide {
struct CheckRangeRightSide {
CheckRangeRightSide(Node *n, std::span<const uint8_t> key, int prefixLen,
InternalVersionT readVersion, ReadContext *tls)
: n(n), key(key), remaining(key), prefixLen(prefixLen),
@@ -2613,8 +2628,7 @@ template <bool kAVX512> struct CheckRangeRightSide {
return true;
}
if (!checkMaxBetweenExclusive<kAVX512>(n, -1, remaining[0], readVersion,
tls)) {
if (!checkMaxBetweenExclusive(n, -1, remaining[0], readVersion, tls)) {
ok = false;
return true;
}
@@ -2701,10 +2715,9 @@ template <bool kAVX512> struct CheckRangeRightSide {
};
} // namespace
template <bool kAVX512>
bool checkRangeReadImpl(Node *n, std::span<const uint8_t> begin,
std::span<const uint8_t> end,
InternalVersionT readVersion, ReadContext *tls) {
bool checkRangeRead(Node *n, std::span<const uint8_t> begin,
std::span<const uint8_t> end, InternalVersionT readVersion,
ReadContext *tls) {
int lcp = longestCommonPrefix(begin.data(), end.data(),
std::min(begin.size(), end.size()));
if (lcp == int(begin.size()) && end.size() == begin.size() + 1 &&
@@ -2746,22 +2759,19 @@ bool checkRangeReadImpl(Node *n, std::span<const uint8_t> begin,
lcp -= consumed;
if (lcp == int(begin.size())) {
CheckRangeRightSide<kAVX512> checkRangeRightSide{n, end, lcp, readVersion,
tls};
CheckRangeRightSide checkRangeRightSide{n, end, lcp, readVersion, tls};
while (!checkRangeRightSide.step())
;
return checkRangeRightSide.ok;
}
if (!checkRangeStartsWith<kAVX512>(n, begin.subspan(0, lcp), begin[lcp],
end[lcp], readVersion, tls)) {
if (!checkRangeStartsWith(n, begin.subspan(0, lcp), begin[lcp], end[lcp],
readVersion, tls)) {
return false;
}
CheckRangeLeftSide<kAVX512> checkRangeLeftSide{n, begin, lcp + 1, readVersion,
tls};
CheckRangeRightSide<kAVX512> checkRangeRightSide{n, end, lcp + 1, readVersion,
tls};
CheckRangeLeftSide checkRangeLeftSide{n, begin, lcp + 1, readVersion, tls};
CheckRangeRightSide checkRangeRightSide{n, end, lcp + 1, readVersion, tls};
for (;;) {
bool leftDone = checkRangeLeftSide.step();
@@ -2800,45 +2810,8 @@ template __attribute__((always_inline, target("avx512f"))) bool
scan16<true>(const InternalVersionT *vs, int begin, int end,
InternalVersionT readVersion);
template __attribute__((target("avx512f"))) bool
checkMaxBetweenExclusive<true>(Node *n, int begin, int end,
InternalVersionT readVersion, ReadContext *);
template __attribute__((target("avx512f"))) bool
checkRangeStartsWith<true>(Node *n, std::span<const uint8_t> key, int begin,
int end, InternalVersionT readVersion,
ReadContext *);
template __attribute__((target("avx512f"))) bool
CheckRangeLeftSide<true>::step();
template __attribute__((target("avx512f"))) bool
CheckRangeRightSide<true>::step();
template __attribute__((target("avx512f"))) bool
checkRangeReadImpl<true>(Node *n, std::span<const uint8_t> begin,
std::span<const uint8_t> end,
InternalVersionT readVersion, ReadContext *);
#endif
#if defined(__SANITIZE_THREAD__) || !defined(__x86_64__)
bool checkRangeRead(Node *n, std::span<const uint8_t> begin,
std::span<const uint8_t> end, InternalVersionT readVersion,
ReadContext *tls) {
return checkRangeReadImpl<false>(n, begin, end, readVersion, tls);
}
#else
// Only one of these is ever exercised. I'm not worried about somehow not
// calling one of these though.
// GCOVR_EXCL_START
__attribute__((target("default"))) bool
checkRangeRead(Node *n, std::span<const uint8_t> begin,
std::span<const uint8_t> end, InternalVersionT readVersion,
ReadContext *tls) {
return checkRangeReadImpl<false>(n, begin, end, readVersion, tls);
}
__attribute__((target("avx512f"))) bool
checkRangeRead(Node *n, std::span<const uint8_t> begin,
std::span<const uint8_t> end, InternalVersionT readVersion,
ReadContext *tls) {
return checkRangeReadImpl<true>(n, begin, end, readVersion, tls);
}
// GCOVR_EXCL_STOP
checkMaxBetweenExclusiveImpl<true>(Node *n, int begin, int end,
InternalVersionT readVersion, ReadContext *);
#endif
// Returns a pointer to the newly inserted node. Caller must set