aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEli Bendersky <eliben@chromium.org>2013-05-15 11:13:43 -0700
committerEli Bendersky <eliben@chromium.org>2013-05-15 11:13:43 -0700
commit28aeda400274e40253573e51cba1b66ca9099270 (patch)
tree575ad6c52484c2d181edd590f0bac00b367aa13f
parentc5d198304d851d6930cfe0cf3c719624109c4c95 (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.txt1
-rw-r--r--tools/LLVMBuild.txt2
-rw-r--r--tools/Makefile2
-rw-r--r--tools/pnacl-llc/CMakeLists.txt8
-rw-r--r--tools/pnacl-llc/LLVMBuild.txt22
-rw-r--r--tools/pnacl-llc/Makefile15
-rw-r--r--tools/pnacl-llc/SRPCStreamer.cpp142
-rw-r--r--tools/pnacl-llc/SRPCStreamer.h117
-rw-r--r--tools/pnacl-llc/nacl_file.cpp422
-rw-r--r--tools/pnacl-llc/pnacl-llc.cpp585
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