Add more benchmarks for literal strings.

Summary:
Comparing against the empty string should generate much better code that
what it does today.
We can also generate better code when comparing against literals that
are larger than the SSO space.

Reviewers: EricWF

Subscribers: christof, jdoerfert, libcxx-commits

Tags: #libc

Differential Revision: https://reviews.llvm.org/D59781

git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@357614 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/benchmarks/string.bench.cpp b/benchmarks/string.bench.cpp
index 2d2b8a9..22d84af 100644
--- a/benchmarks/string.bench.cpp
+++ b/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 <class Rel, class LHLength, class DiffType>
+template <class Rel, class LHLength, class RHLength, class DiffType>
 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<StringRelational, AllRelations, AllLengths,
                                 AllLengths, AllDiffTypes>();
   makeCartesianProductBenchmark<StringRelationalLiteral, AllRelations,
-                                AllLengths, AllDiffTypes>();
+                                AllLengths, AllLengths, AllDiffTypes>();
   makeCartesianProductBenchmark<StringRead, AllTemperatures, AllDepths,
                                 AllLengths>();
   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);
+  }
 }