• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- subzero/src/IceCompileServer.cpp - Compile server ------------------===//
2 //
3 //                        The Subzero Code Generator
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 ///
10 /// \file
11 /// \brief Defines the basic commandline-based compile server.
12 ///
13 //===----------------------------------------------------------------------===//
14 
15 #include "IceCompileServer.h"
16 
17 #include "IceASanInstrumentation.h"
18 #include "IceClFlags.h"
19 #include "IceELFStreamer.h"
20 #include "IceGlobalContext.h"
21 #include "IceRevision.h"
22 #include "LinuxMallocProfiling.h"
23 
24 #ifdef __clang__
25 #pragma clang diagnostic push
26 #pragma clang diagnostic ignored "-Wunused-parameter"
27 #endif // __clang__
28 
29 #ifdef PNACL_LLVM
30 #include "llvm/Bitcode/NaCl/NaClBitcodeMungeUtils.h"
31 #endif // PNACL_LLVM
32 #include "llvm/Support/FileSystem.h"
33 #include "llvm/Support/raw_os_ostream.h"
34 #include "llvm/Support/Signals.h"
35 #include "llvm/Support/SourceMgr.h"
36 #include "llvm/Support/StreamingMemoryObject.h"
37 
38 #ifdef __clang__
39 #pragma clang diagnostic pop
40 #endif // __clang__
41 
42 #include <cstdio>
43 #include <fstream>
44 #include <iostream>
45 #include <thread>
46 
47 namespace Ice {
48 
49 namespace {
50 
51 // Define a SmallVector backed buffer as a data stream, so that it can hold the
52 // generated binary version of the textual bitcode in the input file.
53 class TextDataStreamer : public llvm::DataStreamer {
54 public:
55   TextDataStreamer() = default;
56   ~TextDataStreamer() final = default;
57 #ifdef PNACL_LLVM
58   using CreateType = TextDataStreamer *;
59 #else  // !PNACL_LLVM
60   using CreateType = std::unique_ptr<TextDataStreamer>;
61 #endif // !PNACL_LLVM
62   static CreateType create(const std::string &Filename, std::string *Err);
63   size_t GetBytes(unsigned char *Buf, size_t Len) final;
64 
65 private:
66   llvm::SmallVector<char, 1024> BitcodeBuffer;
67   size_t Cursor = 0;
68 };
69 
70 TextDataStreamer::CreateType
create(const std::string & Filename,std::string * Err)71 TextDataStreamer::create(const std::string &Filename, std::string *Err) {
72 #ifdef PNACL_LLVM
73   TextDataStreamer *Streamer = new TextDataStreamer();
74   llvm::raw_string_ostream ErrStrm(*Err);
75   if (std::error_code EC = llvm::readNaClRecordTextAndBuildBitcode(
76           Filename, Streamer->BitcodeBuffer, &ErrStrm)) {
77     ErrStrm << EC.message();
78     ErrStrm.flush();
79     delete Streamer;
80     return nullptr;
81   }
82   ErrStrm.flush();
83   return Streamer;
84 #else  // !PNACL_LLVM
85   return CreateType();
86 #endif // !PNACL_LLVM
87 }
88 
GetBytes(unsigned char * Buf,size_t Len)89 size_t TextDataStreamer::GetBytes(unsigned char *Buf, size_t Len) {
90   if (Cursor >= BitcodeBuffer.size())
91     return 0;
92   size_t Remaining = BitcodeBuffer.size();
93   Len = std::min(Len, Remaining);
94   for (size_t i = 0; i < Len; ++i)
95     Buf[i] = BitcodeBuffer[Cursor + i];
96   Cursor += Len;
97   return Len;
98 }
99 
makeStream(const std::string & Filename,std::error_code & EC)100 std::unique_ptr<Ostream> makeStream(const std::string &Filename,
101                                     std::error_code &EC) {
102   if (Filename == "-") {
103     return std::unique_ptr<Ostream>(new llvm::raw_os_ostream(std::cout));
104   } else if (Filename == "/dev/stderr") {
105     return std::unique_ptr<Ostream>(new llvm::raw_os_ostream(std::cerr));
106   } else {
107     return std::unique_ptr<Ostream>(
108         new llvm::raw_fd_ostream(Filename, EC, llvm::sys::fs::F_None));
109   }
110 }
111 
getReturnValue(ErrorCodes Val)112 ErrorCodes getReturnValue(ErrorCodes Val) {
113   if (getFlags().getAlwaysExitSuccess())
114     return EC_None;
115   return Val;
116 }
117 
118 // Reports fatal error message, and then exits with success status 0.
reportFatalErrorThenExitSuccess(void * UserData,const std::string & Reason,bool GenCrashDag)119 void reportFatalErrorThenExitSuccess(void *UserData, const std::string &Reason,
120                                      bool GenCrashDag) {
121   (void)UserData;
122   (void)GenCrashDag;
123 
124   // Note: This code is (mostly) copied from llvm/lib/Support/ErrorHandling.cpp
125 
126   // Blast the result out to stderr.  We don't try hard to make sure this
127   // succeeds (e.g. handling EINTR) and we can't use errs() here because
128   // raw ostreams can call report_fatal_error.
129   llvm::SmallVector<char, 64> Buffer;
130   llvm::raw_svector_ostream OS(Buffer);
131   OS << "LLVM ERROR: " << Reason << "\n";
132   llvm::StringRef MessageStr = OS.str();
133   ssize_t Written =
134       std::fwrite(MessageStr.data(), sizeof(char), MessageStr.size(), stderr);
135   (void)Written; // If something went wrong, we deliberately just give up.
136 
137   // If we reached here, we are failing ungracefully. Run the interrupt handlers
138   // to make sure any special cleanups get done, in particular that we remove
139   // files registered with RemoveFileOnSignal.
140   llvm::sys::RunInterruptHandlers();
141 
142   exit(0);
143 }
144 
145 struct {
146   const char *FlagName;
147   bool FlagValue;
148 } ConditionalBuildAttributes[] = {
149     {"dump", BuildDefs::dump()},
150     {"llvm_cl", BuildDefs::llvmCl()},
151     {"llvm_ir", BuildDefs::llvmIr()},
152     {"llvm_ir_as_input", BuildDefs::llvmIrAsInput()},
153     {"minimal_build", BuildDefs::minimal()},
154     {"browser_mode", BuildDefs::browser()}};
155 
156 /// Dumps values of build attributes to Stream if Stream is non-null.
dumpBuildAttributes(Ostream & Str)157 void dumpBuildAttributes(Ostream &Str) {
158 // List the supported targets.
159 #define SUBZERO_TARGET(TARGET) Str << "target_" XSTRINGIFY(TARGET) "\n";
160 #include "SZTargets.def"
161   const char *Prefix[2] = {"no", "allow"};
162   for (size_t i = 0; i < llvm::array_lengthof(ConditionalBuildAttributes);
163        ++i) {
164     const auto &A = ConditionalBuildAttributes[i];
165     Str << Prefix[A.FlagValue] << "_" << A.FlagName << "\n";
166   }
167   Str << "revision_" << getSubzeroRevision() << "\n";
168 }
169 
170 } // end of anonymous namespace
171 
run()172 void CLCompileServer::run() {
173   if (BuildDefs::dump()) {
174 #ifdef PNACL_LLVM
175     llvm::sys::PrintStackTraceOnErrorSignal();
176 #else  // !PNACL_LLVM
177     llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
178 #endif // !PNACL_LLVM
179   }
180   ClFlags::parseFlags(argc, argv);
181   ClFlags &Flags = ClFlags::Flags;
182   ClFlags::getParsedClFlags(Flags);
183 
184   // Override report_fatal_error if we want to exit with 0 status.
185   if (Flags.getAlwaysExitSuccess())
186     llvm::install_fatal_error_handler(reportFatalErrorThenExitSuccess, this);
187 
188   std::error_code EC;
189   std::unique_ptr<Ostream> Ls = makeStream(Flags.getLogFilename(), EC);
190   if (EC) {
191     llvm::report_fatal_error("Unable to open log file");
192   }
193   Ls->SetUnbuffered();
194   Ice::LinuxMallocProfiling _(Flags.getNumTranslationThreads(), Ls.get());
195 
196   std::unique_ptr<Ostream> Os;
197   std::unique_ptr<ELFStreamer> ELFStr;
198   switch (Flags.getOutFileType()) {
199   case FT_Elf: {
200     if (Flags.getOutputFilename() == "-" && !Flags.getGenerateBuildAtts()) {
201       *Ls << "Error: writing binary ELF to stdout is unsupported\n";
202       return transferErrorCode(getReturnValue(Ice::EC_Args));
203     }
204     std::unique_ptr<llvm::raw_fd_ostream> FdOs(new llvm::raw_fd_ostream(
205         Flags.getOutputFilename(), EC, llvm::sys::fs::F_None));
206     if (EC) {
207       *Ls << "Failed to open output file: " << Flags.getOutputFilename()
208           << ":\n" << EC.message() << "\n";
209       return transferErrorCode(getReturnValue(Ice::EC_Args));
210     }
211     ELFStr.reset(new ELFFileStreamer(*FdOs.get()));
212     Os.reset(FdOs.release());
213     // NaCl sets st_blksize to 0, and LLVM uses that to pick the default
214     // preferred buffer size. Set to something non-zero.
215     Os->SetBufferSize(1 << 14);
216   } break;
217   case FT_Asm:
218   case FT_Iasm: {
219     Os = makeStream(Flags.getOutputFilename(), EC);
220     if (EC) {
221       *Ls << "Failed to open output file: " << Flags.getOutputFilename()
222           << ":\n" << EC.message() << "\n";
223       return transferErrorCode(getReturnValue(Ice::EC_Args));
224     }
225     Os->SetUnbuffered();
226   } break;
227   }
228 
229   if (BuildDefs::minimal() && Flags.getBitcodeAsText())
230     llvm::report_fatal_error("Can't specify 'bitcode-as-text' flag in "
231                              "minimal build");
232 
233   std::string StrError;
234   std::unique_ptr<llvm::DataStreamer> InputStream(
235       (!BuildDefs::minimal() && Flags.getBitcodeAsText())
236           ? TextDataStreamer::create(Flags.getIRFilename(), &StrError)
237           : llvm::getDataFileStreamer(Flags.getIRFilename(), &StrError));
238   if (!StrError.empty() || !InputStream) {
239     llvm::SMDiagnostic Err(Flags.getIRFilename(), llvm::SourceMgr::DK_Error,
240                            StrError);
241     Err.print(Flags.getAppName().c_str(), *Ls);
242     return transferErrorCode(getReturnValue(Ice::EC_Bitcode));
243   }
244 
245   if (Flags.getGenerateBuildAtts()) {
246     dumpBuildAttributes(*Os.get());
247     return transferErrorCode(getReturnValue(Ice::EC_None));
248   }
249 
250   Ctx.reset(new GlobalContext(Ls.get(), Os.get(), Ls.get(), ELFStr.get()));
251 
252   if (!BuildDefs::minimal() && getFlags().getSanitizeAddresses()) {
253     std::unique_ptr<Instrumentation> Instr(new ASanInstrumentation(Ctx.get()));
254     Ctx->setInstrumentation(std::move(Instr));
255   }
256 
257   if (getFlags().getNumTranslationThreads() != 0) {
258     std::thread CompileThread([this, &Flags, &InputStream]() {
259       Ctx->initParserThread();
260       getCompiler().run(Flags, *Ctx.get(), std::move(InputStream));
261     });
262     CompileThread.join();
263   } else {
264     getCompiler().run(Flags, *Ctx.get(), std::move(InputStream));
265   }
266   transferErrorCode(
267       getReturnValue(static_cast<ErrorCodes>(Ctx->getErrorStatus()->value())));
268   Ctx->dumpConstantLookupCounts();
269   Ctx->dumpStrings();
270 }
271 
272 } // end of namespace Ice
273