blob: f4dacb85eb7492ca8695d393d65e67cf348737bb [file] [log] [blame]
Jan Voung44c3a802015-03-27 16:29:08 -07001//===- 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//===----------------------------------------------------------------------===//
Andrew Scull9612d322015-07-06 14:53:25 -07009///
10/// \file
Jim Stichnoth92a6e5b2015-12-02 16:52:44 -080011/// \brief Defines the basic commandline-based compile server.
Andrew Scull9612d322015-07-06 14:53:25 -070012///
Jan Voung44c3a802015-03-27 16:29:08 -070013//===----------------------------------------------------------------------===//
14
John Porto67f8de92015-06-25 10:14:17 -070015#include "IceCompileServer.h"
Jan Voung44c3a802015-03-27 16:29:08 -070016
Thomas Lively3f5cb6f2016-06-13 11:23:29 -070017#include "IceASanInstrumentation.h"
John Porto67f8de92015-06-25 10:14:17 -070018#include "IceClFlags.h"
John Porto67f8de92015-06-25 10:14:17 -070019#include "IceELFStreamer.h"
20#include "IceGlobalContext.h"
Jim Stichnoth54cf1a22016-08-08 14:15:00 -070021#include "IceRevision.h"
David Sehr4c16ac02016-03-17 13:51:42 -070022#include "LinuxMallocProfiling.h"
Jim Stichnoth98da9662015-06-27 06:38:08 -070023
Jim Stichnothb0051df2016-01-13 11:39:15 -080024#ifdef __clang__
Jim Stichnoth98da9662015-06-27 06:38:08 -070025#pragma clang diagnostic push
26#pragma clang diagnostic ignored "-Wunused-parameter"
Jim Stichnothb0051df2016-01-13 11:39:15 -080027#endif // __clang__
28
Jim Stichnotha5b16ab2016-05-10 11:20:41 -070029#ifdef PNACL_LLVM
Karl Schimpf6f9ba112015-06-22 13:20:23 -070030#include "llvm/Bitcode/NaCl/NaClBitcodeMungeUtils.h"
Jim Stichnotha5b16ab2016-05-10 11:20:41 -070031#endif // PNACL_LLVM
Jan Voung44c3a802015-03-27 16:29:08 -070032#include "llvm/Support/FileSystem.h"
33#include "llvm/Support/raw_os_ostream.h"
Jan Voungb2d50842015-05-12 09:53:50 -070034#include "llvm/Support/Signals.h"
Jan Voung44c3a802015-03-27 16:29:08 -070035#include "llvm/Support/SourceMgr.h"
36#include "llvm/Support/StreamingMemoryObject.h"
Jim Stichnothb0051df2016-01-13 11:39:15 -080037
38#ifdef __clang__
Jim Stichnoth98da9662015-06-27 06:38:08 -070039#pragma clang diagnostic pop
Jim Stichnothb0051df2016-01-13 11:39:15 -080040#endif // __clang__
Jan Voung44c3a802015-03-27 16:29:08 -070041
Karl Schimpf7e64eaa2015-10-02 10:49:49 -070042#include <cstdio>
John Porto67f8de92015-06-25 10:14:17 -070043#include <fstream>
44#include <iostream>
45#include <thread>
Jan Voung44c3a802015-03-27 16:29:08 -070046
47namespace Ice {
48
49namespace {
50
Andrew Scull57e12682015-09-16 11:30:19 -070051// 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.
Karl Schimpf6f9ba112015-06-22 13:20:23 -070053class TextDataStreamer : public llvm::DataStreamer {
54public:
55 TextDataStreamer() = default;
56 ~TextDataStreamer() final = default;
Jim Stichnothf5fdd232016-05-09 12:24:36 -070057#ifdef PNACL_LLVM
58 using CreateType = TextDataStreamer *;
Jim Stichnotha5b16ab2016-05-10 11:20:41 -070059#else // !PNACL_LLVM
Jim Stichnothf5fdd232016-05-09 12:24:36 -070060 using CreateType = std::unique_ptr<TextDataStreamer>;
61#endif // !PNACL_LLVM
Jim Stichnotha5b16ab2016-05-10 11:20:41 -070062 static CreateType create(const std::string &Filename, std::string *Err);
Karl Schimpf6f9ba112015-06-22 13:20:23 -070063 size_t GetBytes(unsigned char *Buf, size_t Len) final;
Jim Stichnoth20b71f52015-06-24 15:52:24 -070064
Karl Schimpf6f9ba112015-06-22 13:20:23 -070065private:
66 llvm::SmallVector<char, 1024> BitcodeBuffer;
67 size_t Cursor = 0;
68};
69
Jim Stichnotha5b16ab2016-05-10 11:20:41 -070070TextDataStreamer::CreateType
71TextDataStreamer::create(const std::string &Filename, std::string *Err) {
Jim Stichnothf5fdd232016-05-09 12:24:36 -070072#ifdef PNACL_LLVM
Karl Schimpf6f9ba112015-06-22 13:20:23 -070073 TextDataStreamer *Streamer = new TextDataStreamer();
74 llvm::raw_string_ostream ErrStrm(*Err);
75 if (std::error_code EC = llvm::readNaClRecordTextAndBuildBitcode(
76 Filename, Streamer->BitcodeBuffer, &ErrStrm)) {
Karl Schimpfcb6e95a2015-07-23 09:10:03 -070077 ErrStrm << EC.message();
Karl Schimpf6f9ba112015-06-22 13:20:23 -070078 ErrStrm.flush();
79 delete Streamer;
80 return nullptr;
81 }
Karl Schimpfcb6e95a2015-07-23 09:10:03 -070082 ErrStrm.flush();
Karl Schimpf6f9ba112015-06-22 13:20:23 -070083 return Streamer;
Jim Stichnotha5b16ab2016-05-10 11:20:41 -070084#else // !PNACL_LLVM
Jim Stichnothf5fdd232016-05-09 12:24:36 -070085 return CreateType();
86#endif // !PNACL_LLVM
Karl Schimpf6f9ba112015-06-22 13:20:23 -070087}
88
89size_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
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700100std::unique_ptr<Ostream> makeStream(const std::string &Filename,
Jim Stichnoth620ad732015-04-28 14:12:20 -0700101 std::error_code &EC) {
102 if (Filename == "-") {
Jan Voung44c3a802015-03-27 16:29:08 -0700103 return std::unique_ptr<Ostream>(new llvm::raw_os_ostream(std::cout));
Jim Stichnothfd07ad02016-04-20 10:12:46 -0700104 } else if (Filename == "/dev/stderr") {
105 return std::unique_ptr<Ostream>(new llvm::raw_os_ostream(std::cerr));
Jim Stichnoth620ad732015-04-28 14:12:20 -0700106 } else {
107 return std::unique_ptr<Ostream>(
108 new llvm::raw_fd_ostream(Filename, EC, llvm::sys::fs::F_None));
Jan Voung44c3a802015-03-27 16:29:08 -0700109 }
110}
111
Jim Stichnoth98ba0062016-03-07 09:26:22 -0800112ErrorCodes getReturnValue(ErrorCodes Val) {
Karl Schimpfd4699942016-04-02 09:55:31 -0700113 if (getFlags().getAlwaysExitSuccess())
Jan Voung44c3a802015-03-27 16:29:08 -0700114 return EC_None;
115 return Val;
116}
117
Karl Schimpfdb2fd9c2015-09-30 15:02:05 -0700118// Reports fatal error message, and then exits with success status 0.
Jim Stichnoth48e3ae52015-10-01 13:33:35 -0700119void reportFatalErrorThenExitSuccess(void *UserData, const std::string &Reason,
Karl Schimpfdb2fd9c2015-09-30 15:02:05 -0700120 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();
Karl Schimpf4e6ea832015-10-02 12:42:47 -0700133 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.
Karl Schimpfdb2fd9c2015-09-30 15:02:05 -0700136
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
Jim Stichnoth686f35e2016-01-13 13:48:46 -0800145struct {
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.
157void dumpBuildAttributes(Ostream &Str) {
158// List the supported targets.
Jim Stichnoth84ea9a72016-09-09 09:33:07 -0700159#define SUBZERO_TARGET(TARGET) Str << "target_" XSTRINGIFY(TARGET) "\n";
Jim Stichnoth999a22f2016-03-12 10:22:53 -0800160#include "SZTargets.def"
Jim Stichnoth686f35e2016-01-13 13:48:46 -0800161 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 }
Jim Stichnoth54cf1a22016-08-08 14:15:00 -0700167 Str << "revision_" << getSubzeroRevision() << "\n";
Jim Stichnoth686f35e2016-01-13 13:48:46 -0800168}
169
Jan Voung44c3a802015-03-27 16:29:08 -0700170} // end of anonymous namespace
171
172void CLCompileServer::run() {
Jim Stichnoth20b71f52015-06-24 15:52:24 -0700173 if (BuildDefs::dump()) {
Jim Stichnothefdf4122016-08-17 09:12:52 -0700174#ifdef PNACL_LLVM
Jan Voungb2d50842015-05-12 09:53:50 -0700175 llvm::sys::PrintStackTraceOnErrorSignal();
Jim Stichnothefdf4122016-08-17 09:12:52 -0700176#else // !PNACL_LLVM
177 llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
178#endif // !PNACL_LLVM
Jan Voungb2d50842015-05-12 09:53:50 -0700179 }
Jan Voung44c3a802015-03-27 16:29:08 -0700180 ClFlags::parseFlags(argc, argv);
Karl Schimpfd4699942016-04-02 09:55:31 -0700181 ClFlags &Flags = ClFlags::Flags;
Jan Voung44c3a802015-03-27 16:29:08 -0700182 ClFlags::getParsedClFlags(Flags);
Jan Voung44c3a802015-03-27 16:29:08 -0700183
Karl Schimpfdb2fd9c2015-09-30 15:02:05 -0700184 // Override report_fatal_error if we want to exit with 0 status.
John Portoc5bc5cb2016-03-21 11:18:02 -0700185 if (Flags.getAlwaysExitSuccess())
Karl Schimpfdb2fd9c2015-09-30 15:02:05 -0700186 llvm::install_fatal_error_handler(reportFatalErrorThenExitSuccess, this);
187
Jim Stichnoth620ad732015-04-28 14:12:20 -0700188 std::error_code EC;
John Portoc5bc5cb2016-03-21 11:18:02 -0700189 std::unique_ptr<Ostream> Ls = makeStream(Flags.getLogFilename(), EC);
Jim Stichnoth620ad732015-04-28 14:12:20 -0700190 if (EC) {
191 llvm::report_fatal_error("Unable to open log file");
192 }
Jan Voung44c3a802015-03-27 16:29:08 -0700193 Ls->SetUnbuffered();
David Sehr4c16ac02016-03-17 13:51:42 -0700194 Ice::LinuxMallocProfiling _(Flags.getNumTranslationThreads(), Ls.get());
195
Jan Voung44c3a802015-03-27 16:29:08 -0700196 std::unique_ptr<Ostream> Os;
197 std::unique_ptr<ELFStreamer> ELFStr;
198 switch (Flags.getOutFileType()) {
199 case FT_Elf: {
John Portoc5bc5cb2016-03-21 11:18:02 -0700200 if (Flags.getOutputFilename() == "-" && !Flags.getGenerateBuildAtts()) {
Jan Voung44c3a802015-03-27 16:29:08 -0700201 *Ls << "Error: writing binary ELF to stdout is unsupported\n";
Jim Stichnoth98ba0062016-03-07 09:26:22 -0800202 return transferErrorCode(getReturnValue(Ice::EC_Args));
Jan Voung44c3a802015-03-27 16:29:08 -0700203 }
Jan Voung44c3a802015-03-27 16:29:08 -0700204 std::unique_ptr<llvm::raw_fd_ostream> FdOs(new llvm::raw_fd_ostream(
John Portoc5bc5cb2016-03-21 11:18:02 -0700205 Flags.getOutputFilename(), EC, llvm::sys::fs::F_None));
Jan Voung44c3a802015-03-27 16:29:08 -0700206 if (EC) {
John Portoc5bc5cb2016-03-21 11:18:02 -0700207 *Ls << "Failed to open output file: " << Flags.getOutputFilename()
Jan Voung44c3a802015-03-27 16:29:08 -0700208 << ":\n" << EC.message() << "\n";
Jim Stichnoth98ba0062016-03-07 09:26:22 -0800209 return transferErrorCode(getReturnValue(Ice::EC_Args));
Jan Voung44c3a802015-03-27 16:29:08 -0700210 }
Nicolas Capens3e376472016-09-13 11:35:57 -0400211 ELFStr.reset(new ELFFileStreamer(*FdOs.get()));
Jan Voung44c3a802015-03-27 16:29:08 -0700212 Os.reset(FdOs.release());
Andrew Scull57e12682015-09-16 11:30:19 -0700213 // NaCl sets st_blksize to 0, and LLVM uses that to pick the default
214 // preferred buffer size. Set to something non-zero.
Jan Voung44c3a802015-03-27 16:29:08 -0700215 Os->SetBufferSize(1 << 14);
216 } break;
217 case FT_Asm:
218 case FT_Iasm: {
John Portoc5bc5cb2016-03-21 11:18:02 -0700219 Os = makeStream(Flags.getOutputFilename(), EC);
Jim Stichnoth620ad732015-04-28 14:12:20 -0700220 if (EC) {
John Portoc5bc5cb2016-03-21 11:18:02 -0700221 *Ls << "Failed to open output file: " << Flags.getOutputFilename()
Jim Stichnoth620ad732015-04-28 14:12:20 -0700222 << ":\n" << EC.message() << "\n";
Jim Stichnoth98ba0062016-03-07 09:26:22 -0800223 return transferErrorCode(getReturnValue(Ice::EC_Args));
Jim Stichnoth620ad732015-04-28 14:12:20 -0700224 }
Jan Voung44c3a802015-03-27 16:29:08 -0700225 Os->SetUnbuffered();
226 } break;
227 }
228
John Portoc5bc5cb2016-03-21 11:18:02 -0700229 if (BuildDefs::minimal() && Flags.getBitcodeAsText())
Karl Schimpfcb6e95a2015-07-23 09:10:03 -0700230 llvm::report_fatal_error("Can't specify 'bitcode-as-text' flag in "
231 "minimal build");
232
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700233 std::string StrError;
Jan Voung44c3a802015-03-27 16:29:08 -0700234 std::unique_ptr<llvm::DataStreamer> InputStream(
John Portoc5bc5cb2016-03-21 11:18:02 -0700235 (!BuildDefs::minimal() && Flags.getBitcodeAsText())
236 ? TextDataStreamer::create(Flags.getIRFilename(), &StrError)
237 : llvm::getDataFileStreamer(Flags.getIRFilename(), &StrError));
Jan Voung44c3a802015-03-27 16:29:08 -0700238 if (!StrError.empty() || !InputStream) {
John Portoc5bc5cb2016-03-21 11:18:02 -0700239 llvm::SMDiagnostic Err(Flags.getIRFilename(), llvm::SourceMgr::DK_Error,
240 StrError);
241 Err.print(Flags.getAppName().c_str(), *Ls);
Jim Stichnoth98ba0062016-03-07 09:26:22 -0800242 return transferErrorCode(getReturnValue(Ice::EC_Bitcode));
Jan Voung44c3a802015-03-27 16:29:08 -0700243 }
244
John Portoc5bc5cb2016-03-21 11:18:02 -0700245 if (Flags.getGenerateBuildAtts()) {
Jim Stichnoth686f35e2016-01-13 13:48:46 -0800246 dumpBuildAttributes(*Os.get());
Jim Stichnoth98ba0062016-03-07 09:26:22 -0800247 return transferErrorCode(getReturnValue(Ice::EC_None));
Jim Stichnoth686f35e2016-01-13 13:48:46 -0800248 }
249
Jim Stichnoth98ba0062016-03-07 09:26:22 -0800250 Ctx.reset(new GlobalContext(Ls.get(), Os.get(), Ls.get(), ELFStr.get()));
Thomas Livelyaab70992016-06-07 13:54:59 -0700251
Thomas Livelyaab70992016-06-07 13:54:59 -0700252 if (!BuildDefs::minimal() && getFlags().getSanitizeAddresses()) {
Thomas Lively3f5cb6f2016-06-13 11:23:29 -0700253 std::unique_ptr<Instrumentation> Instr(new ASanInstrumentation(Ctx.get()));
Thomas Livelyaab70992016-06-07 13:54:59 -0700254 Ctx->setInstrumentation(std::move(Instr));
255 }
256
Karl Schimpfd4699942016-04-02 09:55:31 -0700257 if (getFlags().getNumTranslationThreads() != 0) {
John Portoc5bc5cb2016-03-21 11:18:02 -0700258 std::thread CompileThread([this, &Flags, &InputStream]() {
Jan Voung44c3a802015-03-27 16:29:08 -0700259 Ctx->initParserThread();
John Portoc5bc5cb2016-03-21 11:18:02 -0700260 getCompiler().run(Flags, *Ctx.get(), std::move(InputStream));
Jan Voung44c3a802015-03-27 16:29:08 -0700261 });
262 CompileThread.join();
263 } else {
John Portoc5bc5cb2016-03-21 11:18:02 -0700264 getCompiler().run(Flags, *Ctx.get(), std::move(InputStream));
Jan Voung44c3a802015-03-27 16:29:08 -0700265 }
Jim Stichnoth98ba0062016-03-07 09:26:22 -0800266 transferErrorCode(
267 getReturnValue(static_cast<ErrorCodes>(Ctx->getErrorStatus()->value())));
Jim Stichnoth9f9aa2c2016-03-07 08:25:24 -0800268 Ctx->dumpConstantLookupCounts();
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700269 Ctx->dumpStrings();
Jan Voung44c3a802015-03-27 16:29:08 -0700270}
271
272} // end of namespace Ice