OSDN Git Service

e700b1ee125674aecefa28ac0db77bbe87479675
[android-x86/external-swiftshader.git] / src / IceCompileServer.cpp
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 "IceClFlags.h"
18 #include "IceELFStreamer.h"
19 #include "IceGlobalContext.h"
20 #include "LinuxMallocProfiling.h"
21
22 #ifdef __clang__
23 #pragma clang diagnostic push
24 #pragma clang diagnostic ignored "-Wunused-parameter"
25 #endif // __clang__
26
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"
33
34 #ifdef __clang__
35 #pragma clang diagnostic pop
36 #endif // __clang__
37
38 #include <cstdio>
39 #include <fstream>
40 #include <iostream>
41 #include <thread>
42
43 namespace Ice {
44
45 namespace {
46
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 {
50 public:
51   TextDataStreamer() = default;
52   ~TextDataStreamer() final = default;
53   static TextDataStreamer *create(const std::string &Filename,
54                                   std::string *Err);
55   size_t GetBytes(unsigned char *Buf, size_t Len) final;
56
57 private:
58   llvm::SmallVector<char, 1024> BitcodeBuffer;
59   size_t Cursor = 0;
60 };
61
62 TextDataStreamer *TextDataStreamer::create(const std::string &Filename,
63                                            std::string *Err) {
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();
69     ErrStrm.flush();
70     delete Streamer;
71     return nullptr;
72   }
73   ErrStrm.flush();
74   return Streamer;
75 }
76
77 size_t TextDataStreamer::GetBytes(unsigned char *Buf, size_t Len) {
78   if (Cursor >= BitcodeBuffer.size())
79     return 0;
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];
84   Cursor += Len;
85   return Len;
86 }
87
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));
94   } else {
95     return std::unique_ptr<Ostream>(
96         new llvm::raw_fd_ostream(Filename, EC, llvm::sys::fs::F_None));
97   }
98 }
99
100 ErrorCodes getReturnValue(ErrorCodes Val) {
101   if (getFlags().getAlwaysExitSuccess())
102     return EC_None;
103   return Val;
104 }
105
106 // Reports fatal error message, and then exits with success status 0.
107 void reportFatalErrorThenExitSuccess(void *UserData, const std::string &Reason,
108                                      bool GenCrashDag) {
109   (void)UserData;
110   (void)GenCrashDag;
111
112   // Note: This code is (mostly) copied from llvm/lib/Support/ErrorHandling.cpp
113
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();
121   ssize_t Written =
122       std::fwrite(MessageStr.data(), sizeof(char), MessageStr.size(), stderr);
123   (void)Written; // If something went wrong, we deliberately just give up.
124
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();
129
130   exit(0);
131 }
132
133 struct {
134   const char *FlagName;
135   bool FlagValue;
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()}};
143
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);
151        ++i) {
152     const auto &A = ConditionalBuildAttributes[i];
153     Str << Prefix[A.FlagValue] << "_" << A.FlagName << "\n";
154   }
155 }
156
157 } // end of anonymous namespace
158
159 void CLCompileServer::run() {
160   if (BuildDefs::dump()) {
161     llvm::sys::PrintStackTraceOnErrorSignal();
162   }
163   ClFlags::parseFlags(argc, argv);
164   ClFlags &Flags = ClFlags::Flags;
165   ClFlags::getParsedClFlags(Flags);
166
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);
170
171   std::error_code EC;
172   std::unique_ptr<Ostream> Ls = makeStream(Flags.getLogFilename(), EC);
173   if (EC) {
174     llvm::report_fatal_error("Unable to open log file");
175   }
176   Ls->SetUnbuffered();
177   Ice::LinuxMallocProfiling _(Flags.getNumTranslationThreads(), Ls.get());
178
179   std::unique_ptr<Ostream> Os;
180   std::unique_ptr<ELFStreamer> ELFStr;
181   switch (Flags.getOutFileType()) {
182   case FT_Elf: {
183     if (Flags.getOutputFilename() == "-" && !Flags.getGenerateBuildAtts()) {
184       *Ls << "Error: writing binary ELF to stdout is unsupported\n";
185       return transferErrorCode(getReturnValue(Ice::EC_Args));
186     }
187     std::unique_ptr<llvm::raw_fd_ostream> FdOs(new llvm::raw_fd_ostream(
188         Flags.getOutputFilename(), EC, llvm::sys::fs::F_None));
189     if (EC) {
190       *Ls << "Failed to open output file: " << Flags.getOutputFilename()
191           << ":\n" << EC.message() << "\n";
192       return transferErrorCode(getReturnValue(Ice::EC_Args));
193     }
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);
199   } break;
200   case FT_Asm:
201   case FT_Iasm: {
202     Os = makeStream(Flags.getOutputFilename(), EC);
203     if (EC) {
204       *Ls << "Failed to open output file: " << Flags.getOutputFilename()
205           << ":\n" << EC.message() << "\n";
206       return transferErrorCode(getReturnValue(Ice::EC_Args));
207     }
208     Os->SetUnbuffered();
209   } break;
210   }
211
212   if (BuildDefs::minimal() && Flags.getBitcodeAsText())
213     llvm::report_fatal_error("Can't specify 'bitcode-as-text' flag in "
214                              "minimal build");
215
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,
223                            StrError);
224     Err.print(Flags.getAppName().c_str(), *Ls);
225     return transferErrorCode(getReturnValue(Ice::EC_Bitcode));
226   }
227
228   if (Flags.getGenerateBuildAtts()) {
229     dumpBuildAttributes(*Os.get());
230     return transferErrorCode(getReturnValue(Ice::EC_None));
231   }
232
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));
238     });
239     CompileThread.join();
240   } else {
241     getCompiler().run(Flags, *Ctx.get(), std::move(InputStream));
242   }
243   transferErrorCode(
244       getReturnValue(static_cast<ErrorCodes>(Ctx->getErrorStatus()->value())));
245   Ctx->dumpConstantLookupCounts();
246   Ctx->dumpStrings();
247 }
248
249 } // end of namespace Ice