Home | History | Annotate | Download | only in src
      1 //===- subzero/src/IceCompiler.cpp - Driver for bitcode translation -------===//
      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 a driver for translating PNaCl bitcode into native code.
     12 ///
     13 /// The driver can either directly parse the binary bitcode file, or use LLVM
     14 /// routines to parse a textual bitcode file into LLVM IR and then convert LLVM
     15 /// IR into ICE. In either case, the high-level ICE is then compiled down to
     16 /// native code, as either an ELF object file or a textual asm file.
     17 ///
     18 //===----------------------------------------------------------------------===//
     19 
     20 #include "IceCompiler.h"
     21 
     22 #include "IceBuildDefs.h"
     23 #include "IceCfg.h"
     24 #include "IceClFlags.h"
     25 #include "IceConverter.h"
     26 #include "IceELFObjectWriter.h"
     27 #include "PNaClTranslator.h"
     28 #include "WasmTranslator.h"
     29 
     30 #ifdef __clang__
     31 #pragma clang diagnostic push
     32 #pragma clang diagnostic ignored "-Wunused-parameter"
     33 #endif // __clang__
     34 
     35 #include "llvm/ADT/STLExtras.h"
     36 #include "llvm/Bitcode/NaCl/NaClReaderWriter.h"
     37 #include "llvm/IR/LLVMContext.h"
     38 #include "llvm/IR/Module.h"
     39 #include "llvm/IRReader/IRReader.h"
     40 #include "llvm/Support/SourceMgr.h"
     41 #include "llvm/Support/StreamingMemoryObject.h"
     42 
     43 #ifdef __clang__
     44 #pragma clang diagnostic pop
     45 #endif // __clang__
     46 
     47 #include <regex>
     48 
     49 namespace Ice {
     50 
     51 namespace {
     52 
     53 bool llvmIRInput(const std::string &Filename) {
     54   return BuildDefs::llvmIrAsInput() &&
     55          std::regex_match(Filename, std::regex(".*\\.ll"));
     56 }
     57 
     58 bool wasmInput(const std::string &Filename) {
     59   return BuildDefs::wasm() &&
     60          std::regex_match(Filename, std::regex(".*\\.wasm"));
     61 }
     62 
     63 } // end of anonymous namespace
     64 
     65 void Compiler::run(const Ice::ClFlags &Flags, GlobalContext &Ctx,
     66                    std::unique_ptr<llvm::DataStreamer> &&InputStream) {
     67   // The Minimal build (specifically, when dump()/emit() are not implemented)
     68   // allows only --filetype=obj. Check here to avoid cryptic error messages
     69   // downstream.
     70   if (!BuildDefs::dump() && getFlags().getOutFileType() != FT_Elf) {
     71     Ctx.getStrError()
     72         << "Error: only --filetype=obj is supported in this build.\n";
     73     Ctx.getErrorStatus()->assign(EC_Args);
     74     return;
     75   }
     76 
     77   TimerMarker T(Ice::TimerStack::TT_szmain, &Ctx);
     78 
     79   Ctx.emitFileHeader();
     80   Ctx.startWorkerThreads();
     81 
     82   std::unique_ptr<Translator> Translator;
     83   const std::string IRFilename = Flags.getIRFilename();
     84   const bool BuildOnRead = Flags.getBuildOnRead() && !llvmIRInput(IRFilename) &&
     85                            !wasmInput(IRFilename);
     86   const bool WasmBuildOnRead = Flags.getBuildOnRead() && wasmInput(IRFilename);
     87   if (BuildOnRead) {
     88     std::unique_ptr<PNaClTranslator> PTranslator(new PNaClTranslator(&Ctx));
     89 #ifdef PNACL_LLVM
     90     std::unique_ptr<llvm::StreamingMemoryObject> MemObj(
     91         new llvm::StreamingMemoryObjectImpl(InputStream.release()));
     92 #else  // !PNACL_LLVM
     93     std::unique_ptr<llvm::StreamingMemoryObject> MemObj(
     94         new llvm::StreamingMemoryObject(std::move(InputStream)));
     95 #endif // !PNACL_LLVM
     96     PTranslator->translate(IRFilename, std::move(MemObj));
     97     Translator.reset(PTranslator.release());
     98   } else if (WasmBuildOnRead) {
     99     if (BuildDefs::wasm()) {
    100 #if !ALLOW_WASM
    101       assert(false && "wasm not allowed");
    102 #else
    103       std::unique_ptr<WasmTranslator> WTranslator(new WasmTranslator(&Ctx));
    104 
    105       WTranslator->translate(IRFilename, std::move(InputStream));
    106 
    107       Translator.reset(WTranslator.release());
    108 #endif // !ALLOW_WASM
    109     } else {
    110       Ctx.getStrError() << "WASM support not enabled\n";
    111       Ctx.getErrorStatus()->assign(EC_Args);
    112       return;
    113     }
    114   } else if (BuildDefs::llvmIr()) {
    115     if (BuildDefs::browser()) {
    116       Ctx.getStrError()
    117           << "non BuildOnRead is not supported w/ PNACL_BROWSER_TRANSLATOR\n";
    118       Ctx.getErrorStatus()->assign(EC_Args);
    119       Ctx.waitForWorkerThreads();
    120       return;
    121     }
    122     // Globals must be kept alive after lowering when converting from LLVM to
    123     // Ice.
    124     Ctx.setDisposeGlobalVariablesAfterLowering(false);
    125     // Parse the input LLVM IR file into a module.
    126     llvm::SMDiagnostic Err;
    127     TimerMarker T1(Ice::TimerStack::TT_parse, &Ctx);
    128 #ifdef PNACL_LLVM
    129     llvm::DiagnosticHandlerFunction DiagnosticHandler =
    130         Flags.getLLVMVerboseErrors()
    131             ? redirectNaClDiagnosticToStream(llvm::errs())
    132             : nullptr;
    133     std::unique_ptr<llvm::Module> Mod =
    134         NaClParseIRFile(IRFilename, Flags.getInputFileFormat(), Err,
    135                         llvm::getGlobalContext(), DiagnosticHandler);
    136 #else  // !PNACL_LLVM
    137     llvm::DiagnosticHandlerFunction DiagnosticHandler = nullptr;
    138     llvm::LLVMContext Context;
    139     std::unique_ptr<llvm::Module> Mod = parseIRFile(IRFilename, Err, Context);
    140 #endif // !PNACL_LLVM
    141     if (!Mod) {
    142       Err.print(Flags.getAppName().c_str(), llvm::errs());
    143       Ctx.getErrorStatus()->assign(EC_Bitcode);
    144       Ctx.waitForWorkerThreads();
    145       return;
    146     }
    147 
    148     std::unique_ptr<Converter> Converter(new class Converter(Mod.get(), &Ctx));
    149     Converter->convertToIce();
    150     Translator.reset(Converter.release());
    151   } else {
    152     Ctx.getStrError() << "Error: Build doesn't allow LLVM IR, "
    153                       << "--build-on-read=0 not allowed\n";
    154     Ctx.getErrorStatus()->assign(EC_Args);
    155     Ctx.waitForWorkerThreads();
    156     return;
    157   }
    158 
    159   Ctx.waitForWorkerThreads();
    160   if (Translator->getErrorStatus()) {
    161     Ctx.getErrorStatus()->assign(Translator->getErrorStatus().value());
    162   } else {
    163     Ctx.lowerGlobals("last");
    164     Ctx.lowerProfileData();
    165     Ctx.lowerConstants();
    166     Ctx.lowerJumpTables();
    167 
    168     if (getFlags().getOutFileType() == FT_Elf) {
    169       TimerMarker T1(Ice::TimerStack::TT_emitAsm, &Ctx);
    170       Ctx.getObjectWriter()->setUndefinedSyms(Ctx.getConstantExternSyms());
    171       Ctx.emitTargetRODataSections();
    172       Ctx.getObjectWriter()->writeNonUserSections();
    173     }
    174   }
    175 
    176   if (getFlags().getSubzeroTimingEnabled())
    177     Ctx.dumpTimers();
    178 
    179   if (getFlags().getTimeEachFunction()) {
    180     constexpr bool NoDumpCumulative = false;
    181     Ctx.dumpTimers(GlobalContext::TSK_Funcs, NoDumpCumulative);
    182   }
    183   Ctx.dumpStats();
    184 }
    185 
    186 } // end of namespace Ice
    187