Skip to content

Commit 95eb2db

Browse files
authored
[libc++] std::cmp_less and other integer comparison functions could be improved (#151332)
Fix #65136 |Benchmark | Baseline | Candidate | Difference | % Difference |------------------------- | ---------- | ----------- | ------------ | -------------- |BM_CmpEqual_int_int | 0.46 | 0.46 | -0.00 | -0.62 |BM_CmpEqual_int_schar | 0.45 | 0.45 | -0.00 | -0.40 |BM_CmpEqual_int_short | 0.45 | 0.45 | 0.00 | 0.34 |BM_CmpEqual_int_uchar | 0.78 | 0.44 | -0.34 | -43.18 |BM_CmpEqual_int_uint | 0.90 | 0.66 | -0.24 | -26.84 |BM_CmpEqual_int_ushort | 0.78 | 0.45 | -0.33 | -42.20 |BM_CmpEqual_schar_int | 0.45 | 0.45 | -0.00 | -0.77 |BM_CmpEqual_schar_schar | 0.54 | 0.57 | 0.03 | 5.64 |BM_CmpEqual_schar_short | 0.92 | 0.88 | -0.04 | -4.80 |BM_CmpEqual_schar_uchar | 1.84 | 0.66 | -1.18 | -64.16 |BM_CmpEqual_schar_uint | 0.78 | 0.66 | -0.12 | -15.18 |BM_CmpEqual_schar_ushort | 1.01 | 0.66 | -0.35 | -34.53 |BM_CmpEqual_short_int | 0.45 | 0.45 | 0.00 | 0.03 |BM_CmpEqual_short_schar | 0.89 | 0.88 | -0.01 | -0.80 |BM_CmpEqual_short_short | 0.47 | 0.46 | -0.01 | -1.28 |BM_CmpEqual_short_uchar | 1.11 | 0.66 | -0.45 | -40.63 |BM_CmpEqual_short_uint | 0.77 | 0.66 | -0.12 | -14.88 |BM_CmpEqual_short_ushort | 1.76 | 0.66 | -1.10 | -62.64 |BM_CmpEqual_uchar_int | 0.79 | 0.44 | -0.35 | -44.06 |BM_CmpEqual_uchar_schar | 1.76 | 0.66 | -1.11 | -62.68 |BM_CmpEqual_uchar_short | 1.11 | 0.66 | -0.45 | -40.33 |BM_CmpEqual_uchar_uchar | 0.57 | 0.51 | -0.06 | -10.61 |BM_CmpEqual_uchar_uint | 0.45 | 0.44 | -0.01 | -1.74 |BM_CmpEqual_uchar_ushort | 0.77 | 0.77 | -0.00 | -0.64 |BM_CmpEqual_uint_int | 0.88 | 0.66 | -0.23 | -25.69 |BM_CmpEqual_uint_schar | 0.77 | 0.66 | -0.11 | -14.85 |BM_CmpEqual_uint_short | 0.77 | 0.66 | -0.11 | -14.56 |BM_CmpEqual_uint_uchar | 0.44 | 0.44 | -0.00 | -0.57 |BM_CmpEqual_uint_uint | 0.47 | 0.51 | 0.04 | 8.62 |BM_CmpEqual_uint_ushort | 0.45 | 0.44 | -0.00 | -0.47 |BM_CmpEqual_ushort_int | 0.77 | 0.45 | -0.33 | -42.02 |BM_CmpEqual_ushort_schar | 1.02 | 0.66 | -0.36 | -35.30 |BM_CmpEqual_ushort_short | 1.76 | 0.66 | -1.10 | -62.60 |BM_CmpEqual_ushort_uchar | 0.78 | 0.77 | -0.01 | -1.84 |BM_CmpEqual_ushort_uint | 0.45 | 0.45 | 0.00 | 0.24 |BM_CmpEqual_ushort_ushort | 0.46 | 0.51 | 0.05 | 11.00 |BM_CmpLess_int_int | 0.67 | 0.66 | -0.01 | -0.99 |BM_CmpLess_int_schar | 0.66 | 0.66 | -0.01 | -0.86 |BM_CmpLess_int_short | 0.66 | 0.66 | -0.00 | -0.57 |BM_CmpLess_int_uchar | 0.88 | 0.66 | -0.23 | -25.48 |BM_CmpLess_int_uint | 1.76 | 0.66 | -1.11 | -62.68 |BM_CmpLess_int_ushort | 0.89 | 0.66 | -0.23 | -25.50 |BM_CmpLess_schar_int | 0.66 | 0.66 | -0.00 | -0.44 |BM_CmpLess_schar_schar | 0.66 | 0.66 | -0.00 | -0.40 |BM_CmpLess_schar_short | 0.88 | 0.88 | -0.00 | -0.50 |BM_CmpLess_schar_uchar | 1.10 | 0.71 | -0.39 | -35.24 |BM_CmpLess_schar_uint | 0.89 | 0.66 | -0.23 | -25.66 |BM_CmpLess_schar_ushort | 0.99 | 0.77 | -0.22 | -22.49 |BM_CmpLess_short_int | 0.66 | 0.66 | -0.00 | -0.35 |BM_CmpLess_short_schar | 0.89 | 0.88 | -0.00 | -0.48 |BM_CmpLess_short_short | 0.66 | 0.66 | -0.00 | -0.34 |BM_CmpLess_short_uchar | 1.10 | 0.71 | -0.39 | -35.36 |BM_CmpLess_short_uint | 0.88 | 0.66 | -0.22 | -25.39 |BM_CmpLess_short_ushort | 1.77 | 0.77 | -1.00 | -56.42 |BM_CmpLess_uchar_int | 0.97 | 0.66 | -0.31 | -31.95 |BM_CmpLess_uchar_schar | 1.11 | 0.66 | -0.44 | -40.17 |BM_CmpLess_uchar_short | 1.19 | 0.66 | -0.53 | -44.59 |BM_CmpLess_uchar_uchar | 0.66 | 0.66 | -0.00 | -0.67 |BM_CmpLess_uchar_uint | 0.67 | 0.66 | -0.01 | -1.19 |BM_CmpLess_uchar_ushort | 0.77 | 0.77 | -0.00 | -0.40 |BM_CmpLess_uint_int | 1.76 | 0.66 | -1.10 | -62.59 |BM_CmpLess_uint_schar | 0.89 | 0.66 | -0.23 | -25.99 |BM_CmpLess_uint_short | 0.88 | 0.66 | -0.22 | -25.41 |BM_CmpLess_uint_uchar | 0.66 | 0.66 | -0.01 | -0.81 |BM_CmpLess_uint_uint | 0.66 | 0.66 | -0.00 | -0.71 |BM_CmpLess_uint_ushort | 0.66 | 0.66 | -0.00 | -0.29 |BM_CmpLess_ushort_int | 0.98 | 0.66 | -0.32 | -33.00 |BM_CmpLess_ushort_schar | 1.29 | 0.77 | -0.52 | -40.56 |BM_CmpLess_ushort_short | 1.77 | 0.77 | -1.00 | -56.55 |BM_CmpLess_ushort_uchar | 0.77 | 0.77 | -0.01 | -0.72 |BM_CmpLess_ushort_uint | 0.66 | 0.66 | -0.00 | -0.46 |BM_CmpLess_ushort_ushort | 0.66 | 0.66 | -0.00 | -0.71
1 parent 910c868 commit 95eb2db

File tree

2 files changed

+151
-0
lines changed

2 files changed

+151
-0
lines changed

libcxx/include/__utility/cmp.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,18 @@ _LIBCPP_BEGIN_NAMESPACE_STD
2626

2727
#if _LIBCPP_STD_VER >= 20
2828

29+
template <typename _Tp, typename _Ip>
30+
concept __comparison_can_promote_to =
31+
sizeof(_Tp) < sizeof(_Ip) || (sizeof(_Tp) == sizeof(_Ip) && __signed_integer<_Tp>);
32+
2933
template <__signed_or_unsigned_integer _Tp, __signed_or_unsigned_integer _Up>
3034
_LIBCPP_HIDE_FROM_ABI constexpr bool cmp_equal(_Tp __t, _Up __u) noexcept {
3135
if constexpr (is_signed_v<_Tp> == is_signed_v<_Up>)
3236
return __t == __u;
37+
else if constexpr (__comparison_can_promote_to<_Tp, int> && __comparison_can_promote_to<_Up, int>)
38+
return static_cast<int>(__t) == static_cast<int>(__u);
39+
else if constexpr (__comparison_can_promote_to<_Tp, long long> && __comparison_can_promote_to<_Up, long long>)
40+
return static_cast<long long>(__t) == static_cast<long long>(__u);
3341
else if constexpr (is_signed_v<_Tp>)
3442
return __t < 0 ? false : make_unsigned_t<_Tp>(__t) == __u;
3543
else
@@ -45,6 +53,10 @@ template <__signed_or_unsigned_integer _Tp, __signed_or_unsigned_integer _Up>
4553
_LIBCPP_HIDE_FROM_ABI constexpr bool cmp_less(_Tp __t, _Up __u) noexcept {
4654
if constexpr (is_signed_v<_Tp> == is_signed_v<_Up>)
4755
return __t < __u;
56+
else if constexpr (__comparison_can_promote_to<_Tp, int> && __comparison_can_promote_to<_Up, int>)
57+
return static_cast<int>(__t) < static_cast<int>(__u);
58+
else if constexpr (__comparison_can_promote_to<_Tp, long long> && __comparison_can_promote_to<_Up, long long>)
59+
return static_cast<long long>(__t) < static_cast<long long>(__u);
4860
else if constexpr (is_signed_v<_Tp>)
4961
return __t < 0 ? true : make_unsigned_t<_Tp>(__t) < __u;
5062
else
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// UNSUPPORTED: c++03, c++11, c++14, c++17
10+
11+
#include <utility>
12+
#include "../CartesianBenchmarks.h"
13+
#include "benchmark/benchmark.h"
14+
15+
namespace {
16+
17+
enum ValueType : size_t {
18+
SChar,
19+
UChar,
20+
Short,
21+
UShort,
22+
Int,
23+
UInt,
24+
Long,
25+
ULong,
26+
LongLong,
27+
ULongLong,
28+
#ifndef TEST_HAS_NO_INT128
29+
Int128,
30+
UInt128,
31+
#endif
32+
};
33+
34+
struct AllValueTypes : EnumValuesAsTuple<AllValueTypes, ValueType, 6> {
35+
static constexpr const char* Names[] = {
36+
"schar",
37+
"uchar",
38+
"short",
39+
"ushort",
40+
"int",
41+
"uint",
42+
"long",
43+
"ulong",
44+
"longlong",
45+
"ulonglong",
46+
#ifndef TEST_HAS_NO_INT128
47+
"int128",
48+
"uint128"
49+
#endif
50+
};
51+
};
52+
53+
using TestType =
54+
std::tuple< signed char,
55+
unsigned char,
56+
short,
57+
unsigned short,
58+
int,
59+
unsigned int,
60+
long,
61+
unsigned long,
62+
long long,
63+
unsigned long long
64+
#ifndef TEST_HAS_NO_INT128
65+
,
66+
__int128_t,
67+
__uint128_t
68+
#endif
69+
>;
70+
71+
template <typename TType, typename UType>
72+
struct CmpEqual {
73+
static void run(benchmark::State& state) {
74+
using T = std::tuple_element_t<TType::value, TestType>;
75+
using U = std::tuple_element_t<UType::value, TestType>;
76+
77+
T x1 = T{127}, x2 = T{111};
78+
U y1 = U{123}, y2 = U{1};
79+
for (auto _ : state) {
80+
benchmark::DoNotOptimize(x1);
81+
benchmark::DoNotOptimize(x2);
82+
benchmark::DoNotOptimize(y1);
83+
benchmark::DoNotOptimize(y2);
84+
benchmark::DoNotOptimize(std::cmp_equal(x1, y1));
85+
benchmark::DoNotOptimize(std::cmp_equal(y1, x1));
86+
benchmark::DoNotOptimize(std::cmp_equal(x1, x1));
87+
benchmark::DoNotOptimize(std::cmp_equal(y1, y1));
88+
89+
benchmark::DoNotOptimize(std::cmp_equal(x2, y2));
90+
benchmark::DoNotOptimize(std::cmp_equal(y2, x2));
91+
benchmark::DoNotOptimize(std::cmp_equal(x2, x2));
92+
benchmark::DoNotOptimize(std::cmp_equal(y2, y2));
93+
}
94+
}
95+
96+
static std::string name() { return "BM_CmpEqual" + TType::name() + UType::name(); }
97+
};
98+
99+
template <typename TType, typename UType>
100+
struct CmpLess {
101+
static void run(benchmark::State& state) {
102+
using T = std::tuple_element_t<TType::value, TestType>;
103+
using U = std::tuple_element_t<UType::value, TestType>;
104+
105+
T x1 = T{127}, x2 = T{111};
106+
U y1 = U{123}, y2 = U{1};
107+
for (auto _ : state) {
108+
benchmark::DoNotOptimize(x1);
109+
benchmark::DoNotOptimize(x2);
110+
benchmark::DoNotOptimize(y1);
111+
benchmark::DoNotOptimize(y2);
112+
benchmark::DoNotOptimize(std::cmp_less(x1, y1));
113+
benchmark::DoNotOptimize(std::cmp_less(y1, x1));
114+
benchmark::DoNotOptimize(std::cmp_less(x1, x1));
115+
benchmark::DoNotOptimize(std::cmp_less(y1, y1));
116+
117+
benchmark::DoNotOptimize(std::cmp_less(x2, y2));
118+
benchmark::DoNotOptimize(std::cmp_less(y2, x2));
119+
benchmark::DoNotOptimize(std::cmp_less(x2, x2));
120+
benchmark::DoNotOptimize(std::cmp_less(y2, y2));
121+
}
122+
}
123+
124+
static std::string name() { return "BM_CmpLess" + TType::name() + UType::name(); }
125+
};
126+
127+
} // namespace
128+
129+
int main(int argc, char** argv) {
130+
benchmark::Initialize(&argc, argv);
131+
if (benchmark::ReportUnrecognizedArguments(argc, argv))
132+
return 1;
133+
134+
makeCartesianProductBenchmark<CmpEqual, AllValueTypes, AllValueTypes>();
135+
makeCartesianProductBenchmark<CmpLess, AllValueTypes, AllValueTypes>();
136+
benchmark::RunSpecifiedBenchmarks();
137+
138+
return 0;
139+
}

0 commit comments

Comments
 (0)