Commit 513a6f93 by Martijn Vels Committed by Copybara-Service

Optimize `Cord::Swap()` for missed compiler optimization in clang.

PiperOrigin-RevId: 603342563
Change-Id: I1cd80103377f457770d5178dad8b56ae459cbd55
parent 4c7e7c7d
...@@ -1170,7 +1170,8 @@ inline void Cord::InlineRep::Swap(absl::Nonnull<Cord::InlineRep*> rhs) { ...@@ -1170,7 +1170,8 @@ inline void Cord::InlineRep::Swap(absl::Nonnull<Cord::InlineRep*> rhs) {
if (rhs == this) { if (rhs == this) {
return; return;
} }
std::swap(data_, rhs->data_); using std::swap;
swap(data_, rhs->data_);
} }
inline absl::Nullable<const char*> Cord::InlineRep::data() const { inline absl::Nullable<const char*> Cord::InlineRep::data() const {
......
...@@ -520,6 +520,7 @@ class InlineData { ...@@ -520,6 +520,7 @@ class InlineData {
constexpr InlineData(const InlineData& rhs) noexcept; constexpr InlineData(const InlineData& rhs) noexcept;
InlineData& operator=(const InlineData& rhs) noexcept; InlineData& operator=(const InlineData& rhs) noexcept;
friend void swap(InlineData& lhs, InlineData& rhs) noexcept;
friend bool operator==(const InlineData& lhs, const InlineData& rhs) { friend bool operator==(const InlineData& lhs, const InlineData& rhs) {
#ifdef ABSL_INTERNAL_CORD_HAVE_SANITIZER #ifdef ABSL_INTERNAL_CORD_HAVE_SANITIZER
...@@ -770,6 +771,12 @@ class InlineData { ...@@ -770,6 +771,12 @@ class InlineData {
char data[kMaxInline + 1]; char data[kMaxInline + 1];
AsTree as_tree; AsTree as_tree;
}; };
// TODO(b/145829486): see swap(InlineData, InlineData) for more info.
inline void SwapValue(Rep rhs, Rep& refrhs) {
memcpy(&refrhs, this, sizeof(*this));
memcpy(this, &rhs, sizeof(*this));
}
}; };
// Private implementation of `Compare()` // Private implementation of `Compare()`
...@@ -884,6 +891,19 @@ inline void CordRep::Unref(CordRep* rep) { ...@@ -884,6 +891,19 @@ inline void CordRep::Unref(CordRep* rep) {
} }
} }
inline void swap(InlineData& lhs, InlineData& rhs) noexcept {
lhs.unpoison();
rhs.unpoison();
// TODO(b/145829486): `std::swap(lhs.rep_, rhs.rep_)` results in bad codegen
// on clang, spilling the temporary swap value on the stack. Since `Rep` is
// trivial, we can make clang DTRT by calling a hand-rolled `SwapValue` where
// we pass `rhs` both by value (register allocated) and by reference. The IR
// then folds and inlines correctly into an optimized swap without spill.
lhs.rep_.SwapValue(rhs.rep_, rhs.rep_);
rhs.poison();
lhs.poison();
}
} // namespace cord_internal } // namespace cord_internal
ABSL_NAMESPACE_END ABSL_NAMESPACE_END
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment