Introduce StringBuilder utility around raw_string_ostream

Alp Toker alp at nuanti.com
Thu Jun 12 05:31:16 PDT 2014


On 12/06/2014 14:54, Chandler Carruth wrote:
>
> On Thu, Jun 12, 2014 at 12:45 PM, Alp Toker <alp at nuanti.com 
> <mailto:alp at nuanti.com>> wrote:
>
>     On 12/06/2014 14:33, Chandler Carruth wrote:
>
>
>         On Thu, Jun 12, 2014 at 5:25 AM, Alp Toker <alp at nuanti.com
>         <mailto:alp at nuanti.com> <mailto:alp at nuanti.com
>         <mailto:alp at nuanti.com>>> wrote:
>
>             Replaces the pattern:
>
>               std::string buf;
>               raw_string_ostream os(buf);
>               ...
>               os.flush();
>               use(buf);
>
>
>         So this pattern should be:
>
>           std::string buf;
>           raw_string_ostream os(buf);
>           ...
>           use(os.str());
>
>             with:
>               StringBuilder os;
>               ...
>               use (os.str());
>
>
>         Which is now almost identical to this. What's the advantage?
>
>
>     Unfortunately people don't get the pattern right. There's that
>     tempting 'buf' string that ends up getting accessed incorrectly.
>     People tend to flush either too often or not enough, and just the
>     casual replace in the patch found a handful of these.
>
>
>
>
>         The reason I like the current form is that it makes it obvious
>         and easy to re-use storage where that is reasonable, and it
>         makes variations with SmallString more obviously the same
>         pattern with a different storage.
>
>
>     We'd keep the raw_string_ostream class with this scheme, and it
>     has several legitimate users. But this patch deals with the ones
>     that really don't want to know about the string backing.
>
>     By hiding the storage for callers that don't care so much whether
>     it's backed by std::string, we can start to do smart things like
>     experimenting with SmallString<> backing and providing a
>     templatized version. Right now these callers are stuck with the
>     worst-case std::string allocator and this patch breaks away from that.
>
>     And it's also easy to go from there to hooking this up to PGO that
>     determines optimal backing sizes for each occurrence to avoid
>     mallocs. That flexibility wasn't really there before.
>
>     But my favourite feature about the new StringBuilder is that it
>     makes invalid state impossible, which is what most simple
>     string-building callers want.
>
>
>
>
>         We could even add a 'make_raw_ostream' or some such so that
>         the pattern can become:
>
>           Foo storage;
>           auto os(make_raw_ostream(storage));
>           ...
>           use(os.str());
>
>         Thoughts?
>
>
>     The dummy storage variable is still there in that last snipped,
>     and I'm proposing to get rid of it. It seems consistently better
>     to hide it so we can tweak it for performance and ensure safe
>     usage -- think of it as RAII for building strings combining
>     storage and interface.
>
>
> I understand what you're going for, I just don't really agree with the 
> tradeoff you're proposing.
>
> I think the current interface is fine, and having the ability to deal 
> with the storage independently of the stream is necessary in some 
> cases. I even think it is good in some cases to expose to the client 
> of the interface that they have storage and should consider its 
> lifetime and semantics. As a consequence, I don't think it is worth 
> adding yet another type and pattern for the minor (IMO) benefit of 
> avoiding one possible misuse. I'd rather just teach people to use the 
> str() method

Okay, but that's aiming for a hypothetical LLVM project where developers 
are paying attention to things like string storage. And that they're 
aiming not only for correctness, but successfully choosing efficient 
backing to avoid heap allocations.

In reality, there are a bunch of developers trying to write various 
compiler backends, frontends and analyses. Their patches get peer 
reviewed by people who history has shown don't care about the 
intricacies of stack string allocation.

The enforced safety in this patch comes without any cost, and the 
potential of optimisation that wasn't there before, and neat 
simplifications at each of the points of use.

Of course the goal is to have more streaming and twines as you suggest, 
but this is a valid interim solution even for those cases that could be 
hand-optimized. Right now they're just hidden away and difficult to 
grep/clang-query.


> , and remove the misuses of flush when we find them (either through an 
> audit or in code review). Now, if there are simple ways to make the 
> interfaces of the stream classes better so that this is easier to get 
> right and harder to get wrong, I'm all for that.

Simpler? The proposed interface is 13 lines of code :-)

I'm pretty sure a lot of people will appreciate this. It's just too easy 
to access the string when it's sitting around in an inconsistent state 
accessible to the caller, and it's a fact that review didn't catch the 
errors found in-tree. With the proposed patch, the compiler catches the 
errors.

Updated version attached.

Alp.

-- 
http://www.nuanti.com
the browser experts

-------------- next part --------------
diff --git a/include/llvm/Analysis/CFGPrinter.h b/include/llvm/Analysis/CFGPrinter.h
index e6d2ed1..57b7333 100644
--- a/include/llvm/Analysis/CFGPrinter.h
+++ b/include/llvm/Analysis/CFGPrinter.h
@@ -36,9 +36,7 @@ struct DOTGraphTraits<const Function*> : public DefaultDOTGraphTraits {
     if (!Node->getName().empty())
       return Node->getName().str();
 
-    std::string Str;
-    raw_string_ostream OS(Str);
-
+    StringBuilder OS;
     Node->printAsOperand(OS, false);
     return OS.str();
   }
@@ -46,8 +44,7 @@ struct DOTGraphTraits<const Function*> : public DefaultDOTGraphTraits {
   static std::string getCompleteNodeLabel(const BasicBlock *Node,
                                           const Function *) {
     enum { MaxColumns = 80 };
-    std::string Str;
-    raw_string_ostream OS(Str);
+    StringBuilder OS;
 
     if (Node->getName().empty()) {
       Node->printAsOperand(OS, false);
@@ -109,8 +106,7 @@ struct DOTGraphTraits<const Function*> : public DefaultDOTGraphTraits {
 
       if (SuccNo == 0) return "def";
 
-      std::string Str;
-      raw_string_ostream OS(Str);
+      StringBuilder OS;
       SwitchInst::ConstCaseIt Case =
           SwitchInst::ConstCaseIt::fromSuccessorIndex(SI, SuccNo);
       OS << Case.getCaseValue()->getValue();
diff --git a/include/llvm/Support/GraphWriter.h b/include/llvm/Support/GraphWriter.h
index 2f02aa7..98ae1a1 100644
--- a/include/llvm/Support/GraphWriter.h
+++ b/include/llvm/Support/GraphWriter.h
@@ -184,8 +184,7 @@ public:
         O << "|" << DOT::EscapeString(NodeDesc);
     }
 
-    std::string edgeSourceLabels;
-    raw_string_ostream EdgeSourceLabels(edgeSourceLabels);
+    StringBuilder EdgeSourceLabels;
     bool hasEdgeSourceLabels = getEdgeSourceLabels(EdgeSourceLabels, Node);
 
     if (hasEdgeSourceLabels) {
diff --git a/include/llvm/Support/YAMLTraits.h b/include/llvm/Support/YAMLTraits.h
index 50da769..e9d4491 100644
--- a/include/llvm/Support/YAMLTraits.h
+++ b/include/llvm/Support/YAMLTraits.h
@@ -612,8 +612,7 @@ template<typename T>
 typename std::enable_if<has_ScalarTraits<T>::value,void>::type
 yamlize(IO &io, T &Val, bool) {
   if ( io.outputting() ) {
-    std::string Storage;
-    llvm::raw_string_ostream Buffer(Storage);
+    llvm::StringBuilder Buffer;
     ScalarTraits<T>::output(Val, io.getContext(), Buffer);
     StringRef Str = Buffer.str();
     io.scalarString(Str, ScalarTraits<T>::mustQuote(Str));
diff --git a/include/llvm/Support/raw_ostream.h b/include/llvm/Support/raw_ostream.h
index 34fbe08..f1b9f31 100644
--- a/include/llvm/Support/raw_ostream.h
+++ b/include/llvm/Support/raw_ostream.h
@@ -438,6 +438,8 @@ class raw_string_ostream : public raw_ostream {
   /// counting the bytes currently in the buffer.
   uint64_t current_pos() const override { return OS.size(); }
 public:
+  // This constructor is specified not to access the string provided for
+  // storage as it may not yet be initialized at construction time.
   explicit raw_string_ostream(std::string &O) : OS(O) {}
   ~raw_string_ostream();
 
@@ -449,6 +451,24 @@ public:
   }
 };
 
+/// StringBuilder - A raw_ostream that builds an std::string.  This is
+/// a raw_string_ostream with storage.
+class StringBuilder : public raw_string_ostream {
+  std::string Buffer;
+
+protected:
+  // There's no need to explicitly flush a StringBuilder.
+  using raw_string_ostream::flush;
+
+public:
+  StringBuilder() : raw_string_ostream(Buffer) {}
+
+  void clear() {
+    flush();
+    Buffer.clear();
+  }
+};
+
 /// raw_svector_ostream - A raw_ostream that writes to an SmallVector or
 /// SmallString.  This is a simple adaptor class. This class does not
 /// encounter output errors.
diff --git a/lib/Analysis/Analysis.cpp b/lib/Analysis/Analysis.cpp
index ade940a..24f57cd 100644
--- a/lib/Analysis/Analysis.cpp
+++ b/lib/Analysis/Analysis.cpp
@@ -75,8 +75,7 @@ void LLVMInitializeAnalysis(LLVMPassRegistryRef R) {
 LLVMBool LLVMVerifyModule(LLVMModuleRef M, LLVMVerifierFailureAction Action,
                           char **OutMessages) {
   raw_ostream *DebugOS = Action != LLVMReturnStatusAction ? &errs() : nullptr;
-  std::string Messages;
-  raw_string_ostream MsgsOS(Messages);
+  StringBuilder MsgsOS;
 
   LLVMBool Result = verifyModule(*unwrap(M), OutMessages ? &MsgsOS : DebugOS);
 
diff --git a/lib/Analysis/BlockFrequencyInfo.cpp b/lib/Analysis/BlockFrequencyInfo.cpp
index 8ed8e3e..3d00418 100644
--- a/lib/Analysis/BlockFrequencyInfo.cpp
+++ b/lib/Analysis/BlockFrequencyInfo.cpp
@@ -82,10 +82,9 @@ struct DOTGraphTraits<BlockFrequencyInfo*> : public DefaultDOTGraphTraits {
 
   std::string getNodeLabel(const BasicBlock *Node,
                            const BlockFrequencyInfo *Graph) {
-    std::string Result;
-    raw_string_ostream OS(Result);
+    StringBuilder OS;
 
-    OS << Node->getName().str() << ":";
+    OS << Node->getName() << ":";
     switch (ViewBlockFreqPropagationDAG) {
     case GVDT_Fraction:
       Graph->printBlockFreq(OS, Node);
@@ -98,7 +97,7 @@ struct DOTGraphTraits<BlockFrequencyInfo*> : public DefaultDOTGraphTraits {
                        "never reach this point.");
     }
 
-    return Result;
+    return OS.str();
   }
 };
 
diff --git a/lib/Analysis/Lint.cpp b/lib/Analysis/Lint.cpp
index b14f329..492149b 100644
--- a/lib/Analysis/Lint.cpp
+++ b/lib/Analysis/Lint.cpp
@@ -105,11 +105,10 @@ namespace {
     const DataLayout *DL;
     TargetLibraryInfo *TLI;
 
-    std::string Messages;
-    raw_string_ostream MessagesStr;
+    StringBuilder MessagesStr;
 
     static char ID; // Pass identification, replacement for typeid
-    Lint() : FunctionPass(ID), MessagesStr(Messages) {
+    Lint() : FunctionPass(ID) {
       initializeLintPass(*PassRegistry::getPassRegistry());
     }
 
@@ -181,7 +180,7 @@ bool Lint::runOnFunction(Function &F) {
   TLI = &getAnalysis<TargetLibraryInfo>();
   visit(F);
   dbgs() << MessagesStr.str();
-  Messages.clear();
+  MessagesStr.clear();
   return false;
 }
 
diff --git a/lib/AsmParser/LLParser.cpp b/lib/AsmParser/LLParser.cpp
index a528a7e..92a063a 100644
--- a/lib/AsmParser/LLParser.cpp
+++ b/lib/AsmParser/LLParser.cpp
@@ -28,10 +28,9 @@
 using namespace llvm;
 
 static std::string getTypeString(Type *T) {
-  std::string Result;
-  raw_string_ostream Tmp(Result);
-  Tmp << *T;
-  return Tmp.str();
+  StringBuilder Result;
+  Result << *T;
+  return Result.str();
 }
 
 /// Run: module ::= toplevelentity*
diff --git a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index 996dc21..d69c2e0 100644
--- a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -1586,8 +1586,7 @@ static const MCExpr *lowerConstant(const Constant *CV, AsmPrinter &AP) {
 
     // Otherwise report the problem to the user.
     {
-      std::string S;
-      raw_string_ostream OS(S);
+      StringBuilder OS;
       OS << "Unsupported expression in static initializer: ";
       CE->printAsOperand(OS, /*PrintType=*/false,
                      !AP.MF ? nullptr : AP.MF->getFunction()->getParent());
diff --git a/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp b/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp
index 46ee0c8..f89e178 100644
--- a/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp
+++ b/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp
@@ -241,8 +241,7 @@ static void EmitMSInlineAsmStr(const char *AsmStr, const MachineInstr *MI,
         }
       }
       if (Error) {
-        std::string msg;
-        raw_string_ostream Msg(msg);
+        StringBuilder Msg;
         Msg << "invalid operand in inline asm: '" << AsmStr << "'";
         MMI->getModule()->getContext().emitError(LocCookie, Msg.str());
       }
@@ -413,8 +412,7 @@ static void EmitGCCInlineAsmStr(const char *AsmStr, const MachineInstr *MI,
           }
         }
         if (Error) {
-          std::string msg;
-          raw_string_ostream Msg(msg);
+          StringBuilder Msg;
           Msg << "invalid operand in inline asm: '" << AsmStr << "'";
           MMI->getModule()->getContext().emitError(LocCookie, Msg.str());
         }
@@ -517,8 +515,7 @@ void AsmPrinter::PrintSpecial(const MachineInstr *MI, raw_ostream &OS,
     }
     OS << Counter;
   } else {
-    std::string msg;
-    raw_string_ostream Msg(msg);
+    StringBuilder Msg;
     Msg << "Unknown special formatter '" << Code
          << "' for machine instr: " << *MI;
     report_fatal_error(Msg.str());
diff --git a/lib/CodeGen/MachineBlockFrequencyInfo.cpp b/lib/CodeGen/MachineBlockFrequencyInfo.cpp
index 9151d99..7bac617 100644
--- a/lib/CodeGen/MachineBlockFrequencyInfo.cpp
+++ b/lib/CodeGen/MachineBlockFrequencyInfo.cpp
@@ -89,10 +89,9 @@ struct DOTGraphTraits<MachineBlockFrequencyInfo*> :
 
   std::string getNodeLabel(const MachineBasicBlock *Node,
                            const MachineBlockFrequencyInfo *Graph) {
-    std::string Result;
-    raw_string_ostream OS(Result);
+    StringBuilder OS;
 
-    OS << Node->getName().str() << ":";
+    OS << Node->getName() << ":";
     switch (ViewMachineBlockFreqPropagationDAG) {
     case GVDT_Fraction:
       Graph->printBlockFreq(OS, Node);
@@ -105,7 +104,7 @@ struct DOTGraphTraits<MachineBlockFrequencyInfo*> :
                        "never reach this point.");
     }
 
-    return Result;
+    return OS.str();
   }
 };
 
diff --git a/lib/CodeGen/MachineBlockPlacement.cpp b/lib/CodeGen/MachineBlockPlacement.cpp
index 74af1e2..7f07393 100644
--- a/lib/CodeGen/MachineBlockPlacement.cpp
+++ b/lib/CodeGen/MachineBlockPlacement.cpp
@@ -264,23 +264,19 @@ INITIALIZE_PASS_END(MachineBlockPlacement, "block-placement2",
 ///
 /// Only used by debug logging.
 static std::string getBlockName(MachineBasicBlock *BB) {
-  std::string Result;
-  raw_string_ostream OS(Result);
+  StringBuilder OS;
   OS << "BB#" << BB->getNumber()
      << " (derived from LLVM BB '" << BB->getName() << "')";
-  OS.flush();
-  return Result;
+  return OS.str();
 }
 
 /// \brief Helper to print the number of a MBB.
 ///
 /// Only used by debug logging.
 static std::string getBlockNum(MachineBasicBlock *BB) {
-  std::string Result;
-  raw_string_ostream OS(Result);
+  StringBuilder OS;
   OS << "BB#" << BB->getNumber();
-  OS.flush();
-  return Result;
+  return OS.str();
 }
 #endif
 
diff --git a/lib/CodeGen/MachineScheduler.cpp b/lib/CodeGen/MachineScheduler.cpp
index cbe937a..e2d4a1a 100644
--- a/lib/CodeGen/MachineScheduler.cpp
+++ b/lib/CodeGen/MachineScheduler.cpp
@@ -3231,8 +3231,7 @@ struct DOTGraphTraits<ScheduleDAGMI*> : public DefaultDOTGraphTraits {
   }
 
   static std::string getNodeLabel(const SUnit *SU, const ScheduleDAG *G) {
-    std::string Str;
-    raw_string_ostream SS(Str);
+    StringBuilder SS;
     const ScheduleDAGMI *DAG = static_cast<const ScheduleDAGMI*>(G);
     const SchedDFSResult *DFS = DAG->hasVRegLiveness() ?
       static_cast<const ScheduleDAGMILive*>(G)->getDFSResult() : nullptr;
diff --git a/lib/CodeGen/ScheduleDAGInstrs.cpp b/lib/CodeGen/ScheduleDAGInstrs.cpp
index 92a9a30..0b7c78a 100644
--- a/lib/CodeGen/ScheduleDAGInstrs.cpp
+++ b/lib/CodeGen/ScheduleDAGInstrs.cpp
@@ -1197,8 +1197,7 @@ void ScheduleDAGInstrs::dumpNode(const SUnit *SU) const {
 }
 
 std::string ScheduleDAGInstrs::getGraphNodeLabel(const SUnit *SU) const {
-  std::string s;
-  raw_string_ostream oss(s);
+  StringBuilder oss;
   if (SU == &EntrySU)
     oss << "<entry>";
   else if (SU == &ExitSU)
diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
index 57e22e2..c73cba0 100644
--- a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
+++ b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
@@ -3245,8 +3245,7 @@ SelectCodeCommon(SDNode *NodeToMatch, const unsigned char *MatcherTable,
 
 
 void SelectionDAGISel::CannotYetSelect(SDNode *N) {
-  std::string msg;
-  raw_string_ostream Msg(msg);
+  StringBuilder Msg;
   Msg << "Cannot select: ";
 
   if (N->getOpcode() != ISD::INTRINSIC_W_CHAIN &&
diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGPrinter.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGPrinter.cpp
index 4df5ede..d92f0fb 100644
--- a/lib/CodeGen/SelectionDAG/SelectionDAGPrinter.cpp
+++ b/lib/CodeGen/SelectionDAG/SelectionDAGPrinter.cpp
@@ -268,8 +268,7 @@ void SelectionDAG::setSubgraphColor(SDNode *N, const char *Color) {
 }
 
 std::string ScheduleDAGSDNodes::getGraphNodeLabel(const SUnit *SU) const {
-  std::string s;
-  raw_string_ostream O(s);
+  StringBuilder O;
   O << "SU(" << SU->NodeNum << "): ";
   if (SU->getNode()) {
     SmallVector<SDNode *, 4> GluedNodes;
diff --git a/lib/CodeGen/TargetSchedule.cpp b/lib/CodeGen/TargetSchedule.cpp
index b0f2ca6..9d4ec6a 100644
--- a/lib/CodeGen/TargetSchedule.cpp
+++ b/lib/CodeGen/TargetSchedule.cpp
@@ -212,11 +212,10 @@ unsigned TargetSchedModel::computeOperandLatency(
   if (SCDesc->isValid() && !DefMI->getOperand(DefOperIdx).isImplicit()
       && !DefMI->getDesc().OpInfo[DefOperIdx].isOptionalDef()
       && SchedModel.isComplete()) {
-    std::string Err;
-    raw_string_ostream ss(Err);
-    ss << "DefIdx " << DefIdx << " exceeds machine model writes for "
+    StringBuilder Err;
+    Err << "DefIdx " << DefIdx << " exceeds machine model writes for "
        << *DefMI;
-    report_fatal_error(ss.str());
+    report_fatal_error(Err.str());
   }
 #endif
   // FIXME: Automatically giving all implicit defs defaultDefLatency is
diff --git a/lib/DebugInfo/DWARFDebugFrame.cpp b/lib/DebugInfo/DWARFDebugFrame.cpp
index a33548e..1023193 100644
--- a/lib/DebugInfo/DWARFDebugFrame.cpp
+++ b/lib/DebugInfo/DWARFDebugFrame.cpp
@@ -353,10 +353,9 @@ void DWARFDebugFrame::parse(DataExtractor Data) {
     Entries.back()->parseInstructions(Data, &Offset, EndStructureOffset);
 
     if (Offset != EndStructureOffset) {
-      std::string Str;
-      raw_string_ostream OS(Str);
-      OS << format("Parsing entry instructions at %lx failed", StartOffset);
-      report_fatal_error(Str);
+      StringBuilder Str;
+      Str << format("Parsing entry instructions at %lx failed", StartOffset);
+      report_fatal_error(Str.str());
     }
   }
 }
diff --git a/lib/IR/Core.cpp b/lib/IR/Core.cpp
index f24704c..2431d70 100644
--- a/lib/IR/Core.cpp
+++ b/lib/IR/Core.cpp
@@ -110,14 +110,10 @@ unsigned LLVMGetMDKindID(const char* Name, unsigned SLen) {
 }
 
 char *LLVMGetDiagInfoDescription(LLVMDiagnosticInfoRef DI) {
-  std::string MsgStorage;
-  raw_string_ostream Stream(MsgStorage);
-  DiagnosticPrinterRawOStream DP(Stream);
-
+  StringBuilder Msg;
+  DiagnosticPrinterRawOStream DP(Msg);
   unwrap(DI)->print(DP);
-  Stream.flush();
-
-  return LLVMCreateMessage(MsgStorage.c_str());
+  return LLVMCreateMessage(Msg.str().c_str());
 }
 
 LLVMDiagnosticSeverity LLVMGetDiagInfoSeverity(LLVMDiagnosticInfoRef DI){
@@ -201,13 +197,9 @@ LLVMBool LLVMPrintModuleToFile(LLVMModuleRef M, const char *Filename,
 }
 
 char *LLVMPrintModuleToString(LLVMModuleRef M) {
-  std::string buf;
-  raw_string_ostream os(buf);
-
+  StringBuilder os;
   unwrap(M)->print(os, nullptr);
-  os.flush();
-
-  return strdup(buf.c_str());
+  return strdup(os.str().c_str());
 }
 
 /*--.. Operations on inline assembler ......................................--*/
@@ -278,14 +270,10 @@ void LLVMDumpType(LLVMTypeRef Ty) {
 }
 
 char *LLVMPrintTypeToString(LLVMTypeRef Ty) {
-  std::string buf;
-  raw_string_ostream os(buf);
-
+  StringBuilder os;
   assert(unwrap(Ty) != nullptr && "Expecting non-null Type");
   unwrap(Ty)->print(os);
-  os.flush();
-
-  return strdup(buf.c_str());
+  return strdup(os.str().c_str());
 }
 
 /*--.. Operations on integer types .........................................--*/
@@ -529,14 +517,10 @@ void LLVMDumpValue(LLVMValueRef Val) {
 }
 
 char* LLVMPrintValueToString(LLVMValueRef Val) {
-  std::string buf;
-  raw_string_ostream os(buf);
-
+  StringBuilder os;
   assert(unwrap(Val) != nullptr && "Expecting non-null Value");
   unwrap(Val)->print(os);
-  os.flush();
-
-  return strdup(buf.c_str());
+  return strdup(os.str().c_str());
 }
 
 void LLVMReplaceAllUsesWith(LLVMValueRef OldVal, LLVMValueRef NewVal) {
diff --git a/lib/IR/DataLayout.cpp b/lib/IR/DataLayout.cpp
index dea05fb..992f7c9 100644
--- a/lib/IR/DataLayout.cpp
+++ b/lib/IR/DataLayout.cpp
@@ -519,8 +519,7 @@ const StructLayout *DataLayout::getStructLayout(StructType *Ty) const {
 }
 
 std::string DataLayout::getStringRepresentation() const {
-  std::string Result;
-  raw_string_ostream OS(Result);
+  StringBuilder OS;
 
   OS << (LittleEndian ? "e" : "E");
 
diff --git a/lib/IRReader/IRReader.cpp b/lib/IRReader/IRReader.cpp
index f4ed437..c1f6c71 100644
--- a/lib/IRReader/IRReader.cpp
+++ b/lib/IRReader/IRReader.cpp
@@ -108,13 +108,9 @@ LLVMBool LLVMParseIRInContext(LLVMContextRef ContextRef,
 
   if(!*OutM) {
     if (OutMessage) {
-      std::string buf;
-      raw_string_ostream os(buf);
-
+      StringBuilder os;
       Diag.print(nullptr, os, false);
-      os.flush();
-
-      *OutMessage = strdup(buf.c_str());
+      *OutMessage = strdup(os.str().c_str());
     }
     return 1;
   }
diff --git a/lib/MC/MCParser/AsmParser.cpp b/lib/MC/MCParser/AsmParser.cpp
index cbff7be..773b28d 100644
--- a/lib/MC/MCParser/AsmParser.cpp
+++ b/lib/MC/MCParser/AsmParser.cpp
@@ -4534,8 +4534,7 @@ bool AsmParser::parseMSInlineAsm(
   }
 
   // Build the IR assembly string.
-  std::string AsmStringIR;
-  raw_string_ostream OS(AsmStringIR);
+  StringBuilder OS;
   const char *AsmStart = SrcMgr.getMemoryBuffer(0)->getBufferStart();
   const char *AsmEnd = SrcMgr.getMemoryBuffer(0)->getBufferEnd();
   array_pod_sort(AsmStrRewrites.begin(), AsmStrRewrites.end(), rewritesSort);
@@ -4603,8 +4602,7 @@ bool AsmParser::parseMSInlineAsm(
     }
     case AOK_DotOperator:
       // Insert the dot if the user omitted it.
-      OS.flush();
-      if (AsmStringIR.back() != '.')
+      if (OS.str().back() != '.')
         OS << '.';
       OS << (*I).Val;
       break;
diff --git a/lib/TableGen/TGParser.cpp b/lib/TableGen/TGParser.cpp
index 0550692..c531d79 100644
--- a/lib/TableGen/TGParser.cpp
+++ b/lib/TableGen/TGParser.cpp
@@ -1307,8 +1307,7 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType,
     if (ItemType) {
       ListRecTy *ListType = dyn_cast<ListRecTy>(ItemType);
       if (!ListType) {
-        std::string s;
-        raw_string_ostream ss(s);
+        StringBuilder ss;
         ss << "Type mismatch for list, expected list type, got "
            << ItemType->getAsString();
         TokError(ss.str());
diff --git a/lib/Target/NVPTX/NVPTXAsmPrinter.cpp b/lib/Target/NVPTX/NVPTXAsmPrinter.cpp
index e6cbf64..5fb445e 100644
--- a/lib/Target/NVPTX/NVPTXAsmPrinter.cpp
+++ b/lib/Target/NVPTX/NVPTXAsmPrinter.cpp
@@ -146,8 +146,7 @@ const MCExpr *nvptx::LowerConstant(const Constant *CV, AsmPrinter &AP) {
 
     // Otherwise report the problem to the user.
     {
-      std::string S;
-      raw_string_ostream OS(S);
+      StringBuilder OS;
       OS << "Unsupported expression in static initializer: ";
       CE->printAsOperand(OS, /*PrintType=*/ false,
                          !AP.MF ? nullptr : AP.MF->getFunction()->getParent());
diff --git a/lib/Target/TargetMachineC.cpp b/lib/Target/TargetMachineC.cpp
index 20923c9..cf04faa 100644
--- a/lib/Target/TargetMachineC.cpp
+++ b/lib/Target/TargetMachineC.cpp
@@ -237,13 +237,11 @@ LLVMBool LLVMTargetMachineEmitToFile(LLVMTargetMachineRef T, LLVMModuleRef M,
 LLVMBool LLVMTargetMachineEmitToMemoryBuffer(LLVMTargetMachineRef T,
   LLVMModuleRef M, LLVMCodeGenFileType codegen, char** ErrorMessage,
   LLVMMemoryBufferRef *OutMemBuf) {
-  std::string CodeString;
-  raw_string_ostream OStream(CodeString);
-  formatted_raw_ostream Out(OStream);
+  StringBuilder Code;
+  formatted_raw_ostream Out(Code);
   bool Result = LLVMTargetMachineEmit(T, M, Out, codegen, ErrorMessage);
-  OStream.flush();
 
-  std::string &Data = OStream.str();
+  std::string &Data = Code.str();
   *OutMemBuf = LLVMCreateMemoryBufferWithMemoryRangeCopy(Data.c_str(),
                                                      Data.length(), "");
   return Result;
diff --git a/lib/Transforms/Instrumentation/GCOVProfiling.cpp b/lib/Transforms/Instrumentation/GCOVProfiling.cpp
index cfeb62e..f2978ba 100644
--- a/lib/Transforms/Instrumentation/GCOVProfiling.cpp
+++ b/lib/Transforms/Instrumentation/GCOVProfiling.cpp
@@ -316,11 +316,9 @@ namespace {
       }
       ReturnBlock = new GCOVBlock(i++, os);
 
-      std::string FunctionNameAndLine;
-      raw_string_ostream FNLOS(FunctionNameAndLine);
-      FNLOS << getFunctionName(SP) << SP.getLineNumber();
-      FNLOS.flush();
-      FuncChecksum = hash_value(FunctionNameAndLine);
+      StringBuilder FnNameLine;
+      FnNameLine << getFunctionName(SP) << SP.getLineNumber();
+      FuncChecksum = hash_value(FnNameLine.str());
     }
 
     ~GCOVFunction() {
@@ -337,15 +335,14 @@ namespace {
     }
 
     std::string getEdgeDestinations() {
-      std::string EdgeDestinations;
-      raw_string_ostream EDOS(EdgeDestinations);
+      StringBuilder EdgeDestinations;
       Function *F = Blocks.begin()->first->getParent();
       for (Function::iterator I = F->begin(), E = F->end(); I != E; ++I) {
         GCOVBlock &Block = *Blocks[I];
         for (int i = 0, e = Block.OutEdges.size(); i != e; ++i)
-          EDOS << Block.OutEdges[i]->Number;
+          EdgeDestinations << Block.OutEdges[i]->Number;
       }
-      return EdgeDestinations;
+      return EdgeDestinations.str();
     }
 
     uint32_t getFuncChecksum() {
diff --git a/lib/Transforms/ObjCARC/ObjCARCOpts.cpp b/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
index dd4dd50..45f7a7f 100644
--- a/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
+++ b/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
@@ -835,8 +835,7 @@ static MDString *AppendMDNodeToSourcePtr(unsigned NodeId,
       // of line at the module level and to provide a very simple format
       // encoding the information herein. Both of these makes it simpler to
       // parse the annotations by a simple external program.
-      std::string Str;
-      raw_string_ostream os(Str);
+      StringBuilder os;
       os << "(" << Inst->getParent()->getParent()->getName() << ",%"
          << Inst->getName() << ")";
 
@@ -849,8 +848,7 @@ static MDString *AppendMDNodeToSourcePtr(unsigned NodeId,
       Hash = cast<MDString>(Node->getOperand(0));
     }
   } else if (Argument *Arg = dyn_cast<Argument>(Ptr)) {
-    std::string str;
-    raw_string_ostream os(str);
+    StringBuilder os;
     os << "(" << Arg->getParent()->getName() << ",%" << Arg->getName()
        << ")";
     Hash = MDString::get(Arg->getContext(), os.str());
@@ -860,8 +858,7 @@ static MDString *AppendMDNodeToSourcePtr(unsigned NodeId,
 }
 
 static std::string SequenceToString(Sequence A) {
-  std::string str;
-  raw_string_ostream os(str);
+  StringBuilder os;
   os << A;
   return os.str();
 }
diff --git a/tools/llvm-ar/llvm-ar.cpp b/tools/llvm-ar/llvm-ar.cpp
index 77914c5..6618464 100644
--- a/tools/llvm-ar/llvm-ar.cpp
+++ b/tools/llvm-ar/llvm-ar.cpp
@@ -686,8 +686,7 @@ static void writeSymbolTable(
     std::vector<std::pair<unsigned, unsigned> > &MemberOffsetRefs) {
   unsigned StartOffset = 0;
   unsigned MemberNum = 0;
-  std::string NameBuf;
-  raw_string_ostream NameOS(NameBuf);
+  StringBuilder NameOS;
   unsigned NumSyms = 0;
   std::vector<object::SymbolicFile *> DeleteIt;
   LLVMContext &Context = getGlobalContext();
diff --git a/tools/llvm-objdump/llvm-objdump.cpp b/tools/llvm-objdump/llvm-objdump.cpp
index a4fc6d0..894bac1 100644
--- a/tools/llvm-objdump/llvm-objdump.cpp
+++ b/tools/llvm-objdump/llvm-objdump.cpp
@@ -222,8 +222,7 @@ static void emitDOTFile(const char *FileName, const MCFunction &f,
         Out << "<o>";
 
       // Escape special chars and print the instruction in mnemonic form.
-      std::string Str;
-      raw_string_ostream OS(Str);
+      StringBuilder OS;
       IP->printInst(&(*i)->getInsts()->at(ii).Inst, OS, "");
       Out << DOT::EscapeString(OS.str());
     }
diff --git a/tools/llvm-readobj/ARMWinEHPrinter.cpp b/tools/llvm-readobj/ARMWinEHPrinter.cpp
index d82b847..de4c058 100644
--- a/tools/llvm-readobj/ARMWinEHPrinter.cpp
+++ b/tools/llvm-readobj/ARMWinEHPrinter.cpp
@@ -95,8 +95,7 @@ raw_ostream &operator<<(raw_ostream &OS, const ARM::WinEH::ReturnType &RT) {
 
 static std::string formatSymbol(StringRef Name, uint64_t Address,
                                 uint64_t Offset = 0) {
-  std::string Buffer;
-  raw_string_ostream OS(Buffer);
+  StringBuilder OS;
 
   if (!Name.empty())
     OS << Name << " ";
diff --git a/tools/llvm-readobj/Win64EHDumper.cpp b/tools/llvm-readobj/Win64EHDumper.cpp
index c64d362..f876d46 100644
--- a/tools/llvm-readobj/Win64EHDumper.cpp
+++ b/tools/llvm-readobj/Win64EHDumper.cpp
@@ -115,8 +115,7 @@ static unsigned getNumUsedSlots(const UnwindCode &UnwindCode) {
 static std::string formatSymbol(const Dumper::Context &Ctx,
                                 const coff_section *Section, uint64_t Offset,
                                 uint32_t Displacement) {
-  std::string Buffer;
-  raw_string_ostream OS(Buffer);
+  StringBuilder OS;
 
   StringRef Name;
   SymbolRef Symbol;
@@ -131,6 +130,7 @@ static std::string formatSymbol(const Dumper::Context &Ctx,
     OS << format(" +0x%X (0x%" PRIX64 ")", Displacement, Offset);
   else
     OS << format(" (0x%" PRIX64 ")", Offset);
+
   return OS.str();
 }
 
diff --git a/unittests/ExecutionEngine/JIT/JITTest.cpp b/unittests/ExecutionEngine/JIT/JITTest.cpp
index 5eb52c6..3a963b0 100644
--- a/unittests/ExecutionEngine/JIT/JITTest.cpp
+++ b/unittests/ExecutionEngine/JIT/JITTest.cpp
@@ -70,9 +70,9 @@ Function *makeReturnGlobal(std::string Name, GlobalVariable *G, Module *M) {
 }
 
 std::string DumpFunction(const Function *F) {
-  std::string Result;
-  raw_string_ostream(Result) << "" << *F;
-  return Result;
+  StringBuilder Result;
+  Result << "" << *F;
+  return Result.str();
 }
 
 class RecordingJITMemoryManager : public JITMemoryManager {
@@ -170,10 +170,9 @@ bool LoadAssemblyInto(Module *M, const char *assembly) {
   SMDiagnostic Error;
   bool success =
     nullptr != ParseAssemblyString(assembly, M, Error, M->getContext());
-  std::string errMsg;
-  raw_string_ostream os(errMsg);
-  Error.print("", os);
-  EXPECT_TRUE(success) << os.str();
+  StringBuilder errMsg;
+  Error.print("", errMsg);
+  EXPECT_TRUE(success) << errMsg.str();
   return success;
 }
 
diff --git a/utils/TableGen/CodeEmitterGen.cpp b/utils/TableGen/CodeEmitterGen.cpp
index 4d0c0ca..e909cf3 100644
--- a/utils/TableGen/CodeEmitterGen.cpp
+++ b/utils/TableGen/CodeEmitterGen.cpp
@@ -319,8 +319,7 @@ void CodeEmitterGen::run(raw_ostream &o) {
 
   // Default case: unhandled opcode
   o << "  default:\n"
-    << "    std::string msg;\n"
-    << "    raw_string_ostream Msg(msg);\n"
+    << "    StringBuilder Msg;\n"
     << "    Msg << \"Not supported instr: \" << MI;\n"
     << "    report_fatal_error(Msg.str());\n"
     << "  }\n"
diff --git a/utils/TableGen/SetTheory.cpp b/utils/TableGen/SetTheory.cpp
index 5ead7ed..83aeffc 100644
--- a/utils/TableGen/SetTheory.cpp
+++ b/utils/TableGen/SetTheory.cpp
@@ -209,13 +209,12 @@ struct SequenceOp : public SetTheory::Operator {
         break;
       else if (Step < 0 && From < To)
         break;
-      std::string Name;
-      raw_string_ostream OS(Name);
-      OS << format(Format.c_str(), unsigned(From));
-      Record *Rec = Records.getDef(OS.str());
+      StringBuilder Name;
+      Name << format(Format.c_str(), unsigned(From));
+      Record *Rec = Records.getDef(Name.str());
       if (!Rec)
-        PrintFatalError(Loc, "No def named '" + Name + "': " +
-          Expr->getAsString());
+        PrintFatalError(Loc, "No def named '" + Name.str() + "': " +
+                                 Expr->getAsString());
       // Try to reevaluate Rec in case it is a set.
       if (const RecVec *Result = ST.expand(Rec))
         Elts.insert(Result->begin(), Result->end());
diff --git a/utils/yaml-bench/YAMLBench.cpp b/utils/yaml-bench/YAMLBench.cpp
index 58b7356..123af66 100644
--- a/utils/yaml-bench/YAMLBench.cpp
+++ b/utils/yaml-bench/YAMLBench.cpp
@@ -166,23 +166,21 @@ static void benchmark( llvm::TimerGroup &Group
 }
 
 static std::string createJSONText(size_t MemoryMB, unsigned ValueSize) {
-  std::string JSONText;
-  llvm::raw_string_ostream Stream(JSONText);
+  llvm::StringBuilder Stream;
   Stream << "[\n";
   size_t MemoryBytes = MemoryMB * 1024 * 1024;
-  while (JSONText.size() < MemoryBytes) {
+  while (Stream.tell() < MemoryBytes) {
     Stream << " {\n"
            << "  \"key1\": \"" << std::string(ValueSize, '*') << "\",\n"
            << "  \"key2\": \"" << std::string(ValueSize, '*') << "\",\n"
            << "  \"key3\": \"" << std::string(ValueSize, '*') << "\"\n"
            << " }";
-    Stream.flush();
-    if (JSONText.size() < MemoryBytes) Stream << ",";
+    if (Stream.tell() < MemoryBytes)
+      Stream << ",";
     Stream << "\n";
   }
   Stream << "]\n";
-  Stream.flush();
-  return JSONText;
+  return Stream.str();
 }
 
 int main(int argc, char **argv) {


More information about the llvm-commits mailing list