IceCompileServer.cpp revision 57e126899b20c65ff3ea23a3b7d7a67ab30b99dc
144c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung//===- subzero/src/IceCompileServer.cpp - Compile server ------------------===//
244c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung//
344c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung//                        The Subzero Code Generator
444c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung//
544c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung// This file is distributed under the University of Illinois Open Source
644c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung// License. See LICENSE.TXT for details.
744c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung//
844c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung//===----------------------------------------------------------------------===//
99612d32c7e5eb2cb403686ef31172d42e075e460Andrew Scull///
109612d32c7e5eb2cb403686ef31172d42e075e460Andrew Scull/// \file
119612d32c7e5eb2cb403686ef31172d42e075e460Andrew Scull/// This file defines the basic commandline-based compile server.
129612d32c7e5eb2cb403686ef31172d42e075e460Andrew Scull///
1344c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung//===----------------------------------------------------------------------===//
1444c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung
1567f8de9adf6439881a00d8e0f081918436c71f62John Porto#include "IceCompileServer.h"
1644c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung
1767f8de9adf6439881a00d8e0f081918436c71f62John Porto#include "IceClFlags.h"
1867f8de9adf6439881a00d8e0f081918436c71f62John Porto#include "IceClFlagsExtra.h"
1967f8de9adf6439881a00d8e0f081918436c71f62John Porto#include "IceELFStreamer.h"
2067f8de9adf6439881a00d8e0f081918436c71f62John Porto#include "IceGlobalContext.h"
2198da96678bc2705d4a37e17b87bbb3c031be9ae0Jim Stichnoth
2298da96678bc2705d4a37e17b87bbb3c031be9ae0Jim Stichnoth#pragma clang diagnostic push
2398da96678bc2705d4a37e17b87bbb3c031be9ae0Jim Stichnoth#pragma clang diagnostic ignored "-Wunused-parameter"
246f9ba115f546d0e3446f08bd6f4477d2b5645bd5Karl Schimpf#include "llvm/Bitcode/NaCl/NaClBitcodeMungeUtils.h"
2544c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung#include "llvm/Support/FileSystem.h"
2644c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung#include "llvm/Support/raw_os_ostream.h"
27b2d5084c573ef5de15eb0e87bdde5dfba59e524aJan Voung#include "llvm/Support/Signals.h"
2844c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung#include "llvm/Support/SourceMgr.h"
2944c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung#include "llvm/Support/StreamingMemoryObject.h"
3098da96678bc2705d4a37e17b87bbb3c031be9ae0Jim Stichnoth#pragma clang diagnostic pop
3144c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung
3267f8de9adf6439881a00d8e0f081918436c71f62John Porto#include <fstream>
3367f8de9adf6439881a00d8e0f081918436c71f62John Porto#include <iostream>
3467f8de9adf6439881a00d8e0f081918436c71f62John Porto#include <thread>
3544c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung
3644c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voungnamespace Ice {
3744c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung
3844c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voungnamespace {
3944c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung
4057e126899b20c65ff3ea23a3b7d7a67ab30b99dcAndrew Scull// Define a SmallVector backed buffer as a data stream, so that it can hold the
4157e126899b20c65ff3ea23a3b7d7a67ab30b99dcAndrew Scull// generated binary version of the textual bitcode in the input file.
426f9ba115f546d0e3446f08bd6f4477d2b5645bd5Karl Schimpfclass TextDataStreamer : public llvm::DataStreamer {
436f9ba115f546d0e3446f08bd6f4477d2b5645bd5Karl Schimpfpublic:
446f9ba115f546d0e3446f08bd6f4477d2b5645bd5Karl Schimpf  TextDataStreamer() = default;
456f9ba115f546d0e3446f08bd6f4477d2b5645bd5Karl Schimpf  ~TextDataStreamer() final = default;
466f9ba115f546d0e3446f08bd6f4477d2b5645bd5Karl Schimpf  static TextDataStreamer *create(const IceString &Filename, std::string *Err);
476f9ba115f546d0e3446f08bd6f4477d2b5645bd5Karl Schimpf  size_t GetBytes(unsigned char *Buf, size_t Len) final;
4820b71f5890ee8651983b126c5978594a01e0af96Jim Stichnoth
496f9ba115f546d0e3446f08bd6f4477d2b5645bd5Karl Schimpfprivate:
506f9ba115f546d0e3446f08bd6f4477d2b5645bd5Karl Schimpf  llvm::SmallVector<char, 1024> BitcodeBuffer;
516f9ba115f546d0e3446f08bd6f4477d2b5645bd5Karl Schimpf  size_t Cursor = 0;
526f9ba115f546d0e3446f08bd6f4477d2b5645bd5Karl Schimpf};
536f9ba115f546d0e3446f08bd6f4477d2b5645bd5Karl Schimpf
546f9ba115f546d0e3446f08bd6f4477d2b5645bd5Karl SchimpfTextDataStreamer *TextDataStreamer::create(const IceString &Filename,
556f9ba115f546d0e3446f08bd6f4477d2b5645bd5Karl Schimpf                                           std::string *Err) {
566f9ba115f546d0e3446f08bd6f4477d2b5645bd5Karl Schimpf  TextDataStreamer *Streamer = new TextDataStreamer();
576f9ba115f546d0e3446f08bd6f4477d2b5645bd5Karl Schimpf  llvm::raw_string_ostream ErrStrm(*Err);
586f9ba115f546d0e3446f08bd6f4477d2b5645bd5Karl Schimpf  if (std::error_code EC = llvm::readNaClRecordTextAndBuildBitcode(
596f9ba115f546d0e3446f08bd6f4477d2b5645bd5Karl Schimpf          Filename, Streamer->BitcodeBuffer, &ErrStrm)) {
60cb6e95aac252a35c66705fb5e30d3c5e9ba4c1dcKarl Schimpf    ErrStrm << EC.message();
616f9ba115f546d0e3446f08bd6f4477d2b5645bd5Karl Schimpf    ErrStrm.flush();
626f9ba115f546d0e3446f08bd6f4477d2b5645bd5Karl Schimpf    delete Streamer;
636f9ba115f546d0e3446f08bd6f4477d2b5645bd5Karl Schimpf    return nullptr;
646f9ba115f546d0e3446f08bd6f4477d2b5645bd5Karl Schimpf  }
65cb6e95aac252a35c66705fb5e30d3c5e9ba4c1dcKarl Schimpf  ErrStrm.flush();
666f9ba115f546d0e3446f08bd6f4477d2b5645bd5Karl Schimpf  return Streamer;
676f9ba115f546d0e3446f08bd6f4477d2b5645bd5Karl Schimpf}
686f9ba115f546d0e3446f08bd6f4477d2b5645bd5Karl Schimpf
696f9ba115f546d0e3446f08bd6f4477d2b5645bd5Karl Schimpfsize_t TextDataStreamer::GetBytes(unsigned char *Buf, size_t Len) {
706f9ba115f546d0e3446f08bd6f4477d2b5645bd5Karl Schimpf  if (Cursor >= BitcodeBuffer.size())
716f9ba115f546d0e3446f08bd6f4477d2b5645bd5Karl Schimpf    return 0;
726f9ba115f546d0e3446f08bd6f4477d2b5645bd5Karl Schimpf  size_t Remaining = BitcodeBuffer.size();
736f9ba115f546d0e3446f08bd6f4477d2b5645bd5Karl Schimpf  Len = std::min(Len, Remaining);
746f9ba115f546d0e3446f08bd6f4477d2b5645bd5Karl Schimpf  for (size_t i = 0; i < Len; ++i)
756f9ba115f546d0e3446f08bd6f4477d2b5645bd5Karl Schimpf    Buf[i] = BitcodeBuffer[Cursor + i];
766f9ba115f546d0e3446f08bd6f4477d2b5645bd5Karl Schimpf  Cursor += Len;
776f9ba115f546d0e3446f08bd6f4477d2b5645bd5Karl Schimpf  return Len;
786f9ba115f546d0e3446f08bd6f4477d2b5645bd5Karl Schimpf}
796f9ba115f546d0e3446f08bd6f4477d2b5645bd5Karl Schimpf
80620ad732db0def93eee3928f9ebebe88b279f63dJim Stichnothstd::unique_ptr<Ostream> makeStream(const IceString &Filename,
81620ad732db0def93eee3928f9ebebe88b279f63dJim Stichnoth                                    std::error_code &EC) {
82620ad732db0def93eee3928f9ebebe88b279f63dJim Stichnoth  if (Filename == "-") {
8344c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung    return std::unique_ptr<Ostream>(new llvm::raw_os_ostream(std::cout));
84620ad732db0def93eee3928f9ebebe88b279f63dJim Stichnoth  } else {
85620ad732db0def93eee3928f9ebebe88b279f63dJim Stichnoth    return std::unique_ptr<Ostream>(
86620ad732db0def93eee3928f9ebebe88b279f63dJim Stichnoth        new llvm::raw_fd_ostream(Filename, EC, llvm::sys::fs::F_None));
8744c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung  }
8844c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung}
8944c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung
9044c3a8046f4c81f9b4476f8c3c72723b584c312dJan VoungErrorCodes getReturnValue(const Ice::ClFlagsExtra &Flags, ErrorCodes Val) {
9144c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung  if (Flags.getAlwaysExitSuccess())
9244c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung    return EC_None;
9344c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung  return Val;
9444c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung}
9544c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung
9644c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung} // end of anonymous namespace
9744c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung
9844c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voungvoid CLCompileServer::run() {
9920b71f5890ee8651983b126c5978594a01e0af96Jim Stichnoth  if (BuildDefs::dump()) {
100b2d5084c573ef5de15eb0e87bdde5dfba59e524aJan Voung    llvm::sys::PrintStackTraceOnErrorSignal();
101b2d5084c573ef5de15eb0e87bdde5dfba59e524aJan Voung  }
10244c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung  ClFlags::parseFlags(argc, argv);
10344c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung  ClFlags Flags;
10444c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung  ClFlagsExtra ExtraFlags;
10544c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung  ClFlags::getParsedClFlags(Flags);
10644c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung  ClFlags::getParsedClFlagsExtra(ExtraFlags);
10744c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung
108620ad732db0def93eee3928f9ebebe88b279f63dJim Stichnoth  std::error_code EC;
109620ad732db0def93eee3928f9ebebe88b279f63dJim Stichnoth  std::unique_ptr<Ostream> Ls = makeStream(ExtraFlags.getLogFilename(), EC);
110620ad732db0def93eee3928f9ebebe88b279f63dJim Stichnoth  if (EC) {
111620ad732db0def93eee3928f9ebebe88b279f63dJim Stichnoth    llvm::report_fatal_error("Unable to open log file");
112620ad732db0def93eee3928f9ebebe88b279f63dJim Stichnoth  }
11344c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung  Ls->SetUnbuffered();
11444c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung  std::unique_ptr<Ostream> Os;
11544c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung  std::unique_ptr<ELFStreamer> ELFStr;
11644c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung  switch (Flags.getOutFileType()) {
11744c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung  case FT_Elf: {
11844c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung    if (ExtraFlags.getOutputFilename() == "-") {
11944c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung      *Ls << "Error: writing binary ELF to stdout is unsupported\n";
12044c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung      return transferErrorCode(getReturnValue(ExtraFlags, Ice::EC_Args));
12144c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung    }
12244c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung    std::unique_ptr<llvm::raw_fd_ostream> FdOs(new llvm::raw_fd_ostream(
12344c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung        ExtraFlags.getOutputFilename(), EC, llvm::sys::fs::F_None));
12444c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung    if (EC) {
12544c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung      *Ls << "Failed to open output file: " << ExtraFlags.getOutputFilename()
12644c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung          << ":\n" << EC.message() << "\n";
12744c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung      return transferErrorCode(getReturnValue(ExtraFlags, Ice::EC_Args));
12844c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung    }
12944c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung    ELFStr.reset(new ELFStreamer(*FdOs.get()));
13044c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung    Os.reset(FdOs.release());
13157e126899b20c65ff3ea23a3b7d7a67ab30b99dcAndrew Scull    // NaCl sets st_blksize to 0, and LLVM uses that to pick the default
13257e126899b20c65ff3ea23a3b7d7a67ab30b99dcAndrew Scull    // preferred buffer size. Set to something non-zero.
13344c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung    Os->SetBufferSize(1 << 14);
13444c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung  } break;
13544c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung  case FT_Asm:
13644c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung  case FT_Iasm: {
137620ad732db0def93eee3928f9ebebe88b279f63dJim Stichnoth    Os = makeStream(ExtraFlags.getOutputFilename(), EC);
138620ad732db0def93eee3928f9ebebe88b279f63dJim Stichnoth    if (EC) {
139620ad732db0def93eee3928f9ebebe88b279f63dJim Stichnoth      *Ls << "Failed to open output file: " << ExtraFlags.getOutputFilename()
140620ad732db0def93eee3928f9ebebe88b279f63dJim Stichnoth          << ":\n" << EC.message() << "\n";
141620ad732db0def93eee3928f9ebebe88b279f63dJim Stichnoth      return transferErrorCode(getReturnValue(ExtraFlags, Ice::EC_Args));
142620ad732db0def93eee3928f9ebebe88b279f63dJim Stichnoth    }
14344c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung    Os->SetUnbuffered();
14444c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung  } break;
14544c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung  }
14644c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung
147cb6e95aac252a35c66705fb5e30d3c5e9ba4c1dcKarl Schimpf  if (BuildDefs::minimal() && ExtraFlags.getBitcodeAsText())
148cb6e95aac252a35c66705fb5e30d3c5e9ba4c1dcKarl Schimpf    llvm::report_fatal_error("Can't specify 'bitcode-as-text' flag in "
149cb6e95aac252a35c66705fb5e30d3c5e9ba4c1dcKarl Schimpf                             "minimal build");
150cb6e95aac252a35c66705fb5e30d3c5e9ba4c1dcKarl Schimpf
15144c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung  IceString StrError;
15244c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung  std::unique_ptr<llvm::DataStreamer> InputStream(
153cb6e95aac252a35c66705fb5e30d3c5e9ba4c1dcKarl Schimpf      (!BuildDefs::minimal() && ExtraFlags.getBitcodeAsText())
15420b71f5890ee8651983b126c5978594a01e0af96Jim Stichnoth          ? TextDataStreamer::create(ExtraFlags.getIRFilename(), &StrError)
15520b71f5890ee8651983b126c5978594a01e0af96Jim Stichnoth          : llvm::getDataFileStreamer(ExtraFlags.getIRFilename(), &StrError));
15644c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung  if (!StrError.empty() || !InputStream) {
15744c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung    llvm::SMDiagnostic Err(ExtraFlags.getIRFilename(),
15844c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung                           llvm::SourceMgr::DK_Error, StrError);
15944c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung    Err.print(ExtraFlags.getAppName().c_str(), *Ls);
16044c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung    return transferErrorCode(getReturnValue(ExtraFlags, Ice::EC_Bitcode));
16144c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung  }
16244c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung
163620ad732db0def93eee3928f9ebebe88b279f63dJim Stichnoth  Ctx.reset(
164620ad732db0def93eee3928f9ebebe88b279f63dJim Stichnoth      new GlobalContext(Ls.get(), Os.get(), Ls.get(), ELFStr.get(), Flags));
16544c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung  if (Ctx->getFlags().getNumTranslationThreads() != 0) {
16644c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung    std::thread CompileThread([this, &ExtraFlags, &InputStream]() {
16744c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung      Ctx->initParserThread();
16844c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung      getCompiler().run(ExtraFlags, *Ctx.get(), std::move(InputStream));
16944c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung    });
17044c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung    CompileThread.join();
17144c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung  } else {
17244c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung    getCompiler().run(ExtraFlags, *Ctx.get(), std::move(InputStream));
17344c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung  }
17444c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung  transferErrorCode(getReturnValue(
17544c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung      ExtraFlags, static_cast<ErrorCodes>(Ctx->getErrorStatus()->value())));
17644c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung}
17744c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung
17844c3a8046f4c81f9b4476f8c3c72723b584c312dJan Voung} // end of namespace Ice
179