|  | //===- subzero/src/IceCompileServer.cpp - Compile server ------------------===// | 
|  | // | 
|  | //                        The Subzero Code Generator | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | /// | 
|  | /// \file | 
|  | /// \brief Defines the basic commandline-based compile server. | 
|  | /// | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "IceCompileServer.h" | 
|  |  | 
|  | #include "IceASanInstrumentation.h" | 
|  | #include "IceClFlags.h" | 
|  | #include "IceELFStreamer.h" | 
|  | #include "IceGlobalContext.h" | 
|  | #include "IceRevision.h" | 
|  | #include "LinuxMallocProfiling.h" | 
|  |  | 
|  | #ifdef __clang__ | 
|  | #pragma clang diagnostic push | 
|  | #pragma clang diagnostic ignored "-Wunused-parameter" | 
|  | #endif // __clang__ | 
|  |  | 
|  | #ifdef PNACL_LLVM | 
|  | #include "llvm/Bitcode/NaCl/NaClBitcodeMungeUtils.h" | 
|  | #endif // PNACL_LLVM | 
|  | #include "llvm/Support/FileSystem.h" | 
|  | #include "llvm/Support/raw_os_ostream.h" | 
|  | #include "llvm/Support/Signals.h" | 
|  | #include "llvm/Support/SourceMgr.h" | 
|  | #include "llvm/Support/StreamingMemoryObject.h" | 
|  |  | 
|  | #ifdef __clang__ | 
|  | #pragma clang diagnostic pop | 
|  | #endif // __clang__ | 
|  |  | 
|  | #include <cstdio> | 
|  | #include <fstream> | 
|  | #include <iostream> | 
|  | #include <thread> | 
|  |  | 
|  | namespace Ice { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | // Define a SmallVector backed buffer as a data stream, so that it can hold the | 
|  | // generated binary version of the textual bitcode in the input file. | 
|  | class TextDataStreamer : public llvm::DataStreamer { | 
|  | public: | 
|  | TextDataStreamer() = default; | 
|  | ~TextDataStreamer() final = default; | 
|  | #ifdef PNACL_LLVM | 
|  | using CreateType = TextDataStreamer *; | 
|  | #else  // !PNACL_LLVM | 
|  | using CreateType = std::unique_ptr<TextDataStreamer>; | 
|  | #endif // !PNACL_LLVM | 
|  | static CreateType create(const std::string &Filename, std::string *Err); | 
|  | size_t GetBytes(unsigned char *Buf, size_t Len) final; | 
|  |  | 
|  | private: | 
|  | llvm::SmallVector<char, 1024> BitcodeBuffer; | 
|  | size_t Cursor = 0; | 
|  | }; | 
|  |  | 
|  | TextDataStreamer::CreateType | 
|  | TextDataStreamer::create(const std::string &Filename, std::string *Err) { | 
|  | #ifdef PNACL_LLVM | 
|  | TextDataStreamer *Streamer = new TextDataStreamer(); | 
|  | llvm::raw_string_ostream ErrStrm(*Err); | 
|  | if (std::error_code EC = llvm::readNaClRecordTextAndBuildBitcode( | 
|  | Filename, Streamer->BitcodeBuffer, &ErrStrm)) { | 
|  | ErrStrm << EC.message(); | 
|  | ErrStrm.flush(); | 
|  | delete Streamer; | 
|  | return nullptr; | 
|  | } | 
|  | ErrStrm.flush(); | 
|  | return Streamer; | 
|  | #else  // !PNACL_LLVM | 
|  | return CreateType(); | 
|  | #endif // !PNACL_LLVM | 
|  | } | 
|  |  | 
|  | size_t TextDataStreamer::GetBytes(unsigned char *Buf, size_t Len) { | 
|  | if (Cursor >= BitcodeBuffer.size()) | 
|  | return 0; | 
|  | size_t Remaining = BitcodeBuffer.size(); | 
|  | Len = std::min(Len, Remaining); | 
|  | for (size_t i = 0; i < Len; ++i) | 
|  | Buf[i] = BitcodeBuffer[Cursor + i]; | 
|  | Cursor += Len; | 
|  | return Len; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<Ostream> makeStream(const std::string &Filename, | 
|  | std::error_code &EC) { | 
|  | if (Filename == "-") { | 
|  | return std::unique_ptr<Ostream>(new llvm::raw_os_ostream(std::cout)); | 
|  | } else if (Filename == "/dev/stderr") { | 
|  | return std::unique_ptr<Ostream>(new llvm::raw_os_ostream(std::cerr)); | 
|  | } else { | 
|  | return std::unique_ptr<Ostream>( | 
|  | new llvm::raw_fd_ostream(Filename, EC, llvm::sys::fs::F_None)); | 
|  | } | 
|  | } | 
|  |  | 
|  | ErrorCodes getReturnValue(ErrorCodes Val) { | 
|  | if (getFlags().getAlwaysExitSuccess()) | 
|  | return EC_None; | 
|  | return Val; | 
|  | } | 
|  |  | 
|  | // Reports fatal error message, and then exits with success status 0. | 
|  | void reportFatalErrorThenExitSuccess(void *UserData, const std::string &Reason, | 
|  | bool GenCrashDag) { | 
|  | (void)UserData; | 
|  | (void)GenCrashDag; | 
|  |  | 
|  | // Note: This code is (mostly) copied from llvm/lib/Support/ErrorHandling.cpp | 
|  |  | 
|  | // Blast the result out to stderr.  We don't try hard to make sure this | 
|  | // succeeds (e.g. handling EINTR) and we can't use errs() here because | 
|  | // raw ostreams can call report_fatal_error. | 
|  | llvm::SmallVector<char, 64> Buffer; | 
|  | llvm::raw_svector_ostream OS(Buffer); | 
|  | OS << "LLVM ERROR: " << Reason << "\n"; | 
|  | llvm::StringRef MessageStr = OS.str(); | 
|  | ssize_t Written = | 
|  | std::fwrite(MessageStr.data(), sizeof(char), MessageStr.size(), stderr); | 
|  | (void)Written; // If something went wrong, we deliberately just give up. | 
|  |  | 
|  | // If we reached here, we are failing ungracefully. Run the interrupt handlers | 
|  | // to make sure any special cleanups get done, in particular that we remove | 
|  | // files registered with RemoveFileOnSignal. | 
|  | llvm::sys::RunInterruptHandlers(); | 
|  |  | 
|  | exit(0); | 
|  | } | 
|  |  | 
|  | struct { | 
|  | const char *FlagName; | 
|  | bool FlagValue; | 
|  | } ConditionalBuildAttributes[] = { | 
|  | {"dump", BuildDefs::dump()}, | 
|  | {"llvm_cl", BuildDefs::llvmCl()}, | 
|  | {"llvm_ir", BuildDefs::llvmIr()}, | 
|  | {"llvm_ir_as_input", BuildDefs::llvmIrAsInput()}, | 
|  | {"minimal_build", BuildDefs::minimal()}, | 
|  | {"browser_mode", BuildDefs::browser()}}; | 
|  |  | 
|  | /// Dumps values of build attributes to Stream if Stream is non-null. | 
|  | void dumpBuildAttributes(Ostream &Str) { | 
|  | // List the supported targets. | 
|  | #define SUBZERO_TARGET(TARGET) Str << "target_" XSTRINGIFY(TARGET) "\n"; | 
|  | #include "SZTargets.def" | 
|  | const char *Prefix[2] = {"no", "allow"}; | 
|  | for (size_t i = 0; i < llvm::array_lengthof(ConditionalBuildAttributes); | 
|  | ++i) { | 
|  | const auto &A = ConditionalBuildAttributes[i]; | 
|  | Str << Prefix[A.FlagValue] << "_" << A.FlagName << "\n"; | 
|  | } | 
|  | Str << "revision_" << getSubzeroRevision() << "\n"; | 
|  | } | 
|  |  | 
|  | } // end of anonymous namespace | 
|  |  | 
|  | void CLCompileServer::run() { | 
|  | if (BuildDefs::dump()) { | 
|  | #ifdef PNACL_LLVM | 
|  | llvm::sys::PrintStackTraceOnErrorSignal(); | 
|  | #else  // !PNACL_LLVM | 
|  | llvm::sys::PrintStackTraceOnErrorSignal(argv[0]); | 
|  | #endif // !PNACL_LLVM | 
|  | } | 
|  | ClFlags::parseFlags(argc, argv); | 
|  | ClFlags &Flags = ClFlags::Flags; | 
|  | ClFlags::getParsedClFlags(Flags); | 
|  |  | 
|  | // Override report_fatal_error if we want to exit with 0 status. | 
|  | if (Flags.getAlwaysExitSuccess()) | 
|  | llvm::install_fatal_error_handler(reportFatalErrorThenExitSuccess, this); | 
|  |  | 
|  | std::error_code EC; | 
|  | std::unique_ptr<Ostream> Ls = makeStream(Flags.getLogFilename(), EC); | 
|  | if (EC) { | 
|  | llvm::report_fatal_error("Unable to open log file"); | 
|  | } | 
|  | Ls->SetUnbuffered(); | 
|  | Ice::LinuxMallocProfiling _(Flags.getNumTranslationThreads(), Ls.get()); | 
|  |  | 
|  | std::unique_ptr<Ostream> Os; | 
|  | std::unique_ptr<ELFStreamer> ELFStr; | 
|  | switch (Flags.getOutFileType()) { | 
|  | case FT_Elf: { | 
|  | if (Flags.getOutputFilename() == "-" && !Flags.getGenerateBuildAtts()) { | 
|  | *Ls << "Error: writing binary ELF to stdout is unsupported\n"; | 
|  | return transferErrorCode(getReturnValue(Ice::EC_Args)); | 
|  | } | 
|  | std::unique_ptr<llvm::raw_fd_ostream> FdOs(new llvm::raw_fd_ostream( | 
|  | Flags.getOutputFilename(), EC, llvm::sys::fs::F_None)); | 
|  | if (EC) { | 
|  | *Ls << "Failed to open output file: " << Flags.getOutputFilename() | 
|  | << ":\n" << EC.message() << "\n"; | 
|  | return transferErrorCode(getReturnValue(Ice::EC_Args)); | 
|  | } | 
|  | ELFStr.reset(new ELFFileStreamer(*FdOs.get())); | 
|  | Os.reset(FdOs.release()); | 
|  | // NaCl sets st_blksize to 0, and LLVM uses that to pick the default | 
|  | // preferred buffer size. Set to something non-zero. | 
|  | Os->SetBufferSize(1 << 14); | 
|  | } break; | 
|  | case FT_Asm: | 
|  | case FT_Iasm: { | 
|  | Os = makeStream(Flags.getOutputFilename(), EC); | 
|  | if (EC) { | 
|  | *Ls << "Failed to open output file: " << Flags.getOutputFilename() | 
|  | << ":\n" << EC.message() << "\n"; | 
|  | return transferErrorCode(getReturnValue(Ice::EC_Args)); | 
|  | } | 
|  | Os->SetUnbuffered(); | 
|  | } break; | 
|  | } | 
|  |  | 
|  | if (BuildDefs::minimal() && Flags.getBitcodeAsText()) | 
|  | llvm::report_fatal_error("Can't specify 'bitcode-as-text' flag in " | 
|  | "minimal build"); | 
|  |  | 
|  | std::string StrError; | 
|  | std::unique_ptr<llvm::DataStreamer> InputStream( | 
|  | (!BuildDefs::minimal() && Flags.getBitcodeAsText()) | 
|  | ? TextDataStreamer::create(Flags.getIRFilename(), &StrError) | 
|  | : llvm::getDataFileStreamer(Flags.getIRFilename(), &StrError)); | 
|  | if (!StrError.empty() || !InputStream) { | 
|  | llvm::SMDiagnostic Err(Flags.getIRFilename(), llvm::SourceMgr::DK_Error, | 
|  | StrError); | 
|  | Err.print(Flags.getAppName().c_str(), *Ls); | 
|  | return transferErrorCode(getReturnValue(Ice::EC_Bitcode)); | 
|  | } | 
|  |  | 
|  | if (Flags.getGenerateBuildAtts()) { | 
|  | dumpBuildAttributes(*Os.get()); | 
|  | return transferErrorCode(getReturnValue(Ice::EC_None)); | 
|  | } | 
|  |  | 
|  | Ctx.reset(new GlobalContext(Ls.get(), Os.get(), Ls.get(), ELFStr.get())); | 
|  |  | 
|  | if (!BuildDefs::minimal() && getFlags().getSanitizeAddresses()) { | 
|  | std::unique_ptr<Instrumentation> Instr(new ASanInstrumentation(Ctx.get())); | 
|  | Ctx->setInstrumentation(std::move(Instr)); | 
|  | } | 
|  |  | 
|  | if (getFlags().getNumTranslationThreads() != 0) { | 
|  | std::thread CompileThread([this, &Flags, &InputStream]() { | 
|  | Ctx->initParserThread(); | 
|  | getCompiler().run(Flags, *Ctx.get(), std::move(InputStream)); | 
|  | }); | 
|  | CompileThread.join(); | 
|  | } else { | 
|  | getCompiler().run(Flags, *Ctx.get(), std::move(InputStream)); | 
|  | } | 
|  | transferErrorCode( | 
|  | getReturnValue(static_cast<ErrorCodes>(Ctx->getErrorStatus()->value()))); | 
|  | Ctx->dumpConstantLookupCounts(); | 
|  | Ctx->dumpStrings(); | 
|  | } | 
|  |  | 
|  | } // end of namespace Ice |