Index: tools/pnacl-llc/pnacl-llc.cpp |
diff --git a/tools/pnacl-llc/pnacl-llc.cpp b/tools/pnacl-llc/pnacl-llc.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..f18938aa742f4cacc41f427f52071895a4cf2688 |
--- /dev/null |
+++ b/tools/pnacl-llc/pnacl-llc.cpp |
@@ -0,0 +1,785 @@ |
+//===-- pnacl-llc.cpp - PNaCl-specific llc: pexe ---> nexe ---------------===// |
+// |
+// The LLVM Compiler Infrastructure |
+// |
+// This file is distributed under the University of Illinois Open Source |
+// License. See LICENSE.TXT for details. |
+// |
+//===----------------------------------------------------------------------===// |
+// |
+// pnacl-llc: the core of the PNaCl translator, compiling a pexe into a nexe. |
+// |
+//===----------------------------------------------------------------------===// |
+ |
+#include "llvm/ADT/Triple.h" |
+#include "llvm/Analysis/NaCl.h" |
+#include "llvm/Bitcode/NaCl/NaClReaderWriter.h" |
+#include "llvm/Bitcode/ReaderWriter.h" |
+#include "llvm/CodeGen/CommandFlags.h" |
+#include "llvm/CodeGen/LinkAllCodegenComponents.h" |
+#include "llvm/IR/DataLayout.h" |
+#include "llvm/IR/LLVMContext.h" |
+#include "llvm/IR/Module.h" |
+#include "llvm/IR/Verifier.h" |
+#include "llvm/IRReader/IRReader.h" |
+#include "llvm/MC/SubtargetFeature.h" |
+#include "llvm/Pass.h" |
+#include "llvm/PassManager.h" |
+#include "llvm/Support/CommandLine.h" |
+#include "llvm/Support/DataStream.h" |
+#include "llvm/Support/Debug.h" |
+#include "llvm/Support/ErrorHandling.h" |
+#include "llvm/Support/FileSystem.h" |
+#include "llvm/Support/FormattedStream.h" |
+#include "llvm/Support/Host.h" |
+#include "llvm/Support/ManagedStatic.h" |
+#include "llvm/Support/PrettyStackTrace.h" |
+#include "llvm/Support/Signals.h" |
+#include "llvm/Support/SourceMgr.h" |
+#include "llvm/Support/StreamingMemoryObject.h" |
+#include "llvm/Support/TargetRegistry.h" |
+#include "llvm/Support/TargetSelect.h" |
+#include "llvm/Support/ToolOutputFile.h" |
+#include "llvm/Target/TargetLibraryInfo.h" |
+#include "llvm/Target/TargetMachine.h" |
+#include "llvm/Target/TargetSubtargetInfo.h" |
+#include "llvm/Transforms/NaCl.h" |
+ |
+#include "ThreadedFunctionQueue.h" |
+#include "ThreadedStreamingCache.h" |
+ |
+#include <pthread.h> |
+#include <memory> |
+ |
+using namespace llvm; |
+ |
+// NOTE: When PNACL_BROWSER_TRANSLATOR is defined it means pnacl-llc is built |
+// as a sandboxed translator (from pnacl-llc.pexe to pnacl-llc.nexe). In this |
+// mode it uses SRPC operations instead of direct OS intefaces. |
+#if defined(PNACL_BROWSER_TRANSLATOR) |
+int srpc_main(int argc, char **argv); |
+int getObjectFileFD(unsigned index); |
+DataStreamer *getNaClBitcodeStreamer(); |
+ |
+fatal_error_handler_t getSRPCErrorHandler(); |
+#endif |
+ |
+cl::opt<NaClFileFormat> |
+InputFileFormat( |
+ "bitcode-format", |
+ cl::desc("Define format of input file:"), |
+ cl::values( |
+ clEnumValN(LLVMFormat, "llvm", "LLVM file (default)"), |
+ clEnumValN(PNaClFormat, "pnacl", "PNaCl bitcode file"), |
+ clEnumValEnd), |
+#if defined(PNACL_BROWSER_TRANSLATOR) |
+ cl::init(PNaClFormat) |
+#else |
+ cl::init(LLVMFormat) |
+#endif |
+ ); |
+ |
+// General options for llc. Other pass-specific options are specified |
+// within the corresponding llc passes, and target-specific options |
+// and back-end code generation options are specified with the target machine. |
+// |
+static cl::opt<std::string> |
+InputFilename(cl::Positional, cl::desc("<input bitcode>"), cl::init("-")); |
+ |
+static cl::opt<std::string> |
+OutputFilename("o", cl::desc("Output filename"), cl::value_desc("filename")); |
+ |
+// Using bitcode streaming allows compilation of one function at a time. This |
+// allows earlier functions to be compiled before later functions are read from |
+// the bitcode but of course means no whole-module optimizations. This means |
+// that Module passes that run should only touch globals/function declarations |
+// and not function bodies, otherwise the streaming and non-streaming code |
+// pathes wouldn't emit the same code for each function. For now, streaming is |
+// only supported for files and stdin. |
+static cl::opt<bool> |
+LazyBitcode("streaming-bitcode", |
+ cl::desc("Use lazy bitcode streaming for file inputs"), |
+ cl::init(false)); |
+ |
+static cl::opt<bool> |
+PNaClABIVerify("pnaclabi-verify", |
+ cl::desc("Verify PNaCl bitcode ABI before translating"), |
+ cl::init(false)); |
+static cl::opt<bool> |
+PNaClABIVerifyFatalErrors("pnaclabi-verify-fatal-errors", |
+ cl::desc("PNaCl ABI verification errors are fatal"), |
+ cl::init(false)); |
+ |
+ |
+static cl::opt<bool> |
+NoIntegratedAssembler("no-integrated-as", cl::Hidden, |
+ cl::desc("Disable integrated assembler")); |
+ |
+// Determine optimization level. |
+static cl::opt<char> |
+OptLevel("O", |
+ cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] " |
+ "(default = '-O2')"), |
+ cl::Prefix, |
+ cl::ZeroOrMore, |
+ cl::init(' ')); |
+ |
+static cl::opt<std::string> |
+UserDefinedTriple("mtriple", cl::desc("Set target triple")); |
+ |
+static cl::opt<bool> NoVerify("disable-verify", cl::Hidden, |
+ cl::desc("Do not verify input module")); |
+ |
+static cl::opt<bool> |
+ DisableSimplifyLibCalls("disable-simplify-libcalls", |
+ cl::desc("Disable simplify-libcalls")); |
+ |
+static cl::opt<unsigned> |
+SplitModuleCount("split-module", |
+ cl::desc("Split PNaCl module"), cl::init(1U)); |
+ |
+enum SplitModuleSchedulerKind { |
+ SplitModuleDynamic, |
+ SplitModuleStatic |
+}; |
+ |
+static cl::opt<SplitModuleSchedulerKind> |
+SplitModuleSched( |
+ "split-module-sched", |
+ cl::desc("Choose thread scheduler for split module compilation."), |
+ cl::values( |
+ clEnumValN(SplitModuleDynamic, "dynamic", |
+ "Dynamic thread scheduling (default)"), |
+ clEnumValN(SplitModuleStatic, "static", |
+ "Static thread scheduling"), |
+ clEnumValEnd), |
+ cl::init(SplitModuleDynamic)); |
+ |
+/// Compile the module provided to pnacl-llc. The file name for reading the |
+/// module and other options are taken from globals populated by command-line |
+/// option parsing. |
+static int compileModule(StringRef ProgramName); |
+ |
+#if !defined(PNACL_BROWSER_TRANSLATOR) |
+// GetFileNameRoot - Helper function to get the basename of a filename. |
+static std::string |
+GetFileNameRoot(StringRef InputFilename) { |
+ std::string IFN = InputFilename; |
+ std::string outputFilename; |
+ int Len = IFN.length(); |
+ if ((Len > 2) && |
+ IFN[Len-3] == '.' && |
+ ((IFN[Len-2] == 'b' && IFN[Len-1] == 'c') || |
+ (IFN[Len-2] == 'l' && IFN[Len-1] == 'l'))) { |
+ outputFilename = std::string(IFN.begin(), IFN.end()-3); // s/.bc/.s/ |
+ } else { |
+ outputFilename = IFN; |
+ } |
+ return outputFilename; |
+} |
+ |
+static tool_output_file *GetOutputStream(const char *TargetName, |
+ Triple::OSType OS, |
+ std::string Filename) { |
+ // If we don't yet have an output filename, make one. |
+ if (Filename.empty()) { |
+ if (InputFilename == "-") |
+ Filename = "-"; |
+ else { |
+ Filename = GetFileNameRoot(InputFilename); |
+ |
+ switch (FileType) { |
+ case TargetMachine::CGFT_AssemblyFile: |
+ if (TargetName[0] == 'c') { |
+ if (TargetName[1] == 0) |
+ Filename += ".cbe.c"; |
+ else if (TargetName[1] == 'p' && TargetName[2] == 'p') |
+ Filename += ".cpp"; |
+ else |
+ Filename += ".s"; |
+ } else |
+ Filename += ".s"; |
+ break; |
+ case TargetMachine::CGFT_ObjectFile: |
+ if (OS == Triple::Win32) |
+ Filename += ".obj"; |
+ else |
+ Filename += ".o"; |
+ break; |
+ case TargetMachine::CGFT_Null: |
+ Filename += ".null"; |
+ break; |
+ } |
+ } |
+ } |
+ |
+ // Decide if we need "binary" output. |
+ bool Binary = false; |
+ switch (FileType) { |
+ case TargetMachine::CGFT_AssemblyFile: |
+ break; |
+ case TargetMachine::CGFT_ObjectFile: |
+ case TargetMachine::CGFT_Null: |
+ Binary = true; |
+ break; |
+ } |
+ |
+ // Open the file. |
+ std::error_code EC; |
+ sys::fs::OpenFlags OpenFlags = sys::fs::F_None; |
+ if (!Binary) |
+ OpenFlags |= sys::fs::F_Text; |
+ tool_output_file *FDOut = new tool_output_file(Filename, EC, OpenFlags); |
+ if (EC) { |
+ errs() << EC.message() << '\n'; |
+ delete FDOut; |
+ return nullptr; |
+ } |
+ |
+ return FDOut; |
+} |
+#endif // !defined(PNACL_BROWSER_TRANSLATOR) |
+ |
+// main - Entry point for the llc compiler. |
+// |
+int llc_main(int argc, char **argv) { |
+ sys::PrintStackTraceOnErrorSignal(); |
+ PrettyStackTraceProgram X(argc, argv); |
+ |
+ // Enable debug stream buffering. |
+ EnableDebugBuffering = true; |
+ |
+ llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. |
+ |
+#if defined(PNACL_BROWSER_TRANSLATOR) |
+ install_fatal_error_handler(getSRPCErrorHandler(), nullptr); |
+#endif |
+ |
+ // Initialize targets first, so that --version shows registered targets. |
+ InitializeAllTargets(); |
+ InitializeAllTargetMCs(); |
+ InitializeAllAsmPrinters(); |
+#if !defined(PNACL_BROWSER_TRANSLATOR) |
+ // Prune asm parsing from sandboxed translator. |
+ // Do not prune "AsmPrinters" because that includes |
+ // the direct object emission. |
+ InitializeAllAsmParsers(); |
+#endif |
+ |
+ // Initialize codegen and IR passes used by pnacl-llc so that the -print-after, |
+ // -print-before, and -stop-after options work. |
+ PassRegistry *Registry = PassRegistry::getPassRegistry(); |
+ initializeCore(*Registry); |
+ initializeCodeGen(*Registry); |
+ initializeLoopStrengthReducePass(*Registry); |
+ initializeLowerIntrinsicsPass(*Registry); |
+ initializeUnreachableBlockElimPass(*Registry); |
+ |
+ // Register the target printer for --version. |
+ cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion); |
+ |
+ // Enable the PNaCl ABI verifier by default in sandboxed mode. |
+#if defined(PNACL_BROWSER_TRANSLATOR) |
+ PNaClABIVerify = true; |
+ PNaClABIVerifyFatalErrors = true; |
+#endif |
+ |
+ cl::ParseCommandLineOptions(argc, argv, "pnacl-llc\n"); |
+ |
+#if defined(PNACL_BROWSER_TRANSLATOR) |
+ // If the user explicitly requests LLVM format in sandboxed mode |
+ // (where the default is PNaCl format), they probably want debug |
+ // metadata enabled. |
+ if (InputFileFormat == LLVMFormat) { |
+ PNaClABIAllowDebugMetadata = true; |
+ } |
+#endif |
+ |
+ if (SplitModuleCount > 1) |
+ LLVMStartMultithreaded(); |
+ |
+ return compileModule(argv[0]); |
+} |
+ |
+static void CheckABIVerifyErrors(PNaClABIErrorReporter &Reporter, |
+ const Twine &Name) { |
+ if (PNaClABIVerify && Reporter.getErrorCount() > 0) { |
+ std::string errors; |
+ raw_string_ostream os(errors); |
+ os << (PNaClABIVerifyFatalErrors ? "ERROR: " : "WARNING: "); |
+ os << Name << " is not valid PNaCl bitcode:\n"; |
+ Reporter.printErrors(os); |
+ if (PNaClABIVerifyFatalErrors) { |
+ report_fatal_error(os.str()); |
+ } |
+ errs() << os.str(); |
+ } |
+ Reporter.reset(); |
+} |
+ |
+static std::unique_ptr<Module> getModule( |
+ StringRef ProgramName, LLVMContext &Context, |
+ StreamingMemoryObject *StreamingObject) { |
+ std::unique_ptr<Module> M; |
+ SMDiagnostic Err; |
+ std::string VerboseBuffer; |
+ raw_string_ostream VerboseStrm(VerboseBuffer); |
+ if (LazyBitcode) { |
+ std::string StrError; |
+ switch (InputFileFormat) { |
+ case PNaClFormat: |
+ M.reset(getNaClStreamedBitcodeModule( |
+ InputFilename, |
+ new ThreadedStreamingCache(StreamingObject), Context, &VerboseStrm, |
+ &StrError)); |
+ break; |
+ case LLVMFormat: |
+ M.reset(getStreamedBitcodeModule( |
+ InputFilename, |
+ new ThreadedStreamingCache(StreamingObject), Context, &StrError)); |
+ break; |
+ case AutodetectFileFormat: |
+ report_fatal_error("Command can't autodetect file format!"); |
+ } |
+ if (!StrError.empty()) |
+ Err = SMDiagnostic(InputFilename, SourceMgr::DK_Error, StrError); |
+ } else { |
+#if defined(PNACL_BROWSER_TRANSLATOR) |
+ llvm_unreachable("native client SRPC only supports streaming"); |
+#else |
+ // Parses binary bitcode as well as textual assembly |
+ // (so pulls in more code into pnacl-llc). |
+ M = NaClParseIRFile(InputFilename, InputFileFormat, Err, &VerboseStrm, |
+ Context); |
+#endif |
+ } |
+ if (!M) { |
+#if defined(PNACL_BROWSER_TRANSLATOR) |
+ report_fatal_error(VerboseStrm.str() + Err.getMessage()); |
+#else |
+ // Err.print is prettier, so use it for the non-sandboxed translator. |
+ Err.print(ProgramName.data(), errs()); |
+ errs() << VerboseStrm.str(); |
+ return nullptr; |
+#endif |
+ } |
+ return std::move(M); |
+} |
+ |
+static cl::opt<bool> |
+ExternalizeAll("externalize", |
+ cl::desc("Externalize all symbols"), |
+ cl::init(false)); |
+ |
+static int runCompilePasses(Module *ModuleRef, |
+ unsigned ModuleIndex, |
+ ThreadedFunctionQueue *FuncQueue, |
+ const Triple &TheTriple, |
+ TargetMachine &Target, |
+ StringRef ProgramName, |
+ formatted_raw_ostream &FOS){ |
+ PNaClABIErrorReporter ABIErrorReporter; |
+ |
+ if (SplitModuleCount > 1 || ExternalizeAll) { |
+ // Add function and global names, and give them external linkage. |
+ // This relies on LLVM's consistent auto-generation of names, we could |
+ // maybe do our own in case something changes there. |
+ for (Function &F : *ModuleRef) { |
+ if (!F.hasName()) |
+ F.setName("Function"); |
+ if (F.hasInternalLinkage()) |
+ F.setLinkage(GlobalValue::ExternalLinkage); |
+ } |
+ for (Module::global_iterator GI = ModuleRef->global_begin(), |
+ GE = ModuleRef->global_end(); |
+ GI != GE; ++GI) { |
+ if (!GI->hasName()) |
+ GI->setName("Global"); |
+ if (GI->hasInternalLinkage()) |
+ GI->setLinkage(GlobalValue::ExternalLinkage); |
+ } |
+ if (ModuleIndex > 0) { |
+ // Remove the initializers for all global variables, turning them into |
+ // declarations. |
+ for (Module::global_iterator GI = ModuleRef->global_begin(), |
+ GE = ModuleRef->global_end(); |
+ GI != GE; ++GI) { |
+ assert(GI->hasInitializer() && "Global variable missing initializer"); |
+ Constant *Init = GI->getInitializer(); |
+ GI->setInitializer(nullptr); |
+ if (Init->getNumUses() == 0) |
+ Init->destroyConstant(); |
+ } |
+ } |
+ } |
+ |
+ // Make all non-weak symbols hidden for better code. We cannot do |
+ // this for weak symbols. The linker complains when some weak |
+ // symbols are not resolved. |
+ for (Function &F : *ModuleRef) { |
+ if (!F.isWeakForLinker() && !F.hasLocalLinkage()) |
+ F.setVisibility(GlobalValue::HiddenVisibility); |
+ } |
+ for (Module::global_iterator GI = ModuleRef->global_begin(), |
+ GE = ModuleRef->global_end(); |
+ GI != GE; ++GI) { |
+ if (!GI->isWeakForLinker() && !GI->hasLocalLinkage()) |
+ GI->setVisibility(GlobalValue::HiddenVisibility); |
+ } |
+ |
+ // Build up all of the passes that we want to do to the module. |
+ std::unique_ptr<PassManagerBase> PM; |
+ if (LazyBitcode) |
+ PM.reset(new FunctionPassManager(ModuleRef)); |
+ else |
+ PM.reset(new PassManager()); |
+ |
+ // Add the target data from the target machine, if it exists, or the module. |
+ if (const DataLayout *DL = Target.getSubtargetImpl()->getDataLayout()) |
+ ModuleRef->setDataLayout(DL); |
+ PM->add(new DataLayoutPass()); |
+ |
+ // For conformance with llc, we let the user disable LLVM IR verification with |
+ // -disable-verify. Unlike llc, when LLVM IR verification is enabled we only |
+ // run it once, before PNaCl ABI verification. |
+ if (!NoVerify) |
+ PM->add(createVerifierPass()); |
+ |
+ // Add the ABI verifier pass before the analysis and code emission passes. |
+ if (PNaClABIVerify) |
+ PM->add(createPNaClABIVerifyFunctionsPass(&ABIErrorReporter)); |
+ |
+ // Add the intrinsic resolution pass. It assumes ABI-conformant code. |
+ PM->add(createResolvePNaClIntrinsicsPass()); |
+ |
+ // Add an appropriate TargetLibraryInfo pass for the module's triple. |
+ TargetLibraryInfo *TLI = new TargetLibraryInfo(TheTriple); |
+ if (DisableSimplifyLibCalls) |
+ TLI->disableAllFunctions(); |
+ PM->add(TLI); |
+ |
+ // Allow subsequent passes and the backend to better optimize instructions |
+ // that were simplified for PNaCl's ABI. This pass uses the TargetLibraryInfo |
+ // above. |
+ PM->add(createBackendCanonicalizePass()); |
+ |
+ // Add internal analysis passes from the target machine. |
+ Target.addAnalysisPasses(*PM); |
+ |
+ // Ask the target to add backend passes as necessary. We explicitly ask it |
+ // not to add the verifier pass because we added it earlier. |
+ if (Target.addPassesToEmitFile(*PM, FOS, FileType, |
+ /* DisableVerify */ true)) { |
+ errs() << ProgramName |
+ << ": target does not support generation of this file type!\n"; |
+ return 1; |
+ } |
+ |
+ if (LazyBitcode) { |
+ auto FPM = static_cast<FunctionPassManager *>(PM.get()); |
+ FPM->doInitialization(); |
+ unsigned FuncIndex = 0; |
+ switch (SplitModuleSched) { |
+ case SplitModuleStatic: |
+ for (Function &F : *ModuleRef) { |
+ if (FuncQueue->GrabFunctionStatic(FuncIndex, ModuleIndex)) { |
+ FPM->run(F); |
+ CheckABIVerifyErrors(ABIErrorReporter, "Function " + F.getName()); |
+ F.Dematerialize(); |
+ } |
+ ++FuncIndex; |
+ } |
+ break; |
+ case SplitModuleDynamic: |
+ unsigned ChunkSize = 0; |
+ unsigned NumFunctions = FuncQueue->Size(); |
+ Module::iterator I = ModuleRef->begin(); |
+ while (FuncIndex < NumFunctions) { |
+ ChunkSize = FuncQueue->RecommendedChunkSize(); |
+ unsigned NextIndex; |
+ bool grabbed = FuncQueue->GrabFunctionDynamic(FuncIndex, ChunkSize, |
+ NextIndex); |
+ if (grabbed) { |
+ while (FuncIndex < NextIndex) { |
+ if (!I->isMaterializable() && I->isDeclaration()) { |
+ ++I; |
+ continue; |
+ } |
+ FPM->run(*I); |
+ CheckABIVerifyErrors(ABIErrorReporter, "Function " + I->getName()); |
+ I->Dematerialize(); |
+ ++FuncIndex; |
+ ++I; |
+ } |
+ } else { |
+ while (FuncIndex < NextIndex) { |
+ if (!I->isMaterializable() && I->isDeclaration()) { |
+ ++I; |
+ continue; |
+ } |
+ ++FuncIndex; |
+ ++I; |
+ } |
+ } |
+ } |
+ break; |
+ } |
+ FPM->doFinalization(); |
+ } else |
+ static_cast<PassManager *>(PM.get())->run(*ModuleRef); |
+ |
+ return 0; |
+} |
+ |
+static int compileSplitModule(const TargetOptions &Options, |
+ const Triple &TheTriple, |
+ const Target *TheTarget, |
+ const std::string &FeaturesStr, |
+ CodeGenOpt::Level OLvl, |
+ const StringRef &ProgramName, |
+ Module *GlobalModuleRef, |
+ StreamingMemoryObject *StreamingObject, |
+ unsigned ModuleIndex, |
+ ThreadedFunctionQueue *FuncQueue) { |
+ std::auto_ptr<TargetMachine> |
+ target(TheTarget->createTargetMachine(TheTriple.getTriple(), |
+ MCPU, FeaturesStr, Options, |
+ RelocModel, CMModel, OLvl)); |
+ assert(target.get() && "Could not allocate target machine!"); |
+ TargetMachine &Target = *target.get(); |
+ // Override default to generate verbose assembly. |
+ Target.setAsmVerbosityDefault(true); |
+ if (RelaxAll.getNumOccurrences() > 0 && |
+ FileType != TargetMachine::CGFT_ObjectFile) |
+ errs() << ProgramName |
+ << ": warning: ignoring -mc-relax-all because filetype != obj"; |
+ // The OwningPtrs are only used if we are not the primary module. |
+ std::unique_ptr<LLVMContext> C; |
+ std::unique_ptr<Module> M; |
+ Module *ModuleRef = nullptr; |
+ |
+ if (ModuleIndex == 0) { |
+ ModuleRef = GlobalModuleRef; |
+ } else { |
+ C.reset(new LLVMContext()); |
+ M = getModule(ProgramName, *C, StreamingObject); |
+ if (!M) |
+ return 1; |
+ // M owns the temporary module, but use a reference through ModuleRef |
+ // to also work in the case we are using GlobalModuleRef. |
+ ModuleRef = M.get(); |
+ |
+ // Add declarations for external functions required by PNaCl. The |
+ // ResolvePNaClIntrinsics function pass running during streaming |
+ // depends on these declarations being in the module. |
+ std::unique_ptr<ModulePass> AddPNaClExternalDeclsPass( |
+ createAddPNaClExternalDeclsPass()); |
+ AddPNaClExternalDeclsPass->runOnModule(*ModuleRef); |
+ AddPNaClExternalDeclsPass.reset(); |
+ } |
+ |
+ ModuleRef->setTargetTriple(Triple::normalize(UserDefinedTriple)); |
+ |
+ { |
+#if !defined(PNACL_BROWSER_TRANSLATOR) |
+ // Figure out where we are going to send the output. |
+ std::string N(OutputFilename); |
+ raw_string_ostream OutFileName(N); |
+ if (ModuleIndex > 0) |
+ OutFileName << ".module" << ModuleIndex; |
+ std::unique_ptr<tool_output_file> Out |
+ (GetOutputStream(TheTarget->getName(), TheTriple.getOS(), |
+ OutFileName.str())); |
+ if (!Out) return 1; |
+ formatted_raw_ostream FOS(Out->os()); |
+#else |
+ raw_fd_ostream ROS(getObjectFileFD(ModuleIndex), /* ShouldClose */ true); |
+ ROS.SetBufferSize(1 << 20); |
+ formatted_raw_ostream FOS(ROS); |
+#endif |
+ int ret = runCompilePasses(ModuleRef, ModuleIndex, FuncQueue, |
+ TheTriple, Target, ProgramName, |
+ FOS); |
+ if (ret) |
+ return ret; |
+#if defined(PNACL_BROWSER_TRANSLATOR) |
+ FOS.flush(); |
+ ROS.flush(); |
+#else |
+ // Declare success. |
+ Out->keep(); |
+#endif // PNACL_BROWSER_TRANSLATOR |
+ } |
+ return 0; |
+} |
+ |
+struct ThreadData { |
+ const TargetOptions *Options; |
+ const Triple *TheTriple; |
+ const Target *TheTarget; |
+ std::string FeaturesStr; |
+ CodeGenOpt::Level OLvl; |
+ std::string ProgramName; |
+ Module *GlobalModuleRef; |
+ StreamingMemoryObject *StreamingObject; |
+ unsigned ModuleIndex; |
+ ThreadedFunctionQueue *FuncQueue; |
+}; |
+ |
+ |
+static void *runCompileThread(void *arg) { |
+ struct ThreadData *Data = static_cast<ThreadData *>(arg); |
+ int ret = compileSplitModule(*Data->Options, |
+ *Data->TheTriple, |
+ Data->TheTarget, |
+ Data->FeaturesStr, |
+ Data->OLvl, |
+ Data->ProgramName, |
+ Data->GlobalModuleRef, |
+ Data->StreamingObject, |
+ Data->ModuleIndex, |
+ Data->FuncQueue); |
+ return reinterpret_cast<void *>(static_cast<intptr_t>(ret)); |
+} |
+ |
+static int compileModule(StringRef ProgramName) { |
+ // Use a new context instead of the global context for the main module. It must |
+ // outlive the module object, declared below. We do this because |
+ // lib/CodeGen/PseudoSourceValue.cpp gets a type from the global context and |
+ // races with any other use of the context. Rather than doing an invasive |
+ // plumbing change to fix it, we work around it by using a new context here |
+ // and leaving PseudoSourceValue as the only user of the global context. |
+ std::unique_ptr<LLVMContext> MainContext(new LLVMContext()); |
+ std::unique_ptr<Module> MainMod; |
+ Triple TheTriple; |
+ PNaClABIErrorReporter ABIErrorReporter; |
+ std::unique_ptr<StreamingMemoryObject> StreamingObject; |
+ |
+ if (!MainContext) return 1; |
+ |
+#if defined(PNACL_BROWSER_TRANSLATOR) |
+ StreamingObject.reset( |
+ new StreamingMemoryObjectImpl(getNaClBitcodeStreamer())); |
+#else |
+ if (LazyBitcode) { |
+ std::string StrError; |
+ DataStreamer* FileStreamer(getDataFileStreamer(InputFilename, &StrError)); |
+ if (!StrError.empty()) { |
+ SMDiagnostic Err(InputFilename, SourceMgr::DK_Error, StrError); |
+ Err.print(ProgramName.data(), errs()); |
+ } |
+ if (!FileStreamer) |
+ return 1; |
+ StreamingObject.reset(new StreamingMemoryObjectImpl(FileStreamer)); |
+ } |
+#endif |
+ MainMod = getModule(ProgramName, *MainContext.get(), StreamingObject.get()); |
+ |
+ if (!MainMod) return 1; |
+ |
+ if (PNaClABIVerify) { |
+ // Verify the module (but not the functions yet) |
+ std::unique_ptr<ModulePass> VerifyPass( |
+ createPNaClABIVerifyModulePass(&ABIErrorReporter, LazyBitcode)); |
+ VerifyPass->runOnModule(*MainMod); |
+ CheckABIVerifyErrors(ABIErrorReporter, "Module"); |
+ VerifyPass.reset(); |
+ } |
+ |
+ // Add declarations for external functions required by PNaCl. The |
+ // ResolvePNaClIntrinsics function pass running during streaming |
+ // depends on these declarations being in the module. |
+ std::unique_ptr<ModulePass> AddPNaClExternalDeclsPass( |
+ createAddPNaClExternalDeclsPass()); |
+ AddPNaClExternalDeclsPass->runOnModule(*MainMod); |
+ AddPNaClExternalDeclsPass.reset(); |
+ |
+ if (UserDefinedTriple.empty()) { |
+ report_fatal_error("-mtriple must be set to a target triple for pnacl-llc"); |
+ } else { |
+ MainMod->setTargetTriple(Triple::normalize(UserDefinedTriple)); |
+ TheTriple = Triple(MainMod->getTargetTriple()); |
+ } |
+ |
+ // Get the target specific parser. |
+ std::string Error; |
+ const Target *TheTarget = TargetRegistry::lookupTarget(MArch, TheTriple, |
+ Error); |
+ if (!TheTarget) { |
+ errs() << ProgramName << ": " << Error; |
+ return 1; |
+ } |
+ |
+ TargetOptions Options = InitTargetOptionsFromCodeGenFlags(); |
+ Options.DisableIntegratedAS = NoIntegratedAssembler; |
+ |
+ if (GenerateSoftFloatCalls) |
+ FloatABIForCalls = FloatABI::Soft; |
+ |
+ // Package up features to be passed to target/subtarget |
+ std::string FeaturesStr; |
+ if (MAttrs.size()) { |
+ SubtargetFeatures Features; |
+ for (unsigned i = 0; i != MAttrs.size(); ++i) |
+ Features.AddFeature(MAttrs[i]); |
+ FeaturesStr = Features.getString(); |
+ } |
+ |
+ CodeGenOpt::Level OLvl = CodeGenOpt::Default; |
+ switch (OptLevel) { |
+ default: |
+ errs() << ProgramName << ": invalid optimization level.\n"; |
+ return 1; |
+ case ' ': break; |
+ case '0': OLvl = CodeGenOpt::None; break; |
+ case '1': OLvl = CodeGenOpt::Less; break; |
+ case '2': OLvl = CodeGenOpt::Default; break; |
+ case '3': OLvl = CodeGenOpt::Aggressive; break; |
+ } |
+ |
+ SmallVector<pthread_t, 4> Pthreads(SplitModuleCount); |
+ SmallVector<ThreadData, 4> ThreadDatas(SplitModuleCount); |
+ ThreadedFunctionQueue FuncQueue(MainMod.get(), SplitModuleCount); |
+ |
+ if (SplitModuleCount == 1) { |
+ // No need for dynamic scheduling with one thread. |
+ SplitModuleSched = SplitModuleStatic; |
+ return compileSplitModule(Options, TheTriple, TheTarget, FeaturesStr, |
+ OLvl, ProgramName, MainMod.get(), nullptr, 0, |
+ &FuncQueue); |
+ } |
+ |
+ for(unsigned ModuleIndex = 0; ModuleIndex < SplitModuleCount; ++ModuleIndex) { |
+ ThreadDatas[ModuleIndex].Options = &Options; |
+ ThreadDatas[ModuleIndex].TheTriple = &TheTriple; |
+ ThreadDatas[ModuleIndex].TheTarget = TheTarget; |
+ ThreadDatas[ModuleIndex].FeaturesStr = FeaturesStr; |
+ ThreadDatas[ModuleIndex].OLvl = OLvl; |
+ ThreadDatas[ModuleIndex].ProgramName = ProgramName.str(); |
+ ThreadDatas[ModuleIndex].GlobalModuleRef = MainMod.get(); |
+ ThreadDatas[ModuleIndex].StreamingObject = StreamingObject.get(); |
+ ThreadDatas[ModuleIndex].ModuleIndex = ModuleIndex; |
+ ThreadDatas[ModuleIndex].FuncQueue = &FuncQueue; |
+ if (pthread_create(&Pthreads[ModuleIndex], nullptr, runCompileThread, |
+ &ThreadDatas[ModuleIndex])) { |
+ report_fatal_error("Failed to create thread"); |
+ } |
+ } |
+ for(unsigned ModuleIndex = 0; ModuleIndex < SplitModuleCount; ++ModuleIndex) { |
+ void *retval; |
+ if (pthread_join(Pthreads[ModuleIndex], &retval)) |
+ report_fatal_error("Failed to join thread"); |
+ intptr_t ret = reinterpret_cast<intptr_t>(retval); |
+ if (ret != 0) |
+ report_fatal_error("Thread returned nonzero"); |
+ } |
+ return 0; |
+} |
+ |
+int main(int argc, char **argv) { |
+#if defined(PNACL_BROWSER_TRANSLATOR) |
+ return srpc_main(argc, argv); |
+#else |
+ return llc_main(argc, argv); |
+#endif // PNACL_BROWSER_TRANSLATOR |
+} |