Use raw_pwrite_stream in clang.

This is a small improvement to -emit-pth and allows llvm to start requiring it.

llvm-svn: 234897
This commit is contained in:
Rafael Espindola 2015-04-14 15:15:49 +00:00
parent b913653b91
commit 2f16bc1095
11 changed files with 85 additions and 63 deletions

View 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

View 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

View 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,

View 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.

View 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);

View 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;

View 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());

View 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

View 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);
}

View 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

View 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 != "-")