From: Rafael Espindola Date: Tue, 14 Apr 2015 15:15:49 +0000 (+0000) Subject: Use raw_pwrite_stream in clang. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=23ddbddd09a4df7c9575d4835fcbf322fa91a557;p=clang Use raw_pwrite_stream in clang. This is a small improvement to -emit-pth and allows llvm to start requiring it. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@234897 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/LLVM.h b/include/clang/Basic/LLVM.h index 3e01d25add..0e6ff9259a 100644 --- a/include/clang/Basic/LLVM.h +++ b/include/clang/Basic/LLVM.h @@ -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 diff --git a/include/clang/CodeGen/BackendUtil.h b/include/clang/CodeGen/BackendUtil.h index 07c6183683..8586e77889 100644 --- a/include/clang/CodeGen/BackendUtil.h +++ b/include/clang/CodeGen/BackendUtil.h @@ -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 diff --git a/include/clang/Frontend/CompilerInstance.h b/include/clang/Frontend/CompilerInstance.h index 433c41c224..62515666d5 100644 --- a/include/clang/Frontend/CompilerInstance.h +++ b/include/clang/Frontend/CompilerInstance.h @@ -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 NonSeekStream; + /// The list of active output files. std::list 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 + std::unique_ptr createOutputFile(StringRef OutputPath, std::error_code &Error, bool Binary, bool RemoveFileOnSignal, StringRef BaseInput, StringRef Extension, bool UseTemporary, diff --git a/include/clang/Frontend/Utils.h b/include/clang/Frontend/Utils.h index 4cd93b994f..cd0ebf6112 100644 --- a/include/clang/Frontend/Utils.h +++ b/include/clang/Frontend/Utils.h @@ -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. diff --git a/lib/CodeGen/BackendUtil.cpp b/lib/CodeGen/BackendUtil.cpp index 7c443cc805..4353b30d3c 100644 --- a/lib/CodeGen/BackendUtil.cpp +++ b/lib/CodeGen/BackendUtil.cpp @@ -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 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); diff --git a/lib/CodeGen/CodeGenAction.cpp b/lib/CodeGen/CodeGenAction.cpp index b5ed12aee3..60aac0782e 100644 --- a/lib/CodeGen/CodeGenAction.cpp +++ b/lib/CodeGen/CodeGenAction.cpp @@ -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 CodeGenAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { BackendAction BA = static_cast(Act); - std::unique_ptr OS(GetOutputStream(CI, InFile, BA)); + std::unique_ptr 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(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; diff --git a/lib/Frontend/CacheTokens.cpp b/lib/Frontend/CacheTokens.cpp index 68429d9686..7d2a09cd7c 100644 --- a/lib/Frontend/CacheTokens.cpp +++ b/lib/Frontend/CacheTokens.cpp @@ -183,7 +183,7 @@ class PTHWriter { typedef llvm::StringMap 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(X); +} + +static void pwrite32le(raw_pwrite_stream &OS, uint32_t Val, uint64_t &Off) { + uint32_t LEVal = swap32le(Val); + OS.pwrite(reinterpret_cast(&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()); diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index 0628442f9b..fdaf7e2a5f 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -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 OS = createOutputFile( + std::unique_ptr 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 CompilerInstance::createOutputFile( +std::unique_ptr 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 CompilerInstance::createOutputFile( if (TempPathName) *TempPathName = TempFile; - return OS; + if (!Binary || OS->supportsSeeking()) + return std::move(OS); + + auto B = llvm::make_unique(*OS); + assert(!NonSeekStream); + NonSeekStream = std::move(OS); + return std::move(B); } // Initialization Utilities diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp index 5ffe65f9f2..0defe5c0c3 100644 --- a/lib/Frontend/FrontendActions.cpp +++ b/lib/Frontend/FrontendActions.cpp @@ -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); } diff --git a/test/PCH/emit-pth.c b/test/PCH/emit-pth.c index 7f863cf1d4..2c0fba7f09 100644 --- a/test/PCH/emit-pth.c +++ b/test/PCH/emit-pth.c @@ -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 diff --git a/tools/driver/cc1as_main.cpp b/tools/driver/cc1as_main.cpp index a4431a1f6c..6feffa8a63 100644 --- a/tools/driver/cc1as_main.cpp +++ b/tools/driver/cc1as_main.cpp @@ -315,8 +315,8 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts, MAI->setCompressDebugSections(true); bool IsBinary = Opts.OutputType == AssemblerInvocation::FT_Obj; - std::unique_ptr Out = getOutputStream(Opts, Diags, IsBinary); - if (!Out) + std::unique_ptr 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 STI( TheTarget->createMCSubtargetInfo(Opts.Triple, Opts.CPU, FS)); + raw_pwrite_stream *Out = FDOS.get(); + std::unique_ptr 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(*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 != "-")