Use raw_pwrite_stream in clang.
authorRafael Espindola <rafael.espindola@gmail.com>
Tue, 14 Apr 2015 15:15:49 +0000 (15:15 +0000)
committerRafael Espindola <rafael.espindola@gmail.com>
Tue, 14 Apr 2015 15:15:49 +0000 (15:15 +0000)
This is a small improvement to -emit-pth and allows llvm to start requiring it.

llvm-svn: 234897

clang/include/clang/Basic/LLVM.h
clang/include/clang/CodeGen/BackendUtil.h
clang/include/clang/Frontend/CompilerInstance.h
clang/include/clang/Frontend/Utils.h
clang/lib/CodeGen/BackendUtil.cpp
clang/lib/CodeGen/CodeGenAction.cpp
clang/lib/Frontend/CacheTokens.cpp
clang/lib/Frontend/CompilerInstance.cpp
clang/lib/Frontend/FrontendActions.cpp
clang/test/PCH/emit-pth.c
clang/tools/driver/cc1as_main.cpp

index 3e01d25..0e6ff92 100644 (file)
@@ -45,6 +45,7 @@ namespace llvm {
   class RefCountedBaseVPTR;
 
   class raw_ostream;
+  class raw_pwrite_stream;
   // TODO: DenseMap, ...
 }
 
@@ -76,6 +77,7 @@ namespace clang {
   using llvm::RefCountedBaseVPTR;
 
   using llvm::raw_ostream;
+  using llvm::raw_pwrite_stream;
 } // end namespace clang.
 
 #endif
index 07c6183..8586e77 100644 (file)
@@ -34,7 +34,7 @@ namespace clang {
   void EmitBackendOutput(DiagnosticsEngine &Diags, const CodeGenOptions &CGOpts,
                          const TargetOptions &TOpts, const LangOptions &LOpts,
                          StringRef TDesc, llvm::Module *M, BackendAction Action,
-                         raw_ostream *OS);
+                         raw_pwrite_stream *OS);
 }
 
 #endif
index 433c41c..6251566 100644 (file)
@@ -161,6 +161,11 @@ class CompilerInstance : public ModuleLoader {
           TempFilename(std::move(O.TempFilename)), OS(std::move(O.OS)) {}
   };
 
+  /// If the output doesn't support seeking (terminal, pipe). we switch
+  /// the stream to a buffer_ostream. These are the buffer and the original
+  /// stream.
+  std::unique_ptr<llvm::raw_fd_ostream> NonSeekStream;
+
   /// The list of active output files.
   std::list<OutputFile> OutputFiles;
 
@@ -631,21 +636,19 @@ public:
   /// atomically replace the target output on success).
   ///
   /// \return - Null on error.
-  llvm::raw_fd_ostream *
-  createDefaultOutputFile(bool Binary = true, StringRef BaseInput = "",
-                          StringRef Extension = "");
+  raw_pwrite_stream *createDefaultOutputFile(bool Binary = true,
+                                             StringRef BaseInput = "",
+                                             StringRef Extension = "");
 
   /// Create a new output file and add it to the list of tracked output files,
   /// optionally deriving the output path name.
   ///
   /// \return - Null on error.
-  llvm::raw_fd_ostream *
-  createOutputFile(StringRef OutputPath,
-                   bool Binary, bool RemoveFileOnSignal,
-                   StringRef BaseInput,
-                   StringRef Extension,
-                   bool UseTemporary,
-                   bool CreateMissingDirectories = false);
+  raw_pwrite_stream *createOutputFile(StringRef OutputPath, bool Binary,
+                                      bool RemoveFileOnSignal,
+                                      StringRef BaseInput, StringRef Extension,
+                                      bool UseTemporary,
+                                      bool CreateMissingDirectories = false);
 
   /// Create a new output file, optionally deriving the output path name.
   ///
@@ -672,7 +675,7 @@ public:
   /// stored here on success.
   /// \param TempPathName [out] - If given, the temporary file path name
   /// will be stored here on success.
-  static std::unique_ptr<llvm::raw_fd_ostream>
+  std::unique_ptr<raw_pwrite_stream>
   createOutputFile(StringRef OutputPath, std::error_code &Error, bool Binary,
                    bool RemoveFileOnSignal, StringRef BaseInput,
                    StringRef Extension, bool UseTemporary,
index 4cd93b9..cd0ebf6 100644 (file)
@@ -159,9 +159,8 @@ void AttachHeaderIncludeGen(Preprocessor &PP, bool ShowAllHeaders = false,
                             StringRef OutputPath = "",
                             bool ShowDepth = true, bool MSStyle = false);
 
-/// CacheTokens - Cache tokens for use with PCH. Note that this requires
-/// a seekable stream.
-void CacheTokens(Preprocessor &PP, llvm::raw_fd_ostream* OS);
+/// Cache tokens for use with PCH. Note that this requires a seekable stream.
+void CacheTokens(Preprocessor &PP, raw_pwrite_stream *OS);
 
 /// The ChainedIncludesSource class converts headers to chained PCHs in
 /// memory, mainly for testing.
index 7c443cc..4353b30 100644 (file)
@@ -96,7 +96,7 @@ private:
 
   void CreatePasses();
 
-  /// CreateTargetMachine - Generates the TargetMachine.
+  /// Generates the TargetMachine.
   /// Returns Null if it is unable to create the target machine.
   /// Some of our clang tests specify triples which are not built
   /// into clang. This is okay because these tests check the generated
@@ -106,10 +106,10 @@ private:
   /// the requested target.
   TargetMachine *CreateTargetMachine(bool MustCreateTM);
 
-  /// AddEmitPasses - Add passes necessary to emit assembly or LLVM IR.
+  /// Add passes necessary to emit assembly or LLVM IR.
   ///
   /// \return True on success.
-  bool AddEmitPasses(BackendAction Action, raw_ostream &OS);
+  bool AddEmitPasses(BackendAction Action, raw_pwrite_stream &OS);
 
 public:
   EmitAssemblyHelper(DiagnosticsEngine &_Diags,
@@ -132,7 +132,7 @@ public:
 
   std::unique_ptr<TargetMachine> TM;
 
-  void EmitAssembly(BackendAction Action, raw_ostream *OS);
+  void EmitAssembly(BackendAction Action, raw_pwrite_stream *OS);
 };
 
 // We need this wrapper to access LangOpts and CGOpts from extension functions
@@ -545,7 +545,8 @@ TargetMachine *EmitAssemblyHelper::CreateTargetMachine(bool MustCreateTM) {
   return TM;
 }
 
-bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action, raw_ostream &OS) {
+bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action,
+                                       raw_pwrite_stream &OS) {
 
   // Create the code generator passes.
   legacy::PassManager *PM = getCodeGenPasses();
@@ -582,7 +583,8 @@ bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action, raw_ostream &OS) {
   return true;
 }
 
-void EmitAssemblyHelper::EmitAssembly(BackendAction Action, raw_ostream *OS) {
+void EmitAssemblyHelper::EmitAssembly(BackendAction Action,
+                                      raw_pwrite_stream *OS) {
   TimeRegion Region(llvm::TimePassesIsEnabled ? &CodeGenerationTime : nullptr);
 
   bool UsesCodeGen = (Action != Backend_EmitNothing &&
@@ -644,7 +646,7 @@ void clang::EmitBackendOutput(DiagnosticsEngine &Diags,
                               const clang::TargetOptions &TOpts,
                               const LangOptions &LOpts, StringRef TDesc,
                               Module *M, BackendAction Action,
-                              raw_ostream *OS) {
+                              raw_pwrite_stream *OS) {
   EmitAssemblyHelper AsmHelper(Diags, CGOpts, TOpts, LOpts, M);
 
   AsmHelper.EmitAssembly(Action, OS);
index b5ed12a..60aac07 100644 (file)
@@ -46,7 +46,7 @@ namespace clang {
     const CodeGenOptions &CodeGenOpts;
     const TargetOptions &TargetOpts;
     const LangOptions &LangOpts;
-    raw_ostream *AsmOutStream;
+    raw_pwrite_stream *AsmOutStream;
     ASTContext *Context;
 
     Timer LLVMIRGeneration;
@@ -61,7 +61,7 @@ namespace clang {
                     const TargetOptions &targetopts,
                     const LangOptions &langopts, bool TimePasses,
                     const std::string &infile, llvm::Module *LinkModule,
-                    raw_ostream *OS, LLVMContext &C,
+                    raw_pwrite_stream *OS, LLVMContext &C,
                     CoverageSourceInfo *CoverageInfo = nullptr)
         : Diags(_Diags), Action(action), CodeGenOpts(compopts),
           TargetOpts(targetopts), LangOpts(langopts), AsmOutStream(OS),
@@ -601,9 +601,8 @@ llvm::LLVMContext *CodeGenAction::takeLLVMContext() {
   return VMContext;
 }
 
-static raw_ostream *GetOutputStream(CompilerInstance &CI,
-                                    StringRef InFile,
-                                    BackendAction Action) {
+static raw_pwrite_stream *
+GetOutputStream(CompilerInstance &CI, StringRef InFile, BackendAction Action) {
   switch (Action) {
   case Backend_EmitAssembly:
     return CI.createDefaultOutputFile(false, InFile, "s");
@@ -625,7 +624,7 @@ static raw_ostream *GetOutputStream(CompilerInstance &CI,
 std::unique_ptr<ASTConsumer>
 CodeGenAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
   BackendAction BA = static_cast<BackendAction>(Act);
-  std::unique_ptr<raw_ostream> OS(GetOutputStream(CI, InFile, BA));
+  std::unique_ptr<raw_pwrite_stream> OS(GetOutputStream(CI, InFile, BA));
   if (BA != Backend_EmitNothing && !OS)
     return nullptr;
 
@@ -678,7 +677,7 @@ void CodeGenAction::ExecuteAction() {
   if (getCurrentFileKind() == IK_LLVM_IR) {
     BackendAction BA = static_cast<BackendAction>(Act);
     CompilerInstance &CI = getCompilerInstance();
-    raw_ostream *OS = GetOutputStream(CI, getCurrentFile(), BA);
+    raw_pwrite_stream *OS = GetOutputStream(CI, getCurrentFile(), BA);
     if (BA != Backend_EmitNothing && !OS)
       return;
 
index 68429d9..7d2a09c 100644 (file)
@@ -183,7 +183,7 @@ class PTHWriter {
   typedef llvm::StringMap<OffsetOpt, llvm::BumpPtrAllocator> CachedStrsTy;
 
   IDMap IM;
-  llvm::raw_fd_ostream& Out;
+  raw_pwrite_stream &Out;
   Preprocessor& PP;
   uint32_t idcount;
   PTHMap PM;
@@ -236,8 +236,8 @@ class PTHWriter {
   Offset EmitCachedSpellings();
 
 public:
-  PTHWriter(llvm::raw_fd_ostream& out, Preprocessor& pp)
-    : Out(out), PP(pp), idcount(0), CurStrOffset(0) {}
+  PTHWriter(raw_pwrite_stream &out, Preprocessor &pp)
+      : Out(out), PP(pp), idcount(0), CurStrOffset(0) {}
 
   PTHMap &getPM() { return PM; }
   void GeneratePTH(const std::string &MainFile);
@@ -468,6 +468,16 @@ Offset PTHWriter::EmitCachedSpellings() {
   return SpellingsOff;
 }
 
+static uint32_t swap32le(uint32_t X) {
+  return llvm::support::endian::byte_swap<uint32_t, llvm::support::little>(X);
+}
+
+static void pwrite32le(raw_pwrite_stream &OS, uint32_t Val, uint64_t &Off) {
+  uint32_t LEVal = swap32le(Val);
+  OS.pwrite(reinterpret_cast<const char *>(&LEVal), 4, Off);
+  Off += 4;
+}
+
 void PTHWriter::GeneratePTH(const std::string &MainFile) {
   // Generate the prologue.
   Out << "cfe-pth" << '\0';
@@ -520,11 +530,11 @@ void PTHWriter::GeneratePTH(const std::string &MainFile) {
   Offset FileTableOff = EmitFileTable();
 
   // Finally, write the prologue.
-  Out.seek(PrologueOffset);
-  Emit32(IdTableOff.first);
-  Emit32(IdTableOff.second);
-  Emit32(FileTableOff);
-  Emit32(SpellingOff);
+  uint64_t Off = PrologueOffset;
+  pwrite32le(Out, IdTableOff.first, Off);
+  pwrite32le(Out, IdTableOff.second, Off);
+  pwrite32le(Out, FileTableOff, Off);
+  pwrite32le(Out, SpellingOff, Off);
 }
 
 namespace {
@@ -559,8 +569,7 @@ public:
 };
 } // end anonymous namespace
 
-
-void clang::CacheTokens(Preprocessor &PP, llvm::raw_fd_ostream* OS) {
+void clang::CacheTokens(Preprocessor &PP, raw_pwrite_stream *OS) {
   // Get the name of the main file.
   const SourceManager &SrcMgr = PP.getSourceManager();
   const FileEntry *MainFile = SrcMgr.getFileEntryForID(SrcMgr.getMainFileID());
index 0628442..fdaf7e2 100644 (file)
@@ -550,11 +550,11 @@ void CompilerInstance::clearOutputFiles(bool EraseFiles) {
 
   }
   OutputFiles.clear();
+  NonSeekStream.reset();
 }
 
-llvm::raw_fd_ostream *
-CompilerInstance::createDefaultOutputFile(bool Binary,
-                                          StringRef InFile,
+raw_pwrite_stream *
+CompilerInstance::createDefaultOutputFile(bool Binary, StringRef InFile,
                                           StringRef Extension) {
   return createOutputFile(getFrontendOpts().OutputFile, Binary,
                           /*RemoveFileOnSignal=*/true, InFile, Extension,
@@ -568,16 +568,14 @@ llvm::raw_null_ostream *CompilerInstance::createNullOutputFile() {
   return Ret;
 }
 
-llvm::raw_fd_ostream *
-CompilerInstance::createOutputFile(StringRef OutputPath,
-                                   bool Binary, bool RemoveFileOnSignal,
-                                   StringRef InFile,
-                                   StringRef Extension,
-                                   bool UseTemporary,
+raw_pwrite_stream *
+CompilerInstance::createOutputFile(StringRef OutputPath, bool Binary,
+                                   bool RemoveFileOnSignal, StringRef InFile,
+                                   StringRef Extension, bool UseTemporary,
                                    bool CreateMissingDirectories) {
   std::string OutputPathName, TempPathName;
   std::error_code EC;
-  std::unique_ptr<llvm::raw_fd_ostream> OS = createOutputFile(
+  std::unique_ptr<raw_pwrite_stream> OS = createOutputFile(
       OutputPath, EC, Binary, RemoveFileOnSignal, InFile, Extension,
       UseTemporary, CreateMissingDirectories, &OutputPathName, &TempPathName);
   if (!OS) {
@@ -586,7 +584,7 @@ CompilerInstance::createOutputFile(StringRef OutputPath,
     return nullptr;
   }
 
-  llvm::raw_fd_ostream *Ret = OS.get();
+  raw_pwrite_stream *Ret = OS.get();
   // Add the output file -- but don't try to remove "-", since this means we are
   // using stdin.
   addOutputFile(OutputFile((OutputPathName != "-") ? OutputPathName : "",
@@ -595,7 +593,7 @@ CompilerInstance::createOutputFile(StringRef OutputPath,
   return Ret;
 }
 
-std::unique_ptr<llvm::raw_fd_ostream> CompilerInstance::createOutputFile(
+std::unique_ptr<llvm::raw_pwrite_stream> CompilerInstance::createOutputFile(
     StringRef OutputPath, std::error_code &Error, bool Binary,
     bool RemoveFileOnSignal, StringRef InFile, StringRef Extension,
     bool UseTemporary, bool CreateMissingDirectories,
@@ -683,7 +681,13 @@ std::unique_ptr<llvm::raw_fd_ostream> CompilerInstance::createOutputFile(
   if (TempPathName)
     *TempPathName = TempFile;
 
-  return OS;
+  if (!Binary || OS->supportsSeeking())
+    return std::move(OS);
+
+  auto B = llvm::make_unique<llvm::buffer_ostream>(*OS);
+  assert(!NonSeekStream);
+  NonSeekStream = std::move(OS);
+  return std::move(B);
 }
 
 // Initialization Utilities
index 5ffe65f..0defe5c 100644 (file)
@@ -599,15 +599,10 @@ void DumpTokensAction::ExecuteAction() {
 
 void GeneratePTHAction::ExecuteAction() {
   CompilerInstance &CI = getCompilerInstance();
-  llvm::raw_fd_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile());
+  raw_pwrite_stream *OS = CI.createDefaultOutputFile(true, getCurrentFile());
   if (!OS)
     return;
 
-  if (!OS->supportsSeeking()) {
-    // FIXME: Don't fail this way.
-    llvm::report_fatal_error("PTH requires a seekable file for output!");
-  }
-
   CacheTokens(CI.getPreprocessor(), OS);
 }
 
index 7f863cf..2c0fba7 100644 (file)
@@ -1,7 +1,7 @@
 // RUN: %clang_cc1 -triple i386-unknown-unknown -emit-pth -o %t1 %s
 // RUN: %clang_cc1 -triple i386-unknown-unknown -emit-pth -o - %s > %t2
 // RUN: cmp %t1 %t2
-// RUN: not %clang_cc1 -triple i386-unknown-unknown -emit-pth -o - %s 2>&1 | \
+// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-pth -o - %s | \
 // RUN: FileCheck %s
 
-// CHECK: PTH requires a seekable file for output!
+// CHECK: cfe-pth
index a4431a1..6feffa8 100644 (file)
@@ -315,8 +315,8 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts,
     MAI->setCompressDebugSections(true);
 
   bool IsBinary = Opts.OutputType == AssemblerInvocation::FT_Obj;
-  std::unique_ptr<raw_fd_ostream> Out = getOutputStream(Opts, Diags, IsBinary);
-  if (!Out)
+  std::unique_ptr<raw_fd_ostream> FDOS = getOutputStream(Opts, Diags, IsBinary);
+  if (!FDOS)
     return true;
 
   // FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and
@@ -355,6 +355,9 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts,
   std::unique_ptr<MCSubtargetInfo> STI(
       TheTarget->createMCSubtargetInfo(Opts.Triple, Opts.CPU, FS));
 
+  raw_pwrite_stream *Out = FDOS.get();
+  std::unique_ptr<buffer_ostream> BOS;
+
   // FIXME: There is a bit of code duplication with addPassesToEmitFile.
   if (Opts.OutputType == AssemblerInvocation::FT_Asm) {
     MCInstPrinter *IP = TheTarget->createMCInstPrinter(
@@ -374,6 +377,11 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts,
   } else {
     assert(Opts.OutputType == AssemblerInvocation::FT_Obj &&
            "Invalid file type!");
+    if (!FDOS->supportsSeeking()) {
+      BOS = make_unique<buffer_ostream>(*FDOS);
+      Out = BOS.get();
+    }
+
     MCCodeEmitter *CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx);
     MCAsmBackend *MAB = TheTarget->createMCAsmBackend(*MRI, Opts.Triple,
                                                       Opts.CPU);
@@ -402,7 +410,8 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts,
   }
 
   // Close the output stream early.
-  Out.reset();
+  BOS.reset();
+  FDOS.reset();
 
   // Delete output file if there were errors.
   if (Failed && Opts.OutputPath != "-")