1 //===- subzero/src/IceCompileServer.cpp - Compile server ------------------===//
3 // The Subzero Code Generator
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
11 /// \brief Defines the basic commandline-based compile server.
13 //===----------------------------------------------------------------------===//
15 #include "IceCompileServer.h"
17 #include "IceClFlags.h"
18 #include "IceELFStreamer.h"
19 #include "IceGlobalContext.h"
20 #include "LinuxMallocProfiling.h"
23 #pragma clang diagnostic push
24 #pragma clang diagnostic ignored "-Wunused-parameter"
27 #include "llvm/Bitcode/NaCl/NaClBitcodeMungeUtils.h"
28 #include "llvm/Support/FileSystem.h"
29 #include "llvm/Support/raw_os_ostream.h"
30 #include "llvm/Support/Signals.h"
31 #include "llvm/Support/SourceMgr.h"
32 #include "llvm/Support/StreamingMemoryObject.h"
35 #pragma clang diagnostic pop
47 // Define a SmallVector backed buffer as a data stream, so that it can hold the
48 // generated binary version of the textual bitcode in the input file.
49 class TextDataStreamer : public llvm::DataStreamer {
51 TextDataStreamer() = default;
52 ~TextDataStreamer() final = default;
53 static TextDataStreamer *create(const std::string &Filename,
55 size_t GetBytes(unsigned char *Buf, size_t Len) final;
58 llvm::SmallVector<char, 1024> BitcodeBuffer;
62 TextDataStreamer *TextDataStreamer::create(const std::string &Filename,
64 TextDataStreamer *Streamer = new TextDataStreamer();
65 llvm::raw_string_ostream ErrStrm(*Err);
66 if (std::error_code EC = llvm::readNaClRecordTextAndBuildBitcode(
67 Filename, Streamer->BitcodeBuffer, &ErrStrm)) {
68 ErrStrm << EC.message();
77 size_t TextDataStreamer::GetBytes(unsigned char *Buf, size_t Len) {
78 if (Cursor >= BitcodeBuffer.size())
80 size_t Remaining = BitcodeBuffer.size();
81 Len = std::min(Len, Remaining);
82 for (size_t i = 0; i < Len; ++i)
83 Buf[i] = BitcodeBuffer[Cursor + i];
88 std::unique_ptr<Ostream> makeStream(const std::string &Filename,
89 std::error_code &EC) {
90 if (Filename == "-") {
91 return std::unique_ptr<Ostream>(new llvm::raw_os_ostream(std::cout));
92 } else if (Filename == "/dev/stderr") {
93 return std::unique_ptr<Ostream>(new llvm::raw_os_ostream(std::cerr));
95 return std::unique_ptr<Ostream>(
96 new llvm::raw_fd_ostream(Filename, EC, llvm::sys::fs::F_None));
100 ErrorCodes getReturnValue(ErrorCodes Val) {
101 if (getFlags().getAlwaysExitSuccess())
106 // Reports fatal error message, and then exits with success status 0.
107 void reportFatalErrorThenExitSuccess(void *UserData, const std::string &Reason,
112 // Note: This code is (mostly) copied from llvm/lib/Support/ErrorHandling.cpp
114 // Blast the result out to stderr. We don't try hard to make sure this
115 // succeeds (e.g. handling EINTR) and we can't use errs() here because
116 // raw ostreams can call report_fatal_error.
117 llvm::SmallVector<char, 64> Buffer;
118 llvm::raw_svector_ostream OS(Buffer);
119 OS << "LLVM ERROR: " << Reason << "\n";
120 llvm::StringRef MessageStr = OS.str();
122 std::fwrite(MessageStr.data(), sizeof(char), MessageStr.size(), stderr);
123 (void)Written; // If something went wrong, we deliberately just give up.
125 // If we reached here, we are failing ungracefully. Run the interrupt handlers
126 // to make sure any special cleanups get done, in particular that we remove
127 // files registered with RemoveFileOnSignal.
128 llvm::sys::RunInterruptHandlers();
134 const char *FlagName;
136 } ConditionalBuildAttributes[] = {
137 {"dump", BuildDefs::dump()},
138 {"llvm_cl", BuildDefs::llvmCl()},
139 {"llvm_ir", BuildDefs::llvmIr()},
140 {"llvm_ir_as_input", BuildDefs::llvmIrAsInput()},
141 {"minimal_build", BuildDefs::minimal()},
142 {"browser_mode", BuildDefs::browser()}};
144 /// Dumps values of build attributes to Stream if Stream is non-null.
145 void dumpBuildAttributes(Ostream &Str) {
146 // List the supported targets.
147 #define SUBZERO_TARGET(TARGET) Str << "target_" #TARGET << "\n";
148 #include "SZTargets.def"
149 const char *Prefix[2] = {"no", "allow"};
150 for (size_t i = 0; i < llvm::array_lengthof(ConditionalBuildAttributes);
152 const auto &A = ConditionalBuildAttributes[i];
153 Str << Prefix[A.FlagValue] << "_" << A.FlagName << "\n";
157 } // end of anonymous namespace
159 void CLCompileServer::run() {
160 if (BuildDefs::dump()) {
161 llvm::sys::PrintStackTraceOnErrorSignal();
163 ClFlags::parseFlags(argc, argv);
164 ClFlags &Flags = ClFlags::Flags;
165 ClFlags::getParsedClFlags(Flags);
167 // Override report_fatal_error if we want to exit with 0 status.
168 if (Flags.getAlwaysExitSuccess())
169 llvm::install_fatal_error_handler(reportFatalErrorThenExitSuccess, this);
172 std::unique_ptr<Ostream> Ls = makeStream(Flags.getLogFilename(), EC);
174 llvm::report_fatal_error("Unable to open log file");
177 Ice::LinuxMallocProfiling _(Flags.getNumTranslationThreads(), Ls.get());
179 std::unique_ptr<Ostream> Os;
180 std::unique_ptr<ELFStreamer> ELFStr;
181 switch (Flags.getOutFileType()) {
183 if (Flags.getOutputFilename() == "-" && !Flags.getGenerateBuildAtts()) {
184 *Ls << "Error: writing binary ELF to stdout is unsupported\n";
185 return transferErrorCode(getReturnValue(Ice::EC_Args));
187 std::unique_ptr<llvm::raw_fd_ostream> FdOs(new llvm::raw_fd_ostream(
188 Flags.getOutputFilename(), EC, llvm::sys::fs::F_None));
190 *Ls << "Failed to open output file: " << Flags.getOutputFilename()
191 << ":\n" << EC.message() << "\n";
192 return transferErrorCode(getReturnValue(Ice::EC_Args));
194 ELFStr.reset(new ELFStreamer(*FdOs.get()));
195 Os.reset(FdOs.release());
196 // NaCl sets st_blksize to 0, and LLVM uses that to pick the default
197 // preferred buffer size. Set to something non-zero.
198 Os->SetBufferSize(1 << 14);
202 Os = makeStream(Flags.getOutputFilename(), EC);
204 *Ls << "Failed to open output file: " << Flags.getOutputFilename()
205 << ":\n" << EC.message() << "\n";
206 return transferErrorCode(getReturnValue(Ice::EC_Args));
212 if (BuildDefs::minimal() && Flags.getBitcodeAsText())
213 llvm::report_fatal_error("Can't specify 'bitcode-as-text' flag in "
216 std::string StrError;
217 std::unique_ptr<llvm::DataStreamer> InputStream(
218 (!BuildDefs::minimal() && Flags.getBitcodeAsText())
219 ? TextDataStreamer::create(Flags.getIRFilename(), &StrError)
220 : llvm::getDataFileStreamer(Flags.getIRFilename(), &StrError));
221 if (!StrError.empty() || !InputStream) {
222 llvm::SMDiagnostic Err(Flags.getIRFilename(), llvm::SourceMgr::DK_Error,
224 Err.print(Flags.getAppName().c_str(), *Ls);
225 return transferErrorCode(getReturnValue(Ice::EC_Bitcode));
228 if (Flags.getGenerateBuildAtts()) {
229 dumpBuildAttributes(*Os.get());
230 return transferErrorCode(getReturnValue(Ice::EC_None));
233 Ctx.reset(new GlobalContext(Ls.get(), Os.get(), Ls.get(), ELFStr.get()));
234 if (getFlags().getNumTranslationThreads() != 0) {
235 std::thread CompileThread([this, &Flags, &InputStream]() {
236 Ctx->initParserThread();
237 getCompiler().run(Flags, *Ctx.get(), std::move(InputStream));
239 CompileThread.join();
241 getCompiler().run(Flags, *Ctx.get(), std::move(InputStream));
244 getReturnValue(static_cast<ErrorCodes>(Ctx->getErrorStatus()->value())));
245 Ctx->dumpConstantLookupCounts();
249 } // end of namespace Ice