[llvm] 673d963 - [llvm][ADT] Make `Twine` aware of `StringLiteral`

Jan Svoboda via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 3 10:53:04 PDT 2023


Author: Jan Svoboda
Date: 2023-08-03T10:52:57-07:00
New Revision: 673d963436666000aba89e3b5c7a85056bdba8ce

URL: https://github.com/llvm/llvm-project/commit/673d963436666000aba89e3b5c7a85056bdba8ce
DIFF: https://github.com/llvm/llvm-project/commit/673d963436666000aba89e3b5c7a85056bdba8ce.diff

LOG: [llvm][ADT] Make `Twine` aware of `StringLiteral`

The `const char *` storage backing StringLiteral has static lifetime. Making `Twine` aware of that allows us to avoid allocating heap memory in some contexts (e.g. avoid passing it to `StringSaver::save()` in a follow-up Clang patch).

Reviewed By: benlangmuir

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

Added: 
    

Modified: 
    llvm/include/llvm/ADT/Twine.h
    llvm/lib/Support/Twine.cpp
    llvm/unittests/ADT/TwineTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/ADT/Twine.h b/llvm/include/llvm/ADT/Twine.h
index ecd9d6df60ac61..8dfbe4f72e07de 100644
--- a/llvm/include/llvm/ADT/Twine.h
+++ b/llvm/include/llvm/ADT/Twine.h
@@ -102,6 +102,10 @@ namespace llvm {
       /// because they are not trivally constructible.
       PtrAndLengthKind,
 
+      /// A pointer and length representation that's also null-terminated.
+      /// Guaranteed to be constructed from a compile-time string literal.
+      StringLiteralKind,
+
       /// A pointer to a formatv_object_base instance.
       FormatvObjectKind,
 
@@ -303,6 +307,14 @@ namespace llvm {
       assert(isValid() && "Invalid twine!");
     }
 
+    /// Construct from a StringLiteral.
+    /*implicit*/ Twine(const StringLiteral &Str)
+        : LHSKind(StringLiteralKind) {
+      LHS.ptrAndLength.ptr = Str.data();
+      LHS.ptrAndLength.length = Str.size();
+      assert(isValid() && "Invalid twine!");
+    }
+
     /// Construct from a SmallString.
     /*implicit*/ Twine(const SmallVectorImpl<char> &Str)
         : LHSKind(PtrAndLengthKind) {
@@ -418,6 +430,11 @@ namespace llvm {
       return isNullary();
     }
 
+    /// Check if this twine is guaranteed to refer to single string literal.
+    bool isSingleStringLiteral() const {
+      return isUnary() && getLHSKind() == StringLiteralKind;
+    }
+
     /// Return true if this twine can be dynamically accessed as a single
     /// StringRef value with getSingleStringRef().
     bool isSingleStringRef() const {
@@ -428,6 +445,7 @@ namespace llvm {
       case CStringKind:
       case StdStringKind:
       case PtrAndLengthKind:
+      case StringLiteralKind:
         return true;
       default:
         return false;
@@ -463,6 +481,7 @@ namespace llvm {
       case StdStringKind:
         return StringRef(*LHS.stdString);
       case PtrAndLengthKind:
+      case StringLiteralKind:
         return StringRef(LHS.ptrAndLength.ptr, LHS.ptrAndLength.length);
       }
     }

diff  --git a/llvm/lib/Support/Twine.cpp b/llvm/lib/Support/Twine.cpp
index 8bbfd0815a402f..495b9cf2dbd680 100644
--- a/llvm/lib/Support/Twine.cpp
+++ b/llvm/lib/Support/Twine.cpp
@@ -44,6 +44,8 @@ StringRef Twine::toNullTerminatedStringRef(SmallVectorImpl<char> &Out) const {
       const std::string *str = LHS.stdString;
       return StringRef(str->c_str(), str->size());
     }
+    case StringLiteralKind:
+      return StringRef(LHS.ptrAndLength.ptr, LHS.ptrAndLength.length);
     default:
       break;
     }
@@ -69,6 +71,7 @@ void Twine::printOneChild(raw_ostream &OS, Child Ptr,
     OS << *Ptr.stdString;
     break;
   case Twine::PtrAndLengthKind:
+  case Twine::StringLiteralKind:
     OS << StringRef(Ptr.ptrAndLength.ptr, Ptr.ptrAndLength.length);
     break;
   case Twine::FormatvObjectKind:
@@ -124,6 +127,10 @@ void Twine::printOneChildRepr(raw_ostream &OS, Child Ptr,
     OS << "ptrAndLength:\""
        << StringRef(Ptr.ptrAndLength.ptr, Ptr.ptrAndLength.length) << "\"";
     break;
+  case Twine::StringLiteralKind:
+    OS << "constexprPtrAndLength:\""
+       << StringRef(Ptr.ptrAndLength.ptr, Ptr.ptrAndLength.length) << "\"";
+    break;
   case Twine::FormatvObjectKind:
     OS << "formatv:\"" << *Ptr.formatvObject << "\"";
     break;

diff  --git a/llvm/unittests/ADT/TwineTest.cpp b/llvm/unittests/ADT/TwineTest.cpp
index bb7127659ee924..d45805f4db7a39 100644
--- a/llvm/unittests/ADT/TwineTest.cpp
+++ b/llvm/unittests/ADT/TwineTest.cpp
@@ -30,6 +30,7 @@ TEST(TwineTest, Construction) {
   EXPECT_EQ("hi", Twine(StringRef("hi")).str());
   EXPECT_EQ("hi", Twine(StringRef(std::string("hi"))).str());
   EXPECT_EQ("hi", Twine(StringRef("hithere", 2)).str());
+  EXPECT_EQ("hi", Twine(StringLiteral("hi")).str());
   EXPECT_EQ("hi", Twine(SmallString<4>("hi")).str());
   EXPECT_EQ("hi", Twine(formatv("{0}", "hi")).str());
   EXPECT_EQ("hi", Twine(std::string_view("hi")).str());
@@ -96,6 +97,9 @@ TEST(TwineTest, toNullTerminatedStringRef) {
   EXPECT_EQ(0, *Twine("hello").toNullTerminatedStringRef(storage).end());
   EXPECT_EQ(0,
            *Twine(StringRef("hello")).toNullTerminatedStringRef(storage).end());
+  EXPECT_EQ(
+      0,
+      *Twine(StringLiteral("hello")).toNullTerminatedStringRef(storage).end());
   EXPECT_EQ(0, *Twine(SmallString<11>("hello"))
                     .toNullTerminatedStringRef(storage)
                     .end());
@@ -104,6 +108,12 @@ TEST(TwineTest, toNullTerminatedStringRef) {
                     .end());
 }
 
+TEST(TwineTest, isSingleStringLiteral) {
+  EXPECT_TRUE(Twine(StringLiteral("hi")).isSingleStringLiteral());
+  EXPECT_FALSE(Twine("hi").isSingleStringLiteral());
+  EXPECT_FALSE(Twine(StringRef("hi")).isSingleStringLiteral());
+}
+
 TEST(TwineTest, LazyEvaluation) {
   struct formatter : FormatAdapter<int> {
     explicit formatter(int &Count) : FormatAdapter(0), Count(Count) {}


        


More information about the llvm-commits mailing list