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) {
if (rhs == this) {
return;
}
std::swap(data_, rhs->data_);
using std::swap;
swap(data_, rhs->data_);
}
inline absl::Nullable<const char*> Cord::InlineRep::data() const {
......
......@@ -520,6 +520,7 @@ class InlineData {
constexpr InlineData(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) {
#ifdef ABSL_INTERNAL_CORD_HAVE_SANITIZER
......@@ -770,6 +771,12 @@ class InlineData {
char data[kMaxInline + 1];
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()`
......@@ -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
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