Index: libcxx/include/functional
===================================================================
--- libcxx/include/functional
+++ libcxx/include/functional
@@ -144,6 +144,12 @@
     bool operator()(const T& x, const T& y) const;
 };
 
+struct compare_three_way {
+    template <class T, class U>
+      requires three_way_comparable_with<T, U> || BUILTIN-PTR-THREE-WAY(T, U)
+    constexpr auto operator()(T&& t, U&& u) const;
+};
+
 template <class T> // <class T=void> in C++14
 struct logical_and : binary_function<T, T, bool>
 {
@@ -506,6 +512,10 @@
 #include <utility>
 #include <version>
 
+#if !defined(_LIBCPP_HAS_NO_SPACESHIP_OPERATOR)
+#include <compare>
+#endif // __LIBCPP_HAS_NO_SPACESHIP_OPERATOR
+
 #include <__functional_base>
 
 #if defined(_LIBCPP_HAS_BLOCKS_RUNTIME) && !defined(_LIBCPP_HAS_OBJC_ARC)
@@ -816,6 +826,18 @@
 };
 #endif
 
+#if !defined(_LIBCPP_HAS_NO_SPACESHIP_OPERATOR)
+struct compare_three_way {
+    template <class _T1, class _T2>
+      // TODO(cjdb): needs concept three_way_comparable_with
+    constexpr auto operator()(_T1&& __t, _T2&& __u) const
+    _NOEXCEPT_(noexcept(_VSTD::forward<_T1>(__t) <=> _VSTD::forward<_T2>(__u)))
+    -> decltype        (_VSTD::forward<_T1>(__t) <=> _VSTD::forward<_T2>(__u))
+        { return _VSTD::forward<_T1>(__t) <=> _VSTD::forward<_T2>(__u); }
+    using is_transparent = void;
+};
+#endif // _LIBCPP_HAS_NO_SPACESHIP_OPERATOR
+
 
 #if _LIBCPP_STD_VER > 11
 template <class _Tp = void>
Index: libcxx/test/std/utilities/function.objects/comparisons/compare_three_way.pass.cpp
===================================================================
--- /dev/null
+++ libcxx/test/std/utilities/function.objects/comparisons/compare_three_way.pass.cpp
@@ -0,0 +1,71 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17
+
+// <functional>
+
+// less
+
+#include <functional>
+#include <compare>
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "pointer_comparison_test_helper.h"
+
+template <class T>
+void do_pointer_comparison_test() {
+  std::vector<std::shared_ptr<T> > pointers;
+  const std::size_t test_size = 100;
+  for (size_t i = 0; i < test_size; ++i)
+    pointers.push_back(std::shared_ptr<T>(new T()));
+  std::compare_three_way comp;
+  std::less vcomp;
+  std::less ucomp;
+  for (size_t i = 0; i < test_size; ++i) {
+    for (size_t j = 0; j < test_size; ++j) {
+      T* lhs = pointers[i].get();
+      T* rhs = pointers[j].get();
+      std::uintptr_t lhs_uint = reinterpret_cast<std::uintptr_t>(lhs);
+      std::uintptr_t rhs_uint = reinterpret_cast<std::uintptr_t>(rhs);
+      assert(vcomp(lhs, rhs) == ucomp(lhs_uint, rhs_uint));
+      assert((comp(lhs, rhs) == std::strong_ordering::less) ==
+             ucomp(lhs_uint, rhs_uint));
+    }
+  }
+}
+
+int main(int, char**) {
+  typedef std::compare_three_way F;
+  const F f = F();
+  assert(f(36, 36) == std::strong_ordering::equal);
+  assert(f(36, 6) == std::strong_ordering::greater);
+  assert(f(6, 36) == std::strong_ordering::less);
+  {
+    // test total ordering of int* for compare_three_way.
+    do_pointer_comparison_test<int>();
+  }
+
+  assert(f(36, 36) == std::strong_ordering::equal);
+  assert(f(36, 6) == std::strong_ordering::greater);
+  assert(f(6, 36) == std::strong_ordering::less);
+  assert(f(36, 6.0) == std::partial_ordering::greater);
+  assert(f(36.0, 6) == std::partial_ordering::greater);
+  assert(f(6, 36.0) == std::partial_ordering::less);
+  assert(f(6.0, 36) == std::partial_ordering::less);
+
+  constexpr std::strong_ordering foo = std::compare_three_way()(36, 36);
+  static_assert(foo == std::strong_ordering::equal, "");
+
+  constexpr std::partial_ordering bar = std::compare_three_way()(36.0, 36);
+  static_assert(bar == std::partial_ordering::equivalent, "");
+
+  return 0;
+}