Skip to content

Commit

Permalink
Call ParseVarint with a pointer to the specific result instead of alw…
Browse files Browse the repository at this point in the history
…ays passing in a uint64_t * when possible.

Specialize ParseVarint for bool, which then takes up much less code.

PiperOrigin-RevId: 485427698
  • Loading branch information
protobuf-github-bot authored and copybara-github committed Nov 1, 2022
1 parent 6c78c66 commit 411cba1
Showing 1 changed file with 76 additions and 8 deletions.
84 changes: 76 additions & 8 deletions src/google/protobuf/generated_message_tctable_lite.cc
Original file line number Diff line number Diff line change
Expand Up @@ -789,31 +789,99 @@ Parse64FallbackPair(const char* p, int64_t res1) {
return {p + 10, res1 & res2 & res3};
}

template <class Type>
inline PROTOBUF_ALWAYS_INLINE const char* ParseVarint(const char* p,
uint64_t* value) {
Type* value) {
static_assert(sizeof(Type) == 4 || sizeof(Type) == 8,
"Only [u]int32_t and [u]int64_t please");
int64_t byte = static_cast<int8_t>(*p);
if (PROTOBUF_PREDICT_TRUE(byte >= 0)) {
*value = byte;
return p + 1;
} else {
auto tmp = Parse64FallbackPair(p, byte);
if (PROTOBUF_PREDICT_TRUE(tmp.first)) *value = tmp.second;
if (PROTOBUF_PREDICT_TRUE(tmp.first)) {
*value = static_cast<Type>(tmp.second);
}
return tmp.first;
}
}

// This overload is specifically for handling bool, because bools have very
// different requirements and performance opportunities than ints.
inline PROTOBUF_ALWAYS_INLINE const char* ParseVarint(const char* p,
bool* value) {
unsigned char byte = static_cast<unsigned char>(*p++);
if (PROTOBUF_PREDICT_TRUE(byte == 0 || byte == 1)) {
// This is the code path almost always taken,
// so we take care to make it very efficient.
if (sizeof(byte) == sizeof(*value)) {
memcpy(value, &byte, 1);
} else {
// The C++ standard does not specify that a `bool` takes only one byte
*value = byte;
}
return p;
}
// This part, we just care about code size.
// Although it's almost never used, we have to support it because we guarantee
// compatibility for users who change a field from an int32 or int64 to a bool
if (PROTOBUF_PREDICT_FALSE(byte & 0x80)) {
byte = (byte - 0x80) | *p++;
if (PROTOBUF_PREDICT_FALSE(byte & 0x80)) {
byte = (byte - 0x80) | *p++;
if (PROTOBUF_PREDICT_FALSE(byte & 0x80)) {
byte = (byte - 0x80) | *p++;
if (PROTOBUF_PREDICT_FALSE(byte & 0x80)) {
byte = (byte - 0x80) | *p++;
if (PROTOBUF_PREDICT_FALSE(byte & 0x80)) {
byte = (byte - 0x80) | *p++;
if (PROTOBUF_PREDICT_FALSE(byte & 0x80)) {
byte = (byte - 0x80) | *p++;
if (PROTOBUF_PREDICT_FALSE(byte & 0x80)) {
byte = (byte - 0x80) | *p++;
if (PROTOBUF_PREDICT_FALSE(byte & 0x80)) {
byte = (byte - 0x80) | *p++;
if (PROTOBUF_PREDICT_FALSE(byte & 0x80)) {
byte = (byte - 0x80) | *p++;
if (PROTOBUF_PREDICT_FALSE(byte & 0x80)) {
return nullptr;
}
}
}
}
}
}
}
}
}
}
*value = byte;
return p;
}

template <typename FieldType, bool zigzag = false>
inline FieldType ZigZagDecodeHelper(uint64_t value) {
inline FieldType ZigZagDecodeHelper(FieldType value) {
return static_cast<FieldType>(value);
}

template <>
inline int32_t ZigZagDecodeHelper<int32_t, true>(uint64_t value) {
inline uint32_t ZigZagDecodeHelper<uint32_t, true>(uint32_t value) {
return WireFormatLite::ZigZagDecode32(value);
}

template <>
inline int64_t ZigZagDecodeHelper<int64_t, true>(uint64_t value) {
inline int32_t ZigZagDecodeHelper<int32_t, true>(int32_t value) {
return WireFormatLite::ZigZagDecode32(value);
}

template <>
inline uint64_t ZigZagDecodeHelper<uint64_t, true>(uint64_t value) {
return WireFormatLite::ZigZagDecode64(value);
}

template <>
inline int64_t ZigZagDecodeHelper<int64_t, true>(int64_t value) {
return WireFormatLite::ZigZagDecode64(value);
}

Expand Down Expand Up @@ -868,11 +936,11 @@ PROTOBUF_NOINLINE const char* TcParser::SingularVarBigint(
#if defined(__GNUC__)
// This empty asm block convinces the compiler that the contents of spill may
// have changed, and thus can't be cached in registers. It's similar to, but
// more optimal then, the effect of declaring it "volatile".
// more optimal than, the effect of declaring it "volatile".
asm("" : "+m"(spill));
#endif

uint64_t tmp;
FieldType tmp;
PROTOBUF_ASSUME(static_cast<int8_t>(*ptr) < 0);
ptr = ParseVarint(ptr, &tmp);

Expand Down Expand Up @@ -946,7 +1014,7 @@ PROTOBUF_ALWAYS_INLINE const char* TcParser::RepeatedVarint(
const auto expected_tag = UnalignedLoad<TagType>(ptr);
do {
ptr += sizeof(TagType);
uint64_t tmp;
FieldType tmp;
ptr = ParseVarint(ptr, &tmp);
if (ptr == nullptr) {
return Error(PROTOBUF_TC_PARAM_PASS);
Expand Down

0 comments on commit 411cba1

Please sign in to comment.