//===- subzero/src/IceCompiler.cpp - Driver for bitcode translation -------===//
//
// The Subzero Code Generator
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief Defines a driver for translating PNaCl bitcode into native code.
///
/// The driver can either directly parse the binary bitcode file, or use LLVM
/// routines to parse a textual bitcode file into LLVM IR and then convert LLVM
/// IR into ICE. In either case, the high-level ICE is then compiled down to
/// native code, as either an ELF object file or a textual asm file.
///
//===----------------------------------------------------------------------===//
#include "IceCompiler.h"
#include "IceBuildDefs.h"
#include "IceCfg.h"
#include "IceClFlags.h"
#include "IceConverter.h"
#include "IceELFObjectWriter.h"
#include "PNaClTranslator.h"
#include "WasmTranslator.h"
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
#endif // __clang__
#include "llvm/ADT/STLExtras.h"
#include "llvm/Bitcode/NaCl/NaClReaderWriter.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IRReader/IRReader.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/StreamingMemoryObject.h"
#ifdef __clang__
#pragma clang diagnostic pop
#endif // __clang__
#include <regex>
namespace Ice {
namespace {
bool llvmIRInput(const std::string &Filename) {
return BuildDefs::llvmIrAsInput() &&
std::regex_match(Filename, std::regex(".*\\.ll"));
}
bool wasmInput(const std::string &Filename) {
return BuildDefs::wasm() &&
std::regex_match(Filename, std::regex(".*\\.wasm"));
}
} // end of anonymous namespace
void Compiler::run(const Ice::ClFlags &Flags, GlobalContext &Ctx,
std::unique_ptr<llvm::DataStreamer> &&InputStream) {
// The Minimal build (specifically, when dump()/emit() are not implemented)
// allows only --filetype=obj. Check here to avoid cryptic error messages
// downstream.
if (!BuildDefs::dump() && getFlags().getOutFileType() != FT_Elf) {
Ctx.getStrError()
<< "Error: only --filetype=obj is supported in this build.\n";
Ctx.getErrorStatus()->assign(EC_Args);
return;
}
TimerMarker T(Ice::TimerStack::TT_szmain, &Ctx);
Ctx.emitFileHeader();
Ctx.startWorkerThreads();
std::unique_ptr<Translator> Translator;
const std::string IRFilename = Flags.getIRFilename();
const bool BuildOnRead = Flags.getBuildOnRead() && !llvmIRInput(IRFilename) &&
!wasmInput(IRFilename);
const bool WasmBuildOnRead = Flags.getBuildOnRead() && wasmInput(IRFilename);
if (BuildOnRead) {
std::unique_ptr<PNaClTranslator> PTranslator(new PNaClTranslator(&Ctx));
#ifdef PNACL_LLVM
std::unique_ptr<llvm::StreamingMemoryObject> MemObj(
new llvm::StreamingMemoryObjectImpl(InputStream.release()));
#else // !PNACL_LLVM
std::unique_ptr<llvm::StreamingMemoryObject> MemObj(
new llvm::StreamingMemoryObject(std::move(InputStream)));
#endif // !PNACL_LLVM
PTranslator->translate(IRFilename, std::move(MemObj));
Translator.reset(PTranslator.release());
} else if (WasmBuildOnRead) {
if (BuildDefs::wasm()) {
#if !ALLOW_WASM
assert(false && "wasm not allowed");
#else
std::unique_ptr<WasmTranslator> WTranslator(new WasmTranslator(&Ctx));
WTranslator->translate(IRFilename, std::move(InputStream));
Translator.reset(WTranslator.release());
#endif // !ALLOW_WASM
} else {
Ctx.getStrError() << "WASM support not enabled\n";
Ctx.getErrorStatus()->assign(EC_Args);
return;
}
} else if (BuildDefs::llvmIr()) {
if (BuildDefs::browser()) {
Ctx.getStrError()
<< "non BuildOnRead is not supported w/ PNACL_BROWSER_TRANSLATOR\n";
Ctx.getErrorStatus()->assign(EC_Args);
Ctx.waitForWorkerThreads();
return;
}
// Globals must be kept alive after lowering when converting from LLVM to
// Ice.
Ctx.setDisposeGlobalVariablesAfterLowering(false);
// Parse the input LLVM IR file into a module.
llvm::SMDiagnostic Err;
TimerMarker T1(Ice::TimerStack::TT_parse, &Ctx);
#ifdef PNACL_LLVM
llvm::DiagnosticHandlerFunction DiagnosticHandler =
Flags.getLLVMVerboseErrors()
? redirectNaClDiagnosticToStream(llvm::errs())
: nullptr;
std::unique_ptr<llvm::Module> Mod =
NaClParseIRFile(IRFilename, Flags.getInputFileFormat(), Err,
llvm::getGlobalContext(), DiagnosticHandler);
#else // !PNACL_LLVM
llvm::DiagnosticHandlerFunction DiagnosticHandler = nullptr;
llvm::LLVMContext Context;
std::unique_ptr<llvm::Module> Mod = parseIRFile(IRFilename, Err, Context);
#endif // !PNACL_LLVM
if (!Mod) {
Err.print(Flags.getAppName().c_str(), llvm::errs());
Ctx.getErrorStatus()->assign(EC_Bitcode);
Ctx.waitForWorkerThreads();
return;
}
std::unique_ptr<Converter> Converter(new class Converter(Mod.get(), &Ctx));
Converter->convertToIce();
Translator.reset(Converter.release());
} else {
Ctx.getStrError() << "Error: Build doesn't allow LLVM IR, "
<< "--build-on-read=0 not allowed\n";
Ctx.getErrorStatus()->assign(EC_Args);
Ctx.waitForWorkerThreads();
return;
}
Ctx.waitForWorkerThreads();
if (Translator->getErrorStatus()) {
Ctx.getErrorStatus()->assign(Translator->getErrorStatus().value());
} else {
Ctx.lowerGlobals("last");
Ctx.lowerProfileData();
Ctx.lowerConstants();
Ctx.lowerJumpTables();
if (getFlags().getOutFileType() == FT_Elf) {
TimerMarker T1(Ice::TimerStack::TT_emitAsm, &Ctx);
Ctx.getObjectWriter()->setUndefinedSyms(Ctx.getConstantExternSyms());
Ctx.emitTargetRODataSections();
Ctx.getObjectWriter()->writeNonUserSections();
}
}
if (getFlags().getSubzeroTimingEnabled())
Ctx.dumpTimers();
if (getFlags().getTimeEachFunction()) {
constexpr bool NoDumpCumulative = false;
Ctx.dumpTimers(GlobalContext::TSK_Funcs, NoDumpCumulative);
}
Ctx.dumpStats();
}
} // end of namespace Ice