This is a small improvement to -emit-pth and allows llvm to start requiring it.
llvm-svn: 234897
class RefCountedBaseVPTR;
class raw_ostream;
+ class raw_pwrite_stream;
// TODO: DenseMap, ...
}
using llvm::RefCountedBaseVPTR;
using llvm::raw_ostream;
+ using llvm::raw_pwrite_stream;
} // end namespace clang.
#endif
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
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;
/// 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.
///
/// 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,
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.
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
/// 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,
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
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();
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 &&
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);
const CodeGenOptions &CodeGenOpts;
const TargetOptions &TargetOpts;
const LangOptions &LangOpts;
- raw_ostream *AsmOutStream;
+ raw_pwrite_stream *AsmOutStream;
ASTContext *Context;
Timer LLVMIRGeneration;
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),
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");
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;
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;
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;
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);
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';
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 {
};
} // 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());
}
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,
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) {
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 : "",
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,
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
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);
}
// 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
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
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(
} 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);
}
// Close the output stream early.
- Out.reset();
+ BOS.reset();
+ FDOS.reset();
// Delete output file if there were errors.
if (Failed && Opts.OutputPath != "-")