diff options
author | Eli Bendersky <eliben@chromium.org> | 2013-05-15 11:13:43 -0700 |
---|---|---|
committer | Eli Bendersky <eliben@chromium.org> | 2013-05-15 11:13:43 -0700 |
commit | 28aeda400274e40253573e51cba1b66ca9099270 (patch) | |
tree | 575ad6c52484c2d181edd590f0bac00b367aa13f | |
parent | c5d198304d851d6930cfe0cf3c719624109c4c95 (diff) |
Separate the PNaCl llc into a tool named pnacl-llc (how original!)
BUG=None
R=jvoung@chromium.org
Review URL: https://codereview.chromium.org/14604011
-rw-r--r-- | tools/CMakeLists.txt | 1 | ||||
-rw-r--r-- | tools/LLVMBuild.txt | 2 | ||||
-rw-r--r-- | tools/Makefile | 2 | ||||
-rw-r--r-- | tools/pnacl-llc/CMakeLists.txt | 8 | ||||
-rw-r--r-- | tools/pnacl-llc/LLVMBuild.txt | 22 | ||||
-rw-r--r-- | tools/pnacl-llc/Makefile | 15 | ||||
-rw-r--r-- | tools/pnacl-llc/SRPCStreamer.cpp | 142 | ||||
-rw-r--r-- | tools/pnacl-llc/SRPCStreamer.h | 117 | ||||
-rw-r--r-- | tools/pnacl-llc/nacl_file.cpp | 422 | ||||
-rw-r--r-- | tools/pnacl-llc/pnacl-llc.cpp | 585 |
10 files changed, 1314 insertions, 2 deletions
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index e149a14831..0be9602fda 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -14,6 +14,7 @@ add_subdirectory(llvm-dis) add_subdirectory(llvm-mc) add_subdirectory(llc) +add_subdirectory(pnacl-llc) add_subdirectory(llvm-ranlib) add_subdirectory(llvm-ar) add_subdirectory(llvm-nm) diff --git a/tools/LLVMBuild.txt b/tools/LLVMBuild.txt index c301ea9371..d7160f774d 100644 --- a/tools/LLVMBuild.txt +++ b/tools/LLVMBuild.txt @@ -16,7 +16,7 @@ ;===------------------------------------------------------------------------===; [common] -subdirectories = bugpoint llc lli llvm-ar llvm-as llvm-bcanalyzer llvm-cov llvm-diff llvm-dis llvm-dwarfdump llvm-extract llvm-jitlistener llvm-link llvm-mc llvm-nm llvm-objdump llvm-prof llvm-ranlib llvm-rtdyld llvm-size macho-dump opt llvm-mcmarkup pnacl-abicheck pnacl-bcanalyzer pnacl-freeze pnacl-thaw +subdirectories = bugpoint llc pnacl-llc lli llvm-ar llvm-as llvm-bcanalyzer llvm-cov llvm-diff llvm-dis llvm-dwarfdump llvm-extract llvm-jitlistener llvm-link llvm-mc llvm-nm llvm-objdump llvm-prof llvm-ranlib llvm-rtdyld llvm-size macho-dump opt llvm-mcmarkup pnacl-abicheck pnacl-bcanalyzer pnacl-freeze pnacl-thaw [component_0] type = Group diff --git a/tools/Makefile b/tools/Makefile index 1940d7606c..cbf94e743e 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -28,7 +28,7 @@ OPTIONAL_DIRS := lldb # in parallel builds. Please retain this ordering. DIRS := llvm-config PARALLEL_DIRS := opt llvm-as llvm-dis \ - llc llvm-ranlib llvm-ar llvm-nm \ + llc pnacl-llc llvm-ranlib llvm-ar llvm-nm \ llvm-prof llvm-link \ lli llvm-extract llvm-mc \ bugpoint llvm-bcanalyzer \ diff --git a/tools/pnacl-llc/CMakeLists.txt b/tools/pnacl-llc/CMakeLists.txt new file mode 100644 index 0000000000..7e5cc10eb1 --- /dev/null +++ b/tools/pnacl-llc/CMakeLists.txt @@ -0,0 +1,8 @@ +set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} bitreader asmparser naclanalysis) + +add_llvm_tool(pnacl-llc +# This file provides wrappers to lseek(2), read(2), etc. + nacl_file.cpp + SRPCStreamer.cpp + pnacl-llc.cpp + ) diff --git a/tools/pnacl-llc/LLVMBuild.txt b/tools/pnacl-llc/LLVMBuild.txt new file mode 100644 index 0000000000..934bed061a --- /dev/null +++ b/tools/pnacl-llc/LLVMBuild.txt @@ -0,0 +1,22 @@ +;===- ./tools/pnacl-llc/LLVMBuild.txt --------------------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Tool +name = pnacl-llc +parent = Tools +required_libraries = AsmParser BitReader all-targets NaClAnalysis diff --git a/tools/pnacl-llc/Makefile b/tools/pnacl-llc/Makefile new file mode 100644 index 0000000000..ae8104eac5 --- /dev/null +++ b/tools/pnacl-llc/Makefile @@ -0,0 +1,15 @@ +#===- tools/pnacl-llc/Makefile -----------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL := ../.. +TOOLNAME := pnacl-llc +LINK_COMPONENTS := all-targets bitreader asmparser naclanalysis + +include $(LEVEL)/Makefile.common + diff --git a/tools/pnacl-llc/SRPCStreamer.cpp b/tools/pnacl-llc/SRPCStreamer.cpp new file mode 100644 index 0000000000..ae70a24822 --- /dev/null +++ b/tools/pnacl-llc/SRPCStreamer.cpp @@ -0,0 +1,142 @@ +//===-- SRPCStreamer.cpp - Stream bitcode over SRPC ----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// +// +//===----------------------------------------------------------------------===// + +#if defined(__native_client__) && defined(NACL_SRPC) +#define DEBUG_TYPE "bitcode-stream" +#include "SRPCStreamer.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +#include <errno.h> + +using llvm::dbgs; + +const size_t QueueStreamer::queuesize_limit_; + +size_t QueueStreamer::GetBytes(unsigned char *buf, size_t len) { + size_t total_copied = 0; + pthread_mutex_lock(&Mutex); + while (!Done && queueSize() < len - total_copied) { + size_t size = queueSize(); + DEBUG(dbgs() << "QueueStreamer::GetBytes len " << len << " size " << + size << " << waiting\n"); + queueGet(buf + total_copied, size); + total_copied += size; + pthread_cond_signal(&Cond); + pthread_cond_wait(&Cond, &Mutex); + } + // If this is the last partial chunk, adjust len such that the amount we + // fetch will be just the remaining bytes. + if (Done && queueSize() < len - total_copied) { + len = queueSize() + total_copied; + } + queueGet(buf + total_copied, len - total_copied); + pthread_cond_signal(&Cond); + pthread_mutex_unlock(&Mutex); + return len; +} + +size_t QueueStreamer::PutBytes(unsigned char *buf, size_t len) { + size_t total_copied = 0; + pthread_mutex_lock(&Mutex); + while (capacityRemaining() < len - total_copied) { + if (Bytes.size() * 2 > queuesize_limit_) { + size_t space = capacityRemaining(); + queuePut(buf + total_copied, space); + total_copied += space; + pthread_cond_signal(&Cond); + pthread_cond_wait(&Cond, &Mutex); + } else { + queueResize(); + } + } + queuePut(buf + total_copied, len - total_copied); + pthread_cond_signal(&Cond); + pthread_mutex_unlock(&Mutex); + return len; +} + +void QueueStreamer::SetDone() { + // Still need the lock to avoid signaling between the check and + // the wait in GetBytes. + pthread_mutex_lock(&Mutex); + Done = true; + pthread_cond_signal(&Cond); + pthread_mutex_unlock(&Mutex); +} + +// Double the size of the queue. Called with Mutex to protect Cons/Prod/Bytes. +void QueueStreamer::queueResize() { + int leftover = Bytes.size() - Cons; + DEBUG(dbgs() << "resizing to " << Bytes.size() * 2 << " " << leftover << " " + << Prod << " " << Cons << "\n"); + Bytes.resize(Bytes.size() * 2); + if (Cons > Prod) { + // There are unread bytes left between Cons and the previous end of the + // buffer. Move them to the new end of the buffer. + memmove(&Bytes[Bytes.size() - leftover], &Bytes[Cons], leftover); + Cons = Bytes.size() - leftover; + } +} + +// Called with Mutex held to protect Cons, Prod, and Bytes +void QueueStreamer::queuePut(unsigned char *buf, size_t len) { + size_t EndSpace = std::min(len, Bytes.size() - Prod); + DEBUG(dbgs() << "put, len " << len << " Endspace " << EndSpace << " p " << + Prod << " c " << Cons << "\n"); + // Copy up to the end of the buffer + memcpy(&Bytes[Prod], buf, EndSpace); + // Wrap around if necessary + memcpy(&Bytes[0], buf + EndSpace, len - EndSpace); + Prod = (Prod + len) % Bytes.size(); +} + +// Called with Mutex held to protect Cons, Prod, and Bytes +void QueueStreamer::queueGet(unsigned char *buf, size_t len) { + assert(len <= queueSize()); + size_t EndSpace = std::min(len, Bytes.size() - Cons); + DEBUG(dbgs() << "get, len " << len << " Endspace " << EndSpace << " p " << + Prod << " c " << Cons << "\n"); + // Copy up to the end of the buffer + memcpy(buf, &Bytes[Cons], EndSpace); + // Wrap around if necessary + memcpy(buf + EndSpace, &Bytes[0], len - EndSpace); + Cons = (Cons + len) % Bytes.size(); +} + +llvm::DataStreamer *SRPCStreamer::init(void *(*Callback)(void *), void *arg, + std::string *ErrMsg) { + int err = pthread_create(&CompileThread, NULL, Callback, arg); + if (err) { + if (ErrMsg) *ErrMsg = std::string(strerror(errno)); + return NULL; + } + return &Q; +} + +size_t SRPCStreamer::gotChunk(unsigned char *bytes, size_t len) { + if (Error) return 0; + return Q.PutBytes(bytes, len); +} + +int SRPCStreamer::streamEnd(std::string *ErrMsg) { + Q.SetDone(); + int err = pthread_join(CompileThread, NULL); + if (err) { + if (ErrMsg) *ErrMsg = std::string(strerror(errno)); + return err; + } + if (Error && ErrMsg) *ErrMsg = std::string("compile failed."); + return Error; +} + +#endif diff --git a/tools/pnacl-llc/SRPCStreamer.h b/tools/pnacl-llc/SRPCStreamer.h new file mode 100644 index 0000000000..4c1c6737e6 --- /dev/null +++ b/tools/pnacl-llc/SRPCStreamer.h @@ -0,0 +1,117 @@ +//===-- SRPCStreamer.cpp - Stream bitcode over SRPC ----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// +// +//===----------------------------------------------------------------------===// + +#ifndef SRPCSTREAMER_H +#define SRPCSTREAMER_H + +#include <pthread.h> +#include <cassert> +#include <cstdio> +#include <cstring> +#include <vector> +#include "llvm/Support/DataStream.h" + +// Implements LLVM's interface for fetching data from a stream source. +// Bitcode bytes from the RPC thread are placed here with PutBytes and buffered +// until the bitcode reader calls GetBytes to remove them. +// The blocking behavior of GetBytes and PutBytes means that if the +// compilation happens faster than the bytes come in from the browser, the +// whole pipeline can block waiting for the RPC thread to put more bytes. + +class QueueStreamer : public llvm::DataStreamer { + public: + QueueStreamer() : Done(false), Prod(0), Cons(0) { + pthread_mutex_init(&Mutex, NULL); + pthread_cond_init(&Cond, NULL); + Bytes.resize(64 * 1024); + } + + // Called by the compilation thread. Copy len bytes from the queue into + // buf. If there are less than len bytes available, copy as many as + // there are, signal the RPC thread, and block to wait for the rest. + // If all bytes have been received from the browser and there are + // fewer than len bytes available, copy all remaining bytes. + // Return the number of bytes copied. + virtual size_t GetBytes(unsigned char *buf, size_t len); + + // Called by the RPC thread. Copy len bytes from buf into the queue. + // If there is not enough space in the queue, copy as many bytes as + // will fit, signal the compilation thread, and block until there is + // enough space for the rest. + // Return the number of bytes copied. + size_t PutBytes(unsigned char *buf, size_t len); + + // Called by the RPC thread. Signal that all bytes have been received, + // so the last call to GetBytes will return the remaining bytes rather + // than waiting for the entire requested amound. + void SetDone(); + + private: + bool Done; + pthread_mutex_t Mutex; + pthread_cond_t Cond; + // Maximum size of the queue. The limitation on the queue size means that + // if the compilation happens slower than bytes arrive from the network, + // the queue will fill up, the RPC thread will be blocked most of the time, + // the RPC thread on the browser side will be waiting for the SRPC to return, + // and the buffer on the browser side will grow unboundedly until the + // whole bitcode file arrives (which is better than having the queue on + // the untrusted side consume all that memory). + // The partial-copying behavior of GetBytes and PutBytes prevents deadlock + // even if the requested number of bytes is greater than the size limit + // (although it will of course be less efficient). + // The initial size of the queue is expected to be smaller than this, but + // if not, it will simply never be resized. + const static size_t queuesize_limit_ = 256 * 1024; + + // Variables and functions to manage the circular queue + std::vector<unsigned char> Bytes; + size_t Prod; // Queue producer index + size_t Cons; // Queue consumer index + size_t queueSize() { + return Prod >= Cons ? Prod - Cons : Bytes.size() - (Cons - Prod); + } + size_t capacityRemaining() { + return (Prod >= Cons ? Bytes.size() - (Prod - Cons) : (Cons - Prod)) - 1; + } + void queueResize(); + void queuePut(unsigned char *buf, size_t len); + void queueGet(unsigned char *buf, size_t len); +}; + +// Class to manage the compliation thread and serve as the interface from +// the SRPC thread +class SRPCStreamer { +public: + SRPCStreamer() : Error(false) {} + // Initialize streamer, create a new thread running Callback, and + // return a pointer to the DataStreamer the threads will use to + // synchronize. On error, return NULL and fill in the ErrorMsg string + llvm::DataStreamer *init(void *(*Callback)(void *), + void *arg, std::string *ErrMsg); + // Called by the RPC thread. Copy len bytes from buf. Return bytes copied. + size_t gotChunk(unsigned char *bytes, size_t len); + // Called by the RPC thread. Wait for the compilation thread to finish. + int streamEnd(std::string *ErrMsg); + // Called by the compilation thread. Signal that there was a compilation + // error so the RPC thread can abort the stream. + void setError() { Error = true; } +private: + bool Error; + QueueStreamer Q; + pthread_t CompileThread; +}; + + + +#endif // SRPCSTREAMER_H diff --git a/tools/pnacl-llc/nacl_file.cpp b/tools/pnacl-llc/nacl_file.cpp new file mode 100644 index 0000000000..b7ecb407cd --- /dev/null +++ b/tools/pnacl-llc/nacl_file.cpp @@ -0,0 +1,422 @@ +/* Copyright 2012 The Native Client Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can + * be found in the LICENSE file. + * + * This file provides wrappers to open() to use pre-opened file descriptors + * for the input bitcode and the output file. + * + * It also has the SRPC interfaces, but that should probably be refactored + * into a separate file. + */ + +#if defined(__native_client__) && defined(NACL_SRPC) + +#include <argz.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +// Headers which are not properly part of the SDK are included by their +// path in the nacl tree +#include "native_client/src/shared/srpc/nacl_srpc.h" +#ifdef __pnacl__ +#include <nacl/pnacl.h> +#endif +#include "SRPCStreamer.h" + +#include <string> +#include <map> +#include <vector> + +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/system_error.h" + + +using llvm::MemoryBuffer; +using llvm::StringRef; +using std::string; +using std::map; + +#define printerr(...) fprintf(stderr, __VA_ARGS__) +// printdbg is currently disabled to reduce spew. +#define printdbg(...) + +#define ARRAY_SIZE(array) (sizeof array / sizeof array[0]) + +namespace { + +typedef std::vector<std::string> string_vector; + +// True if the bitcode to be compiled is for a shared library. +// Used to return to the coordinator. +bool g_bitcode_is_shared_library; +// The soname of the current compilation unit, if it is a shared library. +// Empty string otherwise. +std::string* g_bitcode_soname = NULL; +// The newline separated list of libraries that the current bitcode compilation +// unit depends on. +std::string* g_bitcode_lib_dependencies = NULL; +// The filename used internally for looking up the bitcode file. +char kBitcodeFilename[] = "pnacl.pexe"; +// The filename used internally for looking up the object code file. +char kObjectFilename[] = "pnacl.o"; +// Object which manages streaming bitcode over SRPC and threading. +SRPCStreamer *srpc_streamer; +// FD of the object file. +int object_file_fd; + +} // namespace + +//TODO(dschuff): a little more elegant interface into llc than this? +extern llvm::DataStreamer* NaClBitcodeStreamer; + +extern int llc_main(int argc, char **argv); + +int GetObjectFileFD() { + return object_file_fd; +} + +void NaClRecordObjectInformation(bool is_shared, const std::string& soname) { + // This function is invoked to begin recording library information. + // To make it reentrant, we clean up what might be left over from last time. + delete g_bitcode_soname; + delete g_bitcode_lib_dependencies; + // Then remember the module global information. + g_bitcode_is_shared_library = is_shared; + g_bitcode_soname = new std::string(soname); + g_bitcode_lib_dependencies = new std::string(); +} + +void NaClRecordSharedLibraryDependency(const std::string& library_name) { + const std::string& kDelimiterString("\n"); + *g_bitcode_lib_dependencies += (library_name + kDelimiterString); +} + +namespace { + +int DoTranslate(string_vector* cmd_line_vec, int object_fd) { + if (cmd_line_vec == NULL) { + return 1; + } + object_file_fd = object_fd; + // Make an argv array from the input vector. + size_t argc = cmd_line_vec->size(); + char** argv = new char*[argc]; + for (size_t i = 0; i < argc; ++i) { + // llc_main will not mutate the command line, so this is safe. + argv[i] = const_cast<char*>((*cmd_line_vec)[i].c_str()); + } + argv[argc] = NULL; + // Call main. + return llc_main(static_cast<int>(argc), argv); +} + +string_vector* CommandLineFromArgz(char* str, size_t str_len) { + char* entry = str; + string_vector* vec = new string_vector; + while (entry != NULL) { + vec->push_back(entry); + entry = argz_next(str, str_len, entry); + } + return vec; +} + +void AddFixedArguments(string_vector* vec) { + // Add fixed arguments to the command line. These specify the bitcode + // and object code filenames, removing them from the contract with the + // coordinator. + vec->push_back(kBitcodeFilename); + vec->push_back("-o"); + vec->push_back(kObjectFilename); +} + +bool AddDefaultCPU(string_vector* vec) { +#if defined (__pnacl__) + switch (__builtin_nacl_target_arch()) { + case PnaclTargetArchitectureX86_32: { + vec->push_back("-mcpu=pentium4"); + break; + } + case PnaclTargetArchitectureX86_64: { + vec->push_back("-mcpu=core2"); + break; + } + case PnaclTargetArchitectureARM_32: { + vec->push_back("-mcpu=cortex-a9"); + break; + } + default: + printerr("no target architecture match.\n"); + return false; + } +// Some cases for building this with nacl-gcc. +#elif defined (__i386__) + vec->push_back("-mcpu=pentium4"); +#elif defined (__x86_64__) + vec->push_back("-mcpu=core2"); +#elif defined (__arm__) + vec->push_back("-mcpu=cortex-a9"); +#error "Unknown architecture" +#endif + return true; +} + +bool HasCPUOverride(string_vector* vec) { + std::string mcpu = std::string("-mcpu="); + size_t len = mcpu.length(); + for (size_t i = 0; i < vec->size(); ++i) { + std::string prefix = (*vec)[i].substr(0, len); + if (prefix.compare(mcpu) == 0) + return true; + } + return false; +} + +string_vector* GetDefaultCommandLine() { + string_vector* command_line = new string_vector; + size_t i; + // First, those common to all architectures. + static const char* common_args[] = { "pnacl_translator", + "-filetype=obj" }; + for (i = 0; i < ARRAY_SIZE(common_args); ++i) { + command_line->push_back(common_args[i]); + } + // Then those particular to a platform. + static const char* llc_args_x8632[] = { "-mtriple=i686-none-nacl-gnu", + NULL }; + static const char* llc_args_x8664[] = { "-mtriple=x86_64-none-nacl-gnu", + NULL }; + static const char* llc_args_arm[] = { "-mtriple=armv7a-none-nacl-gnueabi", + "-arm-reserve-r9", + "-sfi-disable-cp", + "-sfi-store", + "-sfi-load", + "-sfi-stack", + "-sfi-branch", + "-sfi-data", + "-mattr=+neon", + "-no-inline-jumptables", + "-float-abi=hard", + NULL }; + + const char **llc_args = NULL; +#if defined (__pnacl__) + switch (__builtin_nacl_target_arch()) { + case PnaclTargetArchitectureX86_32: { + llc_args = llc_args_x8632; + break; + } + case PnaclTargetArchitectureX86_64: { + llc_args = llc_args_x8664; + break; + } + case PnaclTargetArchitectureARM_32: { + llc_args = llc_args_arm; + break; + } + default: + printerr("no target architecture match.\n"); + delete command_line; + return NULL; + } +// Some cases for building this with nacl-gcc. +#elif defined (__i386__) + llc_args = llc_args_x8632; +#elif defined (__x86_64__) + llc_args = llc_args_x8664; +#elif defined (__arm__) + llc_args = llc_args_arm; +#else +#error "Unknown architecture" +#endif + for (i = 0; llc_args[i] != NULL; i++) command_line->push_back(llc_args[i]); + return command_line; +} + +// Data passed from main thread to compile thread. +// Takes ownership of the commandline vector. +class StreamingThreadData { + public: + StreamingThreadData(int object_fd, string_vector* cmd_line_vec) : + object_fd_(object_fd), cmd_line_vec_(cmd_line_vec) {} + int ObjectFD() const { return object_fd_; } + string_vector* CmdLineVec() const { return cmd_line_vec_.get(); } + const int object_fd_; + const llvm::OwningPtr<string_vector> cmd_line_vec_; +}; + +void *run_streamed(void *arg) { + StreamingThreadData* data = reinterpret_cast<StreamingThreadData*>(arg); + data->CmdLineVec()->push_back("-streaming-bitcode"); + if (DoTranslate(data->CmdLineVec(), data->ObjectFD()) != 0) { + printerr("DoTranslate failed.\n"); + srpc_streamer->setError(); + return NULL; + } + delete data; + return NULL; +} + +// Actually do the work for stream initialization. +void do_stream_init(NaClSrpcRpc *rpc, + NaClSrpcArg **in_args, + NaClSrpcArg **out_args, + NaClSrpcClosure *done, + string_vector* command_line_vec) { + NaClSrpcClosureRunner runner(done); + rpc->result = NACL_SRPC_RESULT_APP_ERROR; + srpc_streamer = new SRPCStreamer(); + std::string StrError; + StreamingThreadData* thread_data = new StreamingThreadData( + in_args[0]->u.hval, command_line_vec); + NaClBitcodeStreamer = srpc_streamer->init(run_streamed, + reinterpret_cast<void *>(thread_data), + &StrError); + if (NaClBitcodeStreamer) { + rpc->result = NACL_SRPC_RESULT_OK; + out_args[0]->arrays.str = strdup("no error"); + } else { + out_args[0]->arrays.str = strdup(StrError.c_str()); + } +} + +// Invoked by the StreamInit RPC to initialize bitcode streaming over SRPC. +// Under the hood it forks a new thread at starts the llc_main, which sets +// up the compilation and blocks when it tries to start reading the bitcode. +// Input arg is a file descriptor to write the output object file to. +// Returns a string, containing an error message if the call fails. +void stream_init(NaClSrpcRpc *rpc, + NaClSrpcArg **in_args, + NaClSrpcArg **out_args, + NaClSrpcClosure *done) { + // cmd_line_vec allocated by GetDefaultCommandLine() is freed by the + // translation thread in run_streamed() + string_vector* cmd_line_vec = GetDefaultCommandLine(); + if (!cmd_line_vec || !AddDefaultCPU(cmd_line_vec)) { + NaClSrpcClosureRunner runner(done); + rpc->result = NACL_SRPC_RESULT_APP_ERROR; + out_args[0]->arrays.str = strdup("Failed to get default commandline."); + return; + } + AddFixedArguments(cmd_line_vec); + do_stream_init(rpc, in_args, out_args, done, cmd_line_vec); +} + +// Invoked by StreamInitWithCommandLine RPC. Same as stream_init, but +// provides a command line to use instead of the default. +void stream_init_with_command_line(NaClSrpcRpc *rpc, + NaClSrpcArg **in_args, + NaClSrpcArg **out_args, + NaClSrpcClosure *done) { + char* command_line = in_args[1]->arrays.carr; + size_t command_line_len = in_args[1]->u.count; + string_vector* cmd_line_vec = + CommandLineFromArgz(command_line, command_line_len); + AddFixedArguments(cmd_line_vec); + // cmd_line_vec is freed by the translation thread in run_streamed + do_stream_init(rpc, in_args, out_args, done, cmd_line_vec); +} + +// Invoked by StreamInitWithOverrides RPC. Same as stream_init, but +// provides commandline flag overrides (appended to the default). +void stream_init_with_overrides(NaClSrpcRpc *rpc, + NaClSrpcArg **in_args, + NaClSrpcArg **out_args, + NaClSrpcClosure *done) { + string_vector* cmd_line_vec = GetDefaultCommandLine(); + if (!cmd_line_vec) { + NaClSrpcClosureRunner runner(done); + rpc->result = NACL_SRPC_RESULT_APP_ERROR; + out_args[0]->arrays.str = strdup("Failed to get default commandline."); + return; + } + AddFixedArguments(cmd_line_vec); + + char* command_line = in_args[1]->arrays.carr; + size_t command_line_len = in_args[1]->u.count; + llvm::OwningPtr<string_vector> extra_vec( + CommandLineFromArgz(command_line, command_line_len)); + cmd_line_vec->insert(cmd_line_vec->end(), + extra_vec->begin(), extra_vec->end()); + // Make sure some -mcpu override exists for now to prevent + // auto-cpu feature detection from triggering instructions that + // we do not validate yet. + if (!HasCPUOverride(extra_vec.get())) { + AddDefaultCPU(cmd_line_vec); + } + extra_vec.reset(NULL); + // cmd_line_vec is freed by the translation thread in run_streamed. + do_stream_init(rpc, in_args, out_args, done, cmd_line_vec); +} + +// Invoked by the StreamChunk RPC. Receives a chunk of the bitcode and +// buffers it for later retrieval by the compilation thread. +void stream_chunk(NaClSrpcRpc *rpc, + NaClSrpcArg **in_args, + NaClSrpcArg **out_args, + NaClSrpcClosure *done) { + NaClSrpcClosureRunner runner(done); + rpc->result = NACL_SRPC_RESULT_APP_ERROR; + size_t len = in_args[0]->u.count; + unsigned char *bytes = reinterpret_cast<unsigned char*>( + in_args[0]->arrays.carr); + if (srpc_streamer->gotChunk(bytes, len) != len) { + return; + } + rpc->result = NACL_SRPC_RESULT_OK; +} + +// Invoked by the StreamEnd RPC. Waits until the compilation finishes, +// then returns. Returns an int indicating whether the bitcode is a +// shared library, a string with the soname, a string with dependencies, +// and a string which contains an error message if applicable. +void stream_end(NaClSrpcRpc *rpc, + NaClSrpcArg **in_args, + NaClSrpcArg **out_args, + NaClSrpcClosure *done) { + NaClSrpcClosureRunner runner(done); + rpc->result = NACL_SRPC_RESULT_APP_ERROR; + std::string StrError; + if (srpc_streamer->streamEnd(&StrError)) { + out_args[3]->arrays.str = strdup(StrError.c_str()); + return; + } + out_args[0]->u.ival = g_bitcode_is_shared_library; + // SRPC deletes the strings returned when the closure is invoked. + // Therefore we need to use strdup. + out_args[1]->arrays.str = strdup(g_bitcode_soname->c_str()); + out_args[2]->arrays.str = strdup(g_bitcode_lib_dependencies->c_str()); + rpc->result = NACL_SRPC_RESULT_OK; +} + +const struct NaClSrpcHandlerDesc srpc_methods[] = { + // Protocol for streaming: + // (StreamInit(obj_fd) -> error_str | + // StreamInitWIthCommandLine(obj_fd, escaped_cmdline) -> error_str) + // StreamChunk(data) + + // StreamEnd() -> (is_shared_lib,soname,dependencies,error_str) + { "StreamInit:h:s", stream_init }, + { "StreamInitWithCommandLine:hC:s:", stream_init_with_command_line }, + { "StreamInitWithOverrides:hC:s:", stream_init_with_overrides }, + { "StreamChunk:C:", stream_chunk }, + { "StreamEnd::isss", stream_end }, + { NULL, NULL }, +}; + +} // namespace + +int +main() { + if (!NaClSrpcModuleInit()) { + return 1; + } + + if (!NaClSrpcAcceptClientConnection(srpc_methods)) { + return 1; + } + NaClSrpcModuleFini(); + return 0; +} + +#endif diff --git a/tools/pnacl-llc/pnacl-llc.cpp b/tools/pnacl-llc/pnacl-llc.cpp new file mode 100644 index 0000000000..437dff7c0b --- /dev/null +++ b/tools/pnacl-llc/pnacl-llc.cpp @@ -0,0 +1,585 @@ +//===-- 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/Assembly/PrintModulePass.h" +#include "llvm/Support/DataStream.h" +#include "llvm/CodeGen/CommandFlags.h" +#include "llvm/CodeGen/LinkAllAsmWriterComponents.h" +#include "llvm/CodeGen/LinkAllCodegenComponents.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/MC/SubtargetFeature.h" +#include "llvm/Pass.h" +#include "llvm/PassManager.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/FormattedStream.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/IRReader.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/Support/Timer.h" +#include "llvm/Support/ToolOutputFile.h" +#include "llvm/Target/TargetLibraryInfo.h" +#include "llvm/Target/TargetMachine.h" +#include <memory> + + +using namespace llvm; + +// @LOCALMOD-BEGIN +// NOTE: this tool can be build as a "sandboxed" translator. +// There are two ways to build the translator +// SRPC-style: no file operations are allowed +// see nacl_file.cc for support code +// non-SRPC-style: some basic file operations are allowed +// This can be useful for debugging but will +// not be deployed. +#if defined(__native_client__) && defined(NACL_SRPC) +int GetObjectFileFD(); +// The following two functions communicate metadata to the SRPC wrapper for LLC. +void NaClRecordObjectInformation(bool is_shared, const std::string& soname); +void NaClRecordSharedLibraryDependency(const std::string& library_name); +DataStreamer* NaClBitcodeStreamer; +#endif +// @LOCALMOD-END + +// @LOCALMOD-BEGIN +const char *TimeIRParsingGroupName = "LLVM IR Parsing"; +const char *TimeIRParsingName = "Parse IR"; + +bool TimeIRParsingIsEnabled = false; +static cl::opt<bool,true> +EnableTimeIRParsing("time-ir-parsing", cl::location(TimeIRParsingIsEnabled), + cl::desc("Measure the time IR parsing takes")); +// @LOCALMOD-END + +// 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")); + +static cl::opt<unsigned> +TimeCompilations("time-compilations", cl::Hidden, cl::init(1u), + cl::value_desc("N"), + cl::desc("Repeat compilation N times for timing")); + +// Using bitcode streaming has a couple of ramifications. Primarily it means +// that the module in the file will be compiled one function at a time rather +// than the whole module. This allows earlier functions to be compiled before +// later functions are read from the bitcode but of course means no whole-module +// optimizations. 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)); + +// The option below overlaps very much with bitcode streaming. +// We keep it separate because it is still experimental and we want +// to use it without changing the outside behavior which is especially +// relevant for the sandboxed case. +static cl::opt<bool> +ReduceMemoryFootprint("reduce-memory-footprint", + cl::desc("Aggressively reduce memory used by llc"), + 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)); + +// 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> +TargetTriple("mtriple", cl::desc("Override target triple for module")); + +cl::opt<bool> NoVerify("disable-verify", cl::Hidden, + cl::desc("Do not verify input module")); + +cl::opt<bool> +DisableSimplifyLibCalls("disable-simplify-libcalls", + cl::desc("Disable simplify-libcalls"), + cl::init(false)); + +static int compileModule(char**, LLVMContext&); + +// GetFileNameRoot - Helper function to get the basename of a filename. +static inline std::string +GetFileNameRoot(const std::string &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, + const char *ProgName) { + // If we don't yet have an output filename, make one. + if (OutputFilename.empty()) { + if (InputFilename == "-") + OutputFilename = "-"; + else { + OutputFilename = GetFileNameRoot(InputFilename); + + switch (FileType) { + case TargetMachine::CGFT_AssemblyFile: + if (TargetName[0] == 'c') { + if (TargetName[1] == 0) + OutputFilename += ".cbe.c"; + else if (TargetName[1] == 'p' && TargetName[2] == 'p') + OutputFilename += ".cpp"; + else + OutputFilename += ".s"; + } else + OutputFilename += ".s"; + break; + case TargetMachine::CGFT_ObjectFile: + if (OS == Triple::Win32) + OutputFilename += ".obj"; + else + OutputFilename += ".o"; + break; + case TargetMachine::CGFT_Null: + OutputFilename += ".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::string error; + unsigned OpenFlags = 0; + if (Binary) OpenFlags |= raw_fd_ostream::F_Binary; + tool_output_file *FDOut = new tool_output_file(OutputFilename.c_str(), error, + OpenFlags); + if (!error.empty()) { + errs() << error << '\n'; + delete FDOut; + return 0; + } + + return FDOut; +} + +// 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; + + LLVMContext &Context = getGlobalContext(); + llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. + + // Initialize targets first, so that --version shows registered targets. + InitializeAllTargets(); + InitializeAllTargetMCs(); + InitializeAllAsmPrinters(); +// @LOCALMOD-BEGIN +// Prune asm parsing from sandboxed translator. +// Do not prune "AsmPrinters" because that includes +// the direct object emission. + #if !defined(__native_client__) + InitializeAllAsmParsers(); +#endif +// @LOCALMOD-END + + // Initialize codegen and IR passes used by 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); + + cl::ParseCommandLineOptions(argc, argv, "llvm system compiler\n"); + + // Compile the module TimeCompilations times to give better compile time + // metrics. + for (unsigned I = TimeCompilations; I; --I) + if (int RetVal = compileModule(argv, Context)) + return RetVal; + return 0; +} + +// @LOCALMOD-BEGIN +static void CheckABIVerifyErrors(PNaClABIErrorReporter &Reporter, + const Twine &Name) { + if (PNaClABIVerify && Reporter.getErrorCount() > 0) { + errs() << (PNaClABIVerifyFatalErrors ? "ERROR: " : "WARNING: "); + errs() << Name << " is not valid PNaCl bitcode:\n"; + Reporter.printErrors(errs()); + if (PNaClABIVerifyFatalErrors) + exit(1); + } + Reporter.reset(); +} +// @LOCALMOD-END + +static int compileModule(char **argv, LLVMContext &Context) { + // Load the module to be compiled... + SMDiagnostic Err; + std::auto_ptr<Module> M; + Module *mod = 0; + Triple TheTriple; + + bool SkipModule = MCPU == "help" || + (!MAttrs.empty() && MAttrs.front() == "help"); + + PNaClABIErrorReporter ABIErrorReporter; // @LOCALMOD + + // If user just wants to list available options, skip module loading + if (!SkipModule) { + // @LOCALMOD-BEGIN +#if defined(__native_client__) && defined(NACL_SRPC) + if (LazyBitcode) { + std::string StrError; + M.reset(getStreamedBitcodeModule( + std::string("<SRPC stream>"), + NaClBitcodeStreamer, Context, &StrError)); + if (!StrError.empty()) { + Err = SMDiagnostic(InputFilename, SourceMgr::DK_Error, StrError); + } + } else { + // Avoid using ParseIRFile to avoid pulling in the LLParser. + // Only handle binary bitcode. + llvm_unreachable("native client SRPC only supports streaming"); + } +#else + { + // @LOCALMOD: timing is temporary, until it gets properly added upstream + NamedRegionTimer T(TimeIRParsingName, TimeIRParsingGroupName, + TimeIRParsingIsEnabled); + M.reset(ParseIRFile(InputFilename, Err, Context)); + } +#endif + // @LOCALMOD-END + + mod = M.get(); + if (mod == 0) { + Err.print(argv[0], errs()); + return 1; + } + + // @LOCALMOD-BEGIN + if (PNaClABIVerify) { + // Verify the module (but not the functions yet) + ModulePass *VerifyPass = createPNaClABIVerifyModulePass(&ABIErrorReporter); + VerifyPass->runOnModule(*mod); + CheckABIVerifyErrors(ABIErrorReporter, "Module"); + } +#if defined(__native_client__) && defined(NACL_SRPC) + // To determine if we should compile PIC or not, we needed to load at + // least the metadata. Since we've already constructed the commandline, + // we have to hack this in after commandline processing. + if (mod->getOutputFormat() == Module::SharedOutputFormat) { + RelocModel = Reloc::PIC_; + } + // Also set PIC_ for dynamic executables: + // BUG= http://code.google.com/p/nativeclient/issues/detail?id=2351 + if (mod->lib_size() > 0) { + RelocModel = Reloc::PIC_; + } +#endif // defined(__native_client__) && defined(NACL_SRPC) + // @LOCALMOD-END + + // If we are supposed to override the target triple, do so now. + if (!TargetTriple.empty()) + mod->setTargetTriple(Triple::normalize(TargetTriple)); + TheTriple = Triple(mod->getTargetTriple()); + } else { + TheTriple = Triple(Triple::normalize(TargetTriple)); + } + + if (TheTriple.getTriple().empty()) + TheTriple.setTriple(sys::getDefaultTargetTriple()); + + // Get the target specific parser. + std::string Error; + const Target *TheTarget = TargetRegistry::lookupTarget(MArch, TheTriple, + Error); + if (!TheTarget) { + errs() << argv[0] << ": " << Error; + return 1; + } + + // Package up features to be passed to target/subtarget + std::string FeaturesStr; + if (MAttrs.size()) { + SubtargetFeatures Features; + // @LOCALMOD-BEGIN + // Use the same default attribute settings as libLTO. + // TODO(pdox): Figure out why this isn't done for upstream llc. + Features.getDefaultSubtargetFeatures(TheTriple); + // @LOCALMOD-END + for (unsigned i = 0; i != MAttrs.size(); ++i) + Features.AddFeature(MAttrs[i]); + FeaturesStr = Features.getString(); + } + + CodeGenOpt::Level OLvl = CodeGenOpt::Default; + switch (OptLevel) { + default: + errs() << argv[0] << ": 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; + } + + TargetOptions Options; + Options.LessPreciseFPMADOption = EnableFPMAD; + Options.NoFramePointerElim = DisableFPElim; + Options.NoFramePointerElimNonLeaf = DisableFPElimNonLeaf; + Options.AllowFPOpFusion = FuseFPOps; + Options.UnsafeFPMath = EnableUnsafeFPMath; + Options.NoInfsFPMath = EnableNoInfsFPMath; + Options.NoNaNsFPMath = EnableNoNaNsFPMath; + Options.HonorSignDependentRoundingFPMathOption = + EnableHonorSignDependentRoundingFPMath; + Options.UseSoftFloat = GenerateSoftFloatCalls; + if (FloatABIForCalls != FloatABI::Default) + Options.FloatABIType = FloatABIForCalls; + Options.NoZerosInBSS = DontPlaceZerosInBSS; + Options.GuaranteedTailCallOpt = EnableGuaranteedTailCallOpt; + Options.DisableTailCalls = DisableTailCalls; + Options.StackAlignmentOverride = OverrideStackAlignment; + Options.RealignStack = EnableRealignStack; + Options.TrapFuncName = TrapFuncName; + Options.PositionIndependentExecutable = EnablePIE; + Options.EnableSegmentedStacks = SegmentedStacks; + Options.UseInitArray = UseInitArray; + Options.SSPBufferSize = SSPBufferSize; + + std::auto_ptr<TargetMachine> + target(TheTarget->createTargetMachine(TheTriple.getTriple(), + MCPU, FeaturesStr, Options, + RelocModel, CMModel, OLvl)); + assert(target.get() && "Could not allocate target machine!"); + assert(mod && "Should have exited after outputting help!"); + TargetMachine &Target = *target.get(); + + if (DisableDotLoc) + Target.setMCUseLoc(false); + + if (DisableCFI) + Target.setMCUseCFI(false); + + if (EnableDwarfDirectory) + Target.setMCUseDwarfDirectory(true); + + if (GenerateSoftFloatCalls) + FloatABIForCalls = FloatABI::Soft; + + // Disable .loc support for older OS X versions. + if (TheTriple.isMacOSX() && + TheTriple.isMacOSXVersionLT(10, 6)) + Target.setMCUseLoc(false); + +#if !defined(NACL_SRPC) + // Figure out where we are going to send the output. + OwningPtr<tool_output_file> Out + (GetOutputStream(TheTarget->getName(), TheTriple.getOS(), argv[0])); + if (!Out) return 1; +#endif + + // Build up all of the passes that we want to do to the module. + // @LOCALMOD-BEGIN + OwningPtr<PassManagerBase> PM; + if (LazyBitcode || ReduceMemoryFootprint) + PM.reset(new FunctionPassManager(mod)); + else + PM.reset(new PassManager()); + + // Add the ABI verifier pass before the analysis and code emission passes. + FunctionPass *FunctionVerifyPass = NULL; + if (PNaClABIVerify) { + FunctionVerifyPass = createPNaClABIVerifyFunctionsPass(&ABIErrorReporter); + PM->add(FunctionVerifyPass); + } + // @LOCALMOD-END + + // Add an appropriate TargetLibraryInfo pass for the module's triple. + TargetLibraryInfo *TLI = new TargetLibraryInfo(TheTriple); + if (DisableSimplifyLibCalls) + TLI->disableAllFunctions(); + PM->add(TLI); + + // Add intenal analysis passes from the target machine. + Target.addAnalysisPasses(*PM.get()); + + // Add the target data from the target machine, if it exists, or the module. + if (const DataLayout *TD = Target.getDataLayout()) + PM->add(new DataLayout(*TD)); + else + PM->add(new DataLayout(mod)); + + // Override default to generate verbose assembly. + Target.setAsmVerbosityDefault(true); + + if (RelaxAll) { + if (FileType != TargetMachine::CGFT_ObjectFile) + errs() << argv[0] + << ": warning: ignoring -mc-relax-all because filetype != obj"; + else + Target.setMCRelaxAll(true); + } + + +#if defined __native_client__ && defined(NACL_SRPC) + { + raw_fd_ostream ROS(GetObjectFileFD(), true); + ROS.SetBufferSize(1 << 20); + formatted_raw_ostream FOS(ROS); + + // Ask the target to add backend passes as necessary. + if (Target.addPassesToEmitFile(*PM, FOS, FileType, NoVerify)) { + errs() << argv[0] << ": target does not support generation of this" + << " file type!\n"; + return 1; + } + + if (LazyBitcode || ReduceMemoryFootprint) { + FunctionPassManager* P = static_cast<FunctionPassManager*>(PM.get()); + P->doInitialization(); + for (Module::iterator I = mod->begin(), E = mod->end(); I != E; ++I) { + P->run(*I); + CheckABIVerifyErrors(ABIErrorReporter, "Function " + I->getName()); + if (ReduceMemoryFootprint) { + I->Dematerialize(); + } + } + P->doFinalization(); + } else { + static_cast<PassManager*>(PM.get())->run(*mod); + } + FOS.flush(); + ROS.flush(); + } +#else + + { + formatted_raw_ostream FOS(Out->os()); + + AnalysisID StartAfterID = 0; + AnalysisID StopAfterID = 0; + const PassRegistry *PR = PassRegistry::getPassRegistry(); + if (!StartAfter.empty()) { + const PassInfo *PI = PR->getPassInfo(StartAfter); + if (!PI) { + errs() << argv[0] << ": start-after pass is not registered.\n"; + return 1; + } + StartAfterID = PI->getTypeInfo(); + } + if (!StopAfter.empty()) { + const PassInfo *PI = PR->getPassInfo(StopAfter); + if (!PI) { + errs() << argv[0] << ": stop-after pass is not registered.\n"; + return 1; + } + StopAfterID = PI->getTypeInfo(); + } + + // Ask the target to add backend passes as necessary. + if (Target.addPassesToEmitFile(*PM, FOS, FileType, NoVerify, + StartAfterID, StopAfterID)) { + errs() << argv[0] << ": target does not support generation of this" + << " file type!\n"; + return 1; + } + + // Before executing passes, print the final values of the LLVM options. + cl::PrintOptionValues(); + + if (LazyBitcode || ReduceMemoryFootprint) { + FunctionPassManager *P = static_cast<FunctionPassManager*>(PM.get()); + P->doInitialization(); + for (Module::iterator I = mod->begin(), E = mod->end(); I != E; ++I) { + P->run(*I); + CheckABIVerifyErrors(ABIErrorReporter, "Function " + I->getName()); + if (ReduceMemoryFootprint) { + I->Dematerialize(); + } + } + P->doFinalization(); + } else { + static_cast<PassManager*>(PM.get())->run(*mod); + } + } + + // Declare success. + Out->keep(); +#endif + + return 0; +} + +#if !defined(NACL_SRPC) +int +main (int argc, char **argv) { + return llc_main(argc, argv); +} +#else +// main() is in nacl_file.cpp. +#endif |