diff --git a/libcxx/benchmarks/string.bench.cpp b/libcxx/benchmarks/string.bench.cpp --- a/libcxx/benchmarks/string.bench.cpp +++ b/libcxx/benchmarks/string.bench.cpp @@ -73,12 +73,12 @@ "ChangeMiddle", "ChangeLast"}; }; -static constexpr char kSmallStringLiteral[] = "012345678"; +static constexpr char SmallStringLiteral[] = "012345678"; TEST_ALWAYS_INLINE const char* getSmallString(DiffType D) { switch (D) { case DiffType::Control: - return kSmallStringLiteral; + return SmallStringLiteral; case DiffType::ChangeFirst: return "-12345678"; case DiffType::ChangeMiddle: @@ -88,6 +88,9 @@ } } +static constexpr char LargeStringLiteral[] = + "012345678901234567890123456789012345678901234567890123456789012"; + TEST_ALWAYS_INLINE const char* getLargeString(DiffType D) { #define LARGE_STRING_FIRST "123456789012345678901234567890" #define LARGE_STRING_SECOND "234567890123456789012345678901" @@ -263,21 +266,26 @@ } }; -template +template struct StringRelationalLiteral { static void run(benchmark::State& state) { auto Lhs = makeString(LHLength(), DiffType()); for (auto _ : state) { benchmark::DoNotOptimize(Lhs); + constexpr const char* Literal = RHLength::value == Length::Empty + ? "" + : RHLength::value == Length::Small + ? SmallStringLiteral + : LargeStringLiteral; switch (Rel()) { case Relation::Eq: - benchmark::DoNotOptimize(Lhs == kSmallStringLiteral); + benchmark::DoNotOptimize(Lhs == Literal); break; case Relation::Less: - benchmark::DoNotOptimize(Lhs < kSmallStringLiteral); + benchmark::DoNotOptimize(Lhs < Literal); break; case Relation::Compare: - benchmark::DoNotOptimize(Lhs.compare(kSmallStringLiteral)); + benchmark::DoNotOptimize(Lhs.compare(Literal)); break; } } @@ -285,17 +293,17 @@ static bool skip() { // Doesn't matter how they differ if they have different size. - if (LHLength() != Length::Small && DiffType() != ::DiffType::Control) + if (LHLength() != RHLength() && DiffType() != ::DiffType::Control) return true; // We don't need huge. Doensn't give anything different than Large. - if (LHLength() == Length::Huge) + if (LHLength() == Length::Huge || RHLength() == Length::Huge) return true; return false; } static std::string name() { return "BM_StringRelationalLiteral" + Rel::name() + LHLength::name() + - DiffType::name(); + RHLength::name() + DiffType::name(); } }; @@ -393,6 +401,22 @@ } } +// Some small codegen thunks to easily see generated code. +bool StringEqString(const std::string& a, const std::string& b) { + return a == b; +} +bool StringEqCStr(const std::string& a, const char* b) { return a == b; } +bool CStrEqString(const char* a, const std::string& b) { return a == b; } +bool StringEqCStrLiteralEmpty(const std::string& a) { + return a == ""; +} +bool StringEqCStrLiteralSmall(const std::string& a) { + return a == SmallStringLiteral; +} +bool StringEqCStrLiteralLarge(const std::string& a) { + return a == LargeStringLiteral; +} + int main(int argc, char** argv) { benchmark::Initialize(&argc, argv); if (benchmark::ReportUnrecognizedArguments(argc, argv)) @@ -408,8 +432,16 @@ makeCartesianProductBenchmark(); makeCartesianProductBenchmark(); + AllLengths, AllLengths, AllDiffTypes>(); makeCartesianProductBenchmark(); benchmark::RunSpecifiedBenchmarks(); + + if (argc < 0) { + // ODR-use the functions to force them being generated in the binary. + auto functions = std::make_tuple( + StringEqString, StringEqCStr, CStrEqString, StringEqCStrLiteralEmpty, + StringEqCStrLiteralSmall, StringEqCStrLiteralLarge); + printf("%p", &functions); + } } diff --git a/libcxx/include/string b/libcxx/include/string --- a/libcxx/include/string +++ b/libcxx/include/string @@ -3875,11 +3875,10 @@ operator==(const _CharT* __lhs, const basic_string<_CharT, _Traits, _Allocator>& __rhs) _NOEXCEPT { - typedef basic_string<_CharT, _Traits, _Allocator> _String; _LIBCPP_ASSERT(__lhs != nullptr, "operator==(char*, basic_string): received nullptr"); size_t __lhs_len = _Traits::length(__lhs); if (__lhs_len != __rhs.size()) return false; - return __rhs.compare(0, _String::npos, __lhs, __lhs_len) == 0; + return _Traits::compare(__lhs, __rhs.data(), __lhs_len) == 0; } template @@ -3888,11 +3887,10 @@ operator==(const basic_string<_CharT,_Traits,_Allocator>& __lhs, const _CharT* __rhs) _NOEXCEPT { - typedef basic_string<_CharT, _Traits, _Allocator> _String; _LIBCPP_ASSERT(__rhs != nullptr, "operator==(basic_string, char*): received nullptr"); size_t __rhs_len = _Traits::length(__rhs); if (__rhs_len != __lhs.size()) return false; - return __lhs.compare(0, _String::npos, __rhs, __rhs_len) == 0; + return _Traits::compare(__lhs.data(), __rhs, __rhs_len) == 0; } template