summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVictor Costan <pwnall@chromium.org>2023-01-12 13:33:26 +0000
committerVictor Costan <pwnall@chromium.org>2023-01-12 13:33:26 +0000
commit30326e5b8cae9b5f2ea640d74beb2562ced44219 (patch)
tree05e8f8f85caeaf1111fde0f607844a8fee5e7321
parent74960e8bd6e61e3a1f4e6a16097d4a7ce959663a (diff)
parent6c6e890ef961260b60f9f9a2051ac4618dbd06bd (diff)
downloadsnappy-git-30326e5b8cae9b5f2ea640d74beb2562ced44219.tar.gz
Merge pull request #150 from davemgreen:betterunalignedloads
PiperOrigin-RevId: 501489679
-rw-r--r--snappy-stubs-internal.h57
1 files changed, 45 insertions, 12 deletions
diff --git a/snappy-stubs-internal.h b/snappy-stubs-internal.h
index 7d43c92..1548ed7 100644
--- a/snappy-stubs-internal.h
+++ b/snappy-stubs-internal.h
@@ -171,27 +171,42 @@ class LittleEndian {
public:
// Functions to do unaligned loads and stores in little-endian order.
static inline uint16_t Load16(const void *ptr) {
- const uint8_t* const buffer = reinterpret_cast<const uint8_t*>(ptr);
-
// Compiles to a single mov/str on recent clang and gcc.
+#if SNAPPY_IS_BIG_ENDIAN
+ const uint8_t* const buffer = reinterpret_cast<const uint8_t*>(ptr);
return (static_cast<uint16_t>(buffer[0])) |
(static_cast<uint16_t>(buffer[1]) << 8);
+#else
+ // memcpy() turns into a single instruction early in the optimization
+ // pipeline (relatively to a series of byte accesses). So, using memcpy
+ // instead of byte accesses may lead to better decisions in more stages of
+ // the optimization pipeline.
+ uint16_t value;
+ std::memcpy(&value, ptr, 2);
+ return value;
+#endif
}
static inline uint32_t Load32(const void *ptr) {
- const uint8_t* const buffer = reinterpret_cast<const uint8_t*>(ptr);
-
// Compiles to a single mov/str on recent clang and gcc.
+#if SNAPPY_IS_BIG_ENDIAN
+ const uint8_t* const buffer = reinterpret_cast<const uint8_t*>(ptr);
return (static_cast<uint32_t>(buffer[0])) |
(static_cast<uint32_t>(buffer[1]) << 8) |
(static_cast<uint32_t>(buffer[2]) << 16) |
(static_cast<uint32_t>(buffer[3]) << 24);
+#else
+ // See Load16() for the rationale of using memcpy().
+ uint32_t value;
+ std::memcpy(&value, ptr, 4);
+ return value;
+#endif
}
static inline uint64_t Load64(const void *ptr) {
- const uint8_t* const buffer = reinterpret_cast<const uint8_t*>(ptr);
-
// Compiles to a single mov/str on recent clang and gcc.
+#if SNAPPY_IS_BIG_ENDIAN
+ const uint8_t* const buffer = reinterpret_cast<const uint8_t*>(ptr);
return (static_cast<uint64_t>(buffer[0])) |
(static_cast<uint64_t>(buffer[1]) << 8) |
(static_cast<uint64_t>(buffer[2]) << 16) |
@@ -200,30 +215,44 @@ class LittleEndian {
(static_cast<uint64_t>(buffer[5]) << 40) |
(static_cast<uint64_t>(buffer[6]) << 48) |
(static_cast<uint64_t>(buffer[7]) << 56);
+#else
+ // See Load16() for the rationale of using memcpy().
+ uint64_t value;
+ std::memcpy(&value, ptr, 8);
+ return value;
+#endif
}
static inline void Store16(void *dst, uint16_t value) {
- uint8_t* const buffer = reinterpret_cast<uint8_t*>(dst);
-
// Compiles to a single mov/str on recent clang and gcc.
+#if SNAPPY_IS_BIG_ENDIAN
+ uint8_t* const buffer = reinterpret_cast<uint8_t*>(dst);
buffer[0] = static_cast<uint8_t>(value);
buffer[1] = static_cast<uint8_t>(value >> 8);
+#else
+ // See Load16() for the rationale of using memcpy().
+ std::memcpy(dst, &value, 2);
+#endif
}
static void Store32(void *dst, uint32_t value) {
- uint8_t* const buffer = reinterpret_cast<uint8_t*>(dst);
-
// Compiles to a single mov/str on recent clang and gcc.
+#if SNAPPY_IS_BIG_ENDIAN
+ uint8_t* const buffer = reinterpret_cast<uint8_t*>(dst);
buffer[0] = static_cast<uint8_t>(value);
buffer[1] = static_cast<uint8_t>(value >> 8);
buffer[2] = static_cast<uint8_t>(value >> 16);
buffer[3] = static_cast<uint8_t>(value >> 24);
+#else
+ // See Load16() for the rationale of using memcpy().
+ std::memcpy(dst, &value, 4);
+#endif
}
static void Store64(void* dst, uint64_t value) {
- uint8_t* const buffer = reinterpret_cast<uint8_t*>(dst);
-
// Compiles to a single mov/str on recent clang and gcc.
+#if SNAPPY_IS_BIG_ENDIAN
+ uint8_t* const buffer = reinterpret_cast<uint8_t*>(dst);
buffer[0] = static_cast<uint8_t>(value);
buffer[1] = static_cast<uint8_t>(value >> 8);
buffer[2] = static_cast<uint8_t>(value >> 16);
@@ -232,6 +261,10 @@ class LittleEndian {
buffer[5] = static_cast<uint8_t>(value >> 40);
buffer[6] = static_cast<uint8_t>(value >> 48);
buffer[7] = static_cast<uint8_t>(value >> 56);
+#else
+ // See Load16() for the rationale of using memcpy().
+ std::memcpy(dst, &value, 8);
+#endif
}
static inline constexpr bool IsLittleEndian() {