Skip to content

Commit e31deed

Browse files
committed
[libc++] std::cmp_less and other integer comparison functions could be improved with _LIBCPP_ASSUME
| -------------------------------------------------------------------- | Benchmark Time CPU Iterations | -------------------------------------------------------------------- | BM_CmpEqual_schar_schar 0.221 ns 0.221 ns 3170066917 | BM_CmpEqual_schar_uchar 0.232 ns 0.232 ns 3025025997 | BM_CmpEqual_schar_short 0.280 ns 0.280 ns 2507488723 | BM_CmpEqual_schar_ushort 0.361 ns 0.361 ns 2086768552 | BM_CmpEqual_schar_int 0.220 ns 0.220 ns 3123871432 | BM_CmpEqual_schar_uint 0.233 ns 0.233 ns 3023305113 | BM_CmpEqual_uchar_schar 0.221 ns 0.221 ns 3180711887 | BM_CmpEqual_uchar_uchar 0.220 ns 0.220 ns 3177773411 | BM_CmpEqual_uchar_short 0.221 ns 0.221 ns 3178208863 | BM_CmpEqual_uchar_ushort 0.295 ns 0.295 ns 2331090257 | BM_CmpEqual_uchar_int 0.221 ns 0.221 ns 3156844998 | BM_CmpEqual_uchar_uint 0.220 ns 0.220 ns 3169867220 | BM_CmpEqual_short_schar 0.662 ns 0.662 ns 1057277878 | BM_CmpEqual_short_uchar 0.232 ns 0.232 ns 3019119818 | BM_CmpEqual_short_short 0.222 ns 0.222 ns 3171932178 | BM_CmpEqual_short_ushort 0.282 ns 0.282 ns 2495630490 | BM_CmpEqual_short_int 0.221 ns 0.221 ns 3165298446 | BM_CmpEqual_short_uint 0.368 ns 0.368 ns 2151247764 | BM_CmpEqual_ushort_schar 0.280 ns 0.280 ns 2503964124 | BM_CmpEqual_ushort_uchar 0.221 ns 0.221 ns 3164632430 | BM_CmpEqual_ushort_short 0.281 ns 0.281 ns 2502613193 | BM_CmpEqual_ushort_ushort 0.221 ns 0.221 ns 3164295092 | BM_CmpEqual_ushort_int 0.221 ns 0.221 ns 3170047435 | BM_CmpEqual_ushort_uint 0.222 ns 0.222 ns 3172795286 | BM_CmpEqual_int_schar 0.221 ns 0.221 ns 3170067649 | BM_CmpEqual_int_uchar 0.221 ns 0.221 ns 3162764124 | BM_CmpEqual_int_short 0.222 ns 0.222 ns 3149384461 | BM_CmpEqual_int_ushort 0.221 ns 0.221 ns 3170863296 | BM_CmpEqual_int_int 0.221 ns 0.221 ns 3173623511 | BM_CmpEqual_int_uint 0.349 ns 0.349 ns 2074548798 | BM_CmpEqual_uint_schar 0.221 ns 0.221 ns 3172609898 | BM_CmpEqual_uint_uchar 0.221 ns 0.221 ns 3167865061 | BM_CmpEqual_uint_short 0.221 ns 0.221 ns 3166421901 | BM_CmpEqual_uint_ushort 0.221 ns 0.221 ns 3154601627 | BM_CmpEqual_uint_int 0.222 ns 0.222 ns 3170922460 | BM_CmpEqual_uint_uint 0.221 ns 0.221 ns 3178919527 | BM_CmpLess_schar_schar 0.220 ns 0.220 ns 3166946919 | BM_CmpLess_schar_uchar 0.328 ns 0.328 ns 1989530669 | BM_CmpLess_schar_short 0.280 ns 0.280 ns 2481635006 | BM_CmpLess_schar_ushort 0.280 ns 0.280 ns 2494961754 | BM_CmpLess_schar_int 0.221 ns 0.221 ns 3170387379 | BM_CmpLess_schar_uint 0.232 ns 0.232 ns 3020929987 | BM_CmpLess_uchar_schar 0.339 ns 0.339 ns 2301816456 | BM_CmpLess_uchar_uchar 0.221 ns 0.221 ns 3168381752 | BM_CmpLess_uchar_short 0.221 ns 0.221 ns 3172130050 | BM_CmpLess_uchar_ushort 0.226 ns 0.226 ns 3177268420 | BM_CmpLess_uchar_int 0.221 ns 0.221 ns 3171207495 | BM_CmpLess_uchar_uint 0.221 ns 0.221 ns 3175834030 | BM_CmpLess_short_schar 0.663 ns 0.663 ns 1047532663 | BM_CmpLess_short_uchar 0.301 ns 0.301 ns 2210991543 | BM_CmpLess_short_short 0.220 ns 0.220 ns 3178165314 | BM_CmpLess_short_ushort 0.280 ns 0.280 ns 2502057388 | BM_CmpLess_short_int 0.223 ns 0.223 ns 3163647242 | BM_CmpLess_short_uint 0.233 ns 0.233 ns 3015274874 | BM_CmpLess_ushort_schar 0.280 ns 0.280 ns 2494740988 | BM_CmpLess_ushort_uchar 0.316 ns 0.316 ns 2124921107 | BM_CmpLess_ushort_short 0.280 ns 0.280 ns 2503617728 | BM_CmpLess_ushort_ushort 0.221 ns 0.221 ns 3166649427 | BM_CmpLess_ushort_int 0.221 ns 0.221 ns 3109921684 | BM_CmpLess_ushort_uint 0.221 ns 0.221 ns 3173252017 | BM_CmpLess_int_schar 0.222 ns 0.222 ns 3164772816 | BM_CmpLess_int_uchar 0.221 ns 0.221 ns 3141461765 | BM_CmpLess_int_short 0.221 ns 0.221 ns 3165358991 | BM_CmpLess_int_ushort 0.221 ns 0.221 ns 3172701309 | BM_CmpLess_int_int 0.222 ns 0.222 ns 3152883866 | BM_CmpLess_int_uint 0.232 ns 0.232 ns 2991786154 | BM_CmpLess_uint_schar 0.221 ns 0.221 ns 3174540447 | BM_CmpLess_uint_uchar 0.221 ns 0.220 ns 3177358990 | BM_CmpLess_uint_short 0.300 ns 0.300 ns 2362252788 | BM_CmpLess_uint_ushort 0.221 ns 0.221 ns 3178372133 | BM_CmpLess_uint_int 0.221 ns 0.221 ns 3177162541 | BM_CmpLess_uint_uint 0.221 ns 0.221 ns 3177473622 `----------------------------- .---command stderr------------ | 2025-09-09T20:03:38+08:00 | Running /home/kisuhorikka/Source/llvm-project/build/libcxx/test/benchmarks/utility/Output/cmp.bench.cpp.dir/t.tmp.exe | Run on (16 X 2304 MHz CPU s) | CPU Caches: | L1 Data 48 KiB (x8) | L1 Instruction 32 KiB (x8) | L2 Unified 1280 KiB (x8) | L3 Unified 24576 KiB (x1) | Load Average: 0.12, 0.25, 0.30 `-----------------------------
1 parent 7111443 commit e31deed

File tree

2 files changed

+131
-12
lines changed

2 files changed

+131
-12
lines changed

libcxx/include/__utility/cmp.h

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +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 {
31-
if constexpr (sizeof(_Tp) < sizeof(int) && sizeof(_Up) < sizeof(int)) {
32-
__builtin_assume(__t < numeric_limits<int>::max() && __u < numeric_limits<int>::max());
35+
if constexpr (is_signed_v<_Tp> == is_signed_v<_Up>)
36+
return __t == __u;
37+
else if constexpr (__comparison_can_promote_to<_Tp, int> && __comparison_can_promote_to<_Up, int>)
3338
return static_cast<int>(__t) == static_cast<int>(__u);
34-
} else if constexpr (sizeof(_Tp) < sizeof(long long) && sizeof(_Up) < sizeof(long long)) {
35-
__builtin_assume(__t < numeric_limits<long long>::max() && __u < numeric_limits<long long>::max());
39+
else if constexpr (__comparison_can_promote_to<_Tp, long long> && __comparison_can_promote_to<_Up, long long>)
3640
return static_cast<long long>(__t) == static_cast<long long>(__u);
37-
} else if constexpr (is_signed_v<_Tp> == is_signed_v<_Up>)
38-
return __t == __u;
3941
else if constexpr (is_signed_v<_Tp>)
4042
return __t < 0 ? false : make_unsigned_t<_Tp>(__t) == __u;
4143
else
@@ -49,14 +51,12 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool cmp_not_equal(_Tp __t, _Up __u) noexcept {
4951

5052
template <__signed_or_unsigned_integer _Tp, __signed_or_unsigned_integer _Up>
5153
_LIBCPP_HIDE_FROM_ABI constexpr bool cmp_less(_Tp __t, _Up __u) noexcept {
52-
if constexpr (sizeof(_Tp) < sizeof(int) && sizeof(_Up) < sizeof(int)) {
53-
__builtin_assume(__t < numeric_limits<int>::max() && __u < numeric_limits<int>::max());
54+
if constexpr (is_signed_v<_Tp> == is_signed_v<_Up>)
55+
return __t < __u;
56+
else if constexpr (__comparison_can_promote_to<_Tp, int> && __comparison_can_promote_to<_Up, int>)
5457
return static_cast<int>(__t) < static_cast<int>(__u);
55-
} else if constexpr (sizeof(_Tp) < sizeof(long long) && sizeof(_Up) < sizeof(long long)) {
56-
__builtin_assume(__t < numeric_limits<long long>::max() && __u < numeric_limits<long long>::max());
58+
else if constexpr (__comparison_can_promote_to<_Tp, long long> && __comparison_can_promote_to<_Up, long long>)
5759
return static_cast<long long>(__t) < static_cast<long long>(__u);
58-
} else if constexpr (is_signed_v<_Tp> == is_signed_v<_Up>)
59-
return __t < __u;
6060
else if constexpr (is_signed_v<_Tp>)
6161
return __t < 0 ? true : make_unsigned_t<_Tp>(__t) < __u;
6262
else
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
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 x = T{127};
78+
U y = U{123};
79+
for (auto _ : state) {
80+
benchmark::DoNotOptimize(x);
81+
benchmark::DoNotOptimize(y);
82+
benchmark::DoNotOptimize(std::cmp_equal(x, y));
83+
}
84+
}
85+
86+
static std::string name() { return "BM_CmpEqual" + TType::name() + UType::name(); }
87+
};
88+
89+
template <typename TType, typename UType>
90+
struct CmpLess {
91+
static void run(benchmark::State& state) {
92+
using T = std::tuple_element_t<TType::value, TestType>;
93+
using U = std::tuple_element_t<UType::value, TestType>;
94+
95+
T x = T{127};
96+
U y = U{123};
97+
for (auto _ : state) {
98+
benchmark::DoNotOptimize(x);
99+
benchmark::DoNotOptimize(y);
100+
benchmark::DoNotOptimize(std::cmp_less(x, y));
101+
}
102+
}
103+
104+
static std::string name() { return "BM_CmpLess" + TType::name() + UType::name(); }
105+
};
106+
107+
} // namespace
108+
109+
int main(int argc, char** argv) {
110+
benchmark::Initialize(&argc, argv);
111+
if (benchmark::ReportUnrecognizedArguments(argc, argv))
112+
return 1;
113+
114+
makeCartesianProductBenchmark<CmpEqual, AllValueTypes, AllValueTypes>();
115+
makeCartesianProductBenchmark<CmpLess, AllValueTypes, AllValueTypes>();
116+
benchmark::RunSpecifiedBenchmarks();
117+
118+
return 0;
119+
}

0 commit comments

Comments
 (0)