aboutsummaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/CMakeLists.txt6
-rw-r--r--tools/LLVMBuild.txt2
-rw-r--r--tools/Makefile7
-rw-r--r--tools/bc-wrap/CMakeLists.txt5
-rw-r--r--tools/bc-wrap/LLVMBuild.txt22
-rw-r--r--tools/bc-wrap/Makefile20
-rw-r--r--tools/bc-wrap/bc_wrap.cpp123
-rw-r--r--tools/gold/Makefile4
-rw-r--r--tools/gold/gold-plugin.cpp224
-rw-r--r--tools/llvm-as/llvm-as.cpp5
-rw-r--r--tools/llvm-dis/CMakeLists.txt2
-rw-r--r--tools/llvm-dis/LLVMBuild.txt2
-rw-r--r--tools/llvm-dis/Makefile2
-rw-r--r--tools/llvm-dis/llvm-dis.cpp47
-rw-r--r--tools/llvm-extract/llvm-extract.cpp48
-rw-r--r--tools/llvm-link/CMakeLists.txt2
-rw-r--r--tools/llvm-mc/llvm-mc.cpp6
-rw-r--r--tools/llvm-nm/CMakeLists.txt2
-rw-r--r--tools/llvm-nm/LLVMBuild.txt2
-rw-r--r--tools/llvm-nm/Makefile2
-rw-r--r--tools/llvm-nm/llvm-nm.cpp29
-rw-r--r--tools/lto/LTOCodeGenerator.cpp140
-rw-r--r--tools/lto/LTOCodeGenerator.h19
-rw-r--r--tools/lto/LTOModule.cpp43
-rw-r--r--tools/lto/LTOModule.h8
-rw-r--r--tools/lto/Makefile8
-rw-r--r--tools/lto/lto.cpp141
-rw-r--r--tools/lto/lto.exports17
-rw-r--r--tools/opt/CMakeLists.txt2
-rw-r--r--tools/opt/LLVMBuild.txt2
-rw-r--r--tools/opt/Makefile2
-rw-r--r--tools/opt/opt.cpp100
-rw-r--r--tools/pnacl-abicheck/CMakeLists.txt5
-rw-r--r--tools/pnacl-abicheck/LLVMBuild.txt22
-rw-r--r--tools/pnacl-abicheck/Makefile16
-rw-r--r--tools/pnacl-abicheck/pnacl-abicheck.cpp87
-rw-r--r--tools/pnacl-bcanalyzer/CMakeLists.txt5
-rw-r--r--tools/pnacl-bcanalyzer/LLVMBuild.txt22
-rw-r--r--tools/pnacl-bcanalyzer/Makefile17
-rw-r--r--tools/pnacl-bcanalyzer/pnacl-bcanalyzer.cpp641
-rw-r--r--tools/pnacl-freeze/CMakeLists.txt5
-rw-r--r--tools/pnacl-freeze/LLVMBuild.txt16
-rw-r--r--tools/pnacl-freeze/Makefile17
-rw-r--r--tools/pnacl-freeze/pnacl-freeze.cpp95
-rw-r--r--tools/pnacl-llc/CMakeLists.txt9
-rw-r--r--tools/pnacl-llc/LLVMBuild.txt22
-rw-r--r--tools/pnacl-llc/Makefile16
-rw-r--r--tools/pnacl-llc/SRPCStreamer.cpp142
-rw-r--r--tools/pnacl-llc/SRPCStreamer.h117
-rw-r--r--tools/pnacl-llc/nacl_file.cpp399
-rw-r--r--tools/pnacl-llc/pnacl-llc.cpp563
-rw-r--r--tools/pnacl-thaw/CMakeLists.txt5
-rw-r--r--tools/pnacl-thaw/LLVMBuild.txt16
-rw-r--r--tools/pnacl-thaw/Makefile17
-rw-r--r--tools/pnacl-thaw/pnacl-thaw.cpp96
-rw-r--r--tools/pso-stub/CMakeLists.txt5
-rw-r--r--tools/pso-stub/LLVMBuild.txt22
-rw-r--r--tools/pso-stub/Makefile18
-rw-r--r--tools/pso-stub/pso-stub.cpp309
59 files changed, 3719 insertions, 29 deletions
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index 6b7c884516..e32aef3169 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)
@@ -42,6 +43,11 @@ add_subdirectory(llvm-stress)
add_subdirectory(llvm-mcmarkup)
add_subdirectory(llvm-symbolizer)
+add_subdirectory(pnacl-abicheck)
+add_subdirectory(pnacl-bcanalyzer)
+add_subdirectory(pnacl-freeze)
+add_subdirectory(pnacl-thaw)
+add_subdirectory(bc-wrap)
add_subdirectory(obj2yaml)
add_subdirectory(yaml2obj)
diff --git a/tools/LLVMBuild.txt b/tools/LLVMBuild.txt
index 25aa177b35..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
+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 eaf9ed3577..b94f08f81c 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -28,14 +28,15 @@ 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 \
llvm-diff macho-dump llvm-objdump llvm-readobj \
llvm-rtdyld llvm-dwarfdump llvm-cov \
- llvm-size llvm-stress llvm-mcmarkup \
- llvm-symbolizer obj2yaml yaml2obj
+ llvm-size llvm-stress llvm-mcmarkup bc-wrap pso-stub \
+ llvm-symbolizer pnacl-abicheck pnacl-bcanalyzer pnacl-freeze \
+ pnacl-thaw obj2yaml yaml2obj
# If Intel JIT Events support is configured, build an extra tool to test it.
ifeq ($(USE_INTEL_JITEVENTS), 1)
diff --git a/tools/bc-wrap/CMakeLists.txt b/tools/bc-wrap/CMakeLists.txt
new file mode 100644
index 0000000000..7d8ce4fc11
--- /dev/null
+++ b/tools/bc-wrap/CMakeLists.txt
@@ -0,0 +1,5 @@
+set(LLVM_LINK_COMPONENTS wrap support )
+
+add_llvm_tool(bc-wrap
+ bc_wrap.cpp
+ ) \ No newline at end of file
diff --git a/tools/bc-wrap/LLVMBuild.txt b/tools/bc-wrap/LLVMBuild.txt
new file mode 100644
index 0000000000..a91f77625e
--- /dev/null
+++ b/tools/bc-wrap/LLVMBuild.txt
@@ -0,0 +1,22 @@
+;===- ./tools/bc-wrap/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 = bc-wrap
+parent = Tools
+required_libraries = Wrap Support
diff --git a/tools/bc-wrap/Makefile b/tools/bc-wrap/Makefile
new file mode 100644
index 0000000000..dccff2ecde
--- /dev/null
+++ b/tools/bc-wrap/Makefile
@@ -0,0 +1,20 @@
+#===- tools/bc-wrap/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 = bc-wrap
+
+# Include this here so we can get the configuration of the targets
+# that have been configured for construction. We have to do this
+# early so we can set up LINK_COMPONENTS before including Makefile.rules
+include $(LEVEL)/Makefile.config
+
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) Wrap
+
+include $(LLVM_SRC_ROOT)/Makefile.rules
diff --git a/tools/bc-wrap/bc_wrap.cpp b/tools/bc-wrap/bc_wrap.cpp
new file mode 100644
index 0000000000..5311f714ee
--- /dev/null
+++ b/tools/bc-wrap/bc_wrap.cpp
@@ -0,0 +1,123 @@
+/* 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.
+ */
+/*
+ * Utility to wrap a .bc file, using LLVM standard+ custom headers.
+ */
+
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Wrap/bitcode_wrapperer.h"
+#include "llvm/Wrap/file_wrapper_input.h"
+#include "llvm/Wrap/file_wrapper_output.h"
+
+#include <ctype.h>
+#include <string.h>
+
+using namespace llvm;
+
+static cl::opt<std::string>
+InputFilename(cl::Positional, cl::desc("<input file>"), cl::Required);
+
+static cl::opt<std::string>
+OutputFilename("o", cl::desc("<output file>"));
+
+static cl::opt<bool> UnwrapFlag("u",
+ cl::desc("unwrap rather than wrap the file"),
+ cl::init(false));
+
+static cl::opt<bool> VerboseFlag("v",
+ cl::desc("print verbose header information"),
+ cl::init(false));
+
+static cl::opt<bool> DryRunFlag("n",
+ cl::desc("Dry run (implies -v)"),
+ cl::init(false));
+
+// Accept the hash on the command line to avoid having to include sha1
+// library with the LLVM code
+static cl::opt<std::string> BitcodeHash("hash",
+ cl::desc("Hash of bitcode (ignored if -u is given)"));
+
+const int kMaxBinaryHashLen = 32;
+
+// Convert ASCII hex hash to binary hash. return buffer and length.
+// The caller must free the returned buffer.
+static uint8_t* ParseBitcodeHash(int* len) {
+ if (BitcodeHash.size() > kMaxBinaryHashLen * 2 ||
+ BitcodeHash.size() % 2) return NULL;
+ *len = BitcodeHash.size() / 2;
+ uint8_t* buf = new uint8_t[*len];
+ const char* arg = BitcodeHash.data();
+ for (size_t i = 0; i < BitcodeHash.size() / 2; i++) {
+ unsigned int r; // glibc has %hhx but it's nonstandard
+ if (!isxdigit(*(arg + 2 * i + 1)) || // sscanf ignores trailing junk
+ !sscanf(arg + 2 * i, "%2x", &r) ||
+ r > std::numeric_limits<uint8_t>::max()) {
+ delete [] buf;
+ return NULL;
+ }
+ buf[i] = static_cast<uint8_t>(r);
+ }
+ return buf;
+}
+
+int main(const int argc, const char* argv[]) {
+ bool success = true;
+ cl::ParseCommandLineOptions(argc, argv, "bitcode wrapper/unwrapper\n");
+ if (OutputFilename == "") {
+ // Default to input file = output file. The cl lib doesn't seem to
+ // directly support initializing one opt from another.
+ OutputFilename = InputFilename;
+ }
+ if (DryRunFlag) VerboseFlag = true;
+ sys::fs::file_status outfile_status;
+ std::string outfile_temp;
+ outfile_temp = std::string(OutputFilename) + ".temp";
+ if (UnwrapFlag) {
+ FileWrapperInput inbc(InputFilename);
+ FileWrapperOutput outbc(outfile_temp);
+ BitcodeWrapperer wrapperer(&inbc, &outbc);
+ if (wrapperer.IsInputBitcodeWrapper()) {
+ if (VerboseFlag) {
+ fprintf(stderr, "Headers read from infile:\n");
+ wrapperer.PrintWrapperHeader();
+ }
+ if (DryRunFlag)
+ return 0;
+ success = wrapperer.GenerateRawBitcodeFile();
+ }
+ } else {
+ FileWrapperInput inbc(InputFilename);
+ FileWrapperOutput outbc(outfile_temp);
+ BitcodeWrapperer wrapperer(&inbc, &outbc);
+ if (BitcodeHash.size()) {
+ // SHA-2 hash is 256 bit
+ int hash_len;
+ uint8_t* buf = ParseBitcodeHash(&hash_len);
+ if (!buf) {
+ fprintf(stderr, "Bitcode hash must be a hex string <= 64 chars.\n");
+ exit(1);
+ }
+ BCHeaderField hash(BCHeaderField::kBitcodeHash, hash_len, buf);
+ wrapperer.AddHeaderField(&hash);
+ }
+ if (VerboseFlag) {
+ fprintf(stderr, "Headers generated:\n");
+ wrapperer.PrintWrapperHeader();
+ }
+ if (DryRunFlag)
+ return 0;
+ success = wrapperer.GenerateWrappedBitcodeFile();
+ }
+ error_code ec;
+ if ((ec = sys::fs::rename(outfile_temp, OutputFilename))) {
+ fprintf(stderr, "Could not rename temporary: %s\n", ec.message().c_str());
+ success = false;
+ }
+ if (success) return 0;
+ fprintf(stderr, "error: Unable to generate a proper %s bitcode file!\n",
+ (UnwrapFlag ? "unwrapped" : "wrapped"));
+ return 1;
+}
diff --git a/tools/gold/Makefile b/tools/gold/Makefile
index 496e31cc39..31812e1f8c 100644
--- a/tools/gold/Makefile
+++ b/tools/gold/Makefile
@@ -14,6 +14,10 @@ LINK_LIBS_IN_SHARED := 1
SHARED_LIBRARY := 1
LOADABLE_MODULE := 1
+# @LOCALMOD: this forces to appear -lLTO *after* the object file
+# on the linkline. This is necessary for linking on ubuntu precise.
+# Otherwise LLVMgold.so will not have a dt_needed entry for LTO
+EXTRA_LIBS := -lLTO
EXPORTED_SYMBOL_FILE = $(PROJ_SRC_DIR)/gold.exports
# Include this here so we can get the configuration of the targets
diff --git a/tools/gold/gold-plugin.cpp b/tools/gold/gold-plugin.cpp
index 40f5fd6086..1e96762d10 100644
--- a/tools/gold/gold-plugin.cpp
+++ b/tools/gold/gold-plugin.cpp
@@ -52,6 +52,25 @@ namespace {
ld_plugin_set_extra_library_path set_extra_library_path = NULL;
ld_plugin_get_view get_view = NULL;
ld_plugin_message message = discard_message;
+ // @LOCALMOD-BEGIN
+ // REL, DYN, or EXEC
+ ld_plugin_output_file_type linker_output;
+
+ // Callback for getting link soname from gold
+ ld_plugin_get_output_soname get_output_soname = NULL;
+
+ // Callback for getting needed libraries from gold
+ ld_plugin_get_needed get_needed = NULL;
+
+ // Callback for getting number of needed library from gold
+ ld_plugin_get_num_needed get_num_needed = NULL;
+
+ // Callback for getting the number of --wrap'd symbols.
+ ld_plugin_get_num_wrapped get_num_wrapped = NULL;
+
+ // Callback for getting the name of a wrapped symbol.
+ ld_plugin_get_wrapped get_wrapped = NULL;
+ // @LOCALMOD-END
int api_version = 0;
int gold_version = 0;
@@ -59,11 +78,17 @@ namespace {
struct claimed_file {
void *handle;
std::vector<ld_plugin_symbol> syms;
+ bool is_linked_in; // @LOCALMOD
};
lto_codegen_model output_type = LTO_CODEGEN_PIC_MODEL_STATIC;
std::string output_name = "";
std::list<claimed_file> Modules;
+
+ // @LOCALMOD-BEGIN
+ std::vector<std::string> DepLibs;
+ // @LOCALMOD-END
+
std::vector<sys::Path> Cleanup;
lto_code_gen_t code_gen = NULL;
}
@@ -71,6 +96,7 @@ namespace {
namespace options {
enum generate_bc { BC_NO, BC_ALSO, BC_ONLY };
static bool generate_api_file = false;
+ static bool gather_then_link = true; // @LOCALMOD
static generate_bc generate_bc_file = BC_NO;
static std::string bc_path;
static std::string obj_path;
@@ -100,6 +126,10 @@ namespace options {
triple = opt.substr(strlen("mtriple="));
} else if (opt.startswith("obj-path=")) {
obj_path = opt.substr(strlen("obj-path="));
+ // @LOCALMOD-BEGIN
+ } else if (opt == "no-gather-then-link") {
+ gather_then_link = false;
+ // @LOCALMOD-END
} else if (opt == "emit-llvm") {
generate_bc_file = BC_ONLY;
} else if (opt == "also-emit-llvm") {
@@ -120,6 +150,18 @@ namespace options {
}
}
+// @LOCALMOD-BEGIN
+static const char *get_basename(const char *path) {
+ if (path == NULL)
+ return NULL;
+ const char *slash = strrchr(path, '/');
+ if (slash)
+ return slash + 1;
+
+ return path;
+}
+// @LOCALMOD-END
+
static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file,
int *claimed);
static ld_plugin_status all_symbols_read_hook(void);
@@ -147,6 +189,10 @@ ld_plugin_status onload(ld_plugin_tv *tv) {
output_name = tv->tv_u.tv_string;
break;
case LDPT_LINKER_OUTPUT:
+ // @LOCALMOD-BEGIN
+ linker_output =
+ static_cast<ld_plugin_output_file_type>(tv->tv_u.tv_val);
+ // @LOCALMOD-END
switch (tv->tv_u.tv_val) {
case LDPO_REL: // .o
case LDPO_DYN: // .so
@@ -210,7 +256,23 @@ ld_plugin_status onload(ld_plugin_tv *tv) {
break;
case LDPT_GET_VIEW:
get_view = tv->tv_u.tv_get_view;
+ // @LOCALMOD-BEGIN
+ case LDPT_GET_OUTPUT_SONAME:
+ get_output_soname = tv->tv_u.tv_get_output_soname;
break;
+ case LDPT_GET_NEEDED:
+ get_needed = tv->tv_u.tv_get_needed;
+ break;
+ case LDPT_GET_NUM_NEEDED:
+ get_num_needed = tv->tv_u.tv_get_num_needed;
+ break;
+ case LDPT_GET_WRAPPED:
+ get_wrapped = tv->tv_u.tv_get_wrapped;
+ break;
+ case LDPT_GET_NUM_WRAPPED:
+ get_num_wrapped = tv->tv_u.tv_get_num_wrapped;
+ break;
+ // @LOCALMOD-END
case LDPT_MESSAGE:
message = tv->tv_u.tv_message;
break;
@@ -228,6 +290,24 @@ ld_plugin_status onload(ld_plugin_tv *tv) {
return LDPS_ERR;
}
+ // @LOCALMOD-BEGIN
+ // Parse extra command-line options
+ // Although lto_codegen provides a way to parse command-line arguments,
+ // we need the arguments to be parsed and applied before LTOModules are
+ // even created. In particular, this is needed because the
+ // "-add-nacl-read-tp-dependency" flag affects how modules are created.
+ if (!options::extra.empty()) {
+ for (std::vector<std::string>::iterator it = options::extra.begin();
+ it != options::extra.end(); ++it) {
+ lto_add_command_line_option((*it).c_str());
+ }
+ lto_parse_command_line_options();
+ // We clear the options so that they don't get parsed again in
+ // lto_codegen_debug_options.
+ options::extra.clear();
+ }
+ // @LOCALMOD-END
+
return LDPS_OK;
}
@@ -294,7 +374,21 @@ static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file,
ld_plugin_symbol &sym = cf.syms.back();
sym.name = const_cast<char *>(lto_module_get_symbol_name(M, i));
sym.name = strdup(sym.name);
+ // @LOCALMOD-BEGIN
+ // Localmods have disabled the use of the 'version' field for passing
+ // version information to Gold. Instead, the version is now transmitted as
+ // part of the 'name' field, which has the form "sym@VER" or "sym@@VER".
+ // This is nicer because it communicates one extra bit of information (@@
+ // marks the default version), and allows us to access the real symbol
+ // name in all_symbols_read.
+
+ // These fields are set by Gold to communicate the updated version info
+ // to the plugin. They are used in all_symbols_read_hook().
+ // Initialize them for predictability.
sym.version = NULL;
+ sym.is_default = false;
+ sym.dynfile = NULL;
+ // @LOCALMOD-END
int scope = attrs & LTO_SYMBOL_SCOPE_MASK;
switch (scope) {
@@ -343,18 +437,45 @@ static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file,
}
cf.syms.reserve(cf.syms.size());
+ // @LOCALMOD-BEGIN
+ bool is_shared =
+ (lto_module_get_output_format(M) == LTO_OUTPUT_FORMAT_SHARED);
+ const char* soname = lto_module_get_soname(M);
+ if (soname[0] == '\0')
+ soname = NULL;
+ // @LOCALMOD-END
if (!cf.syms.empty()) {
- if ((*add_symbols)(cf.handle, cf.syms.size(), &cf.syms[0]) != LDPS_OK) {
+ if ((*add_symbols)(cf.handle, cf.syms.size(), &cf.syms[0],
+ is_shared, soname) != LDPS_OK) { // @LOCALMOD
(*message)(LDPL_ERROR, "Unable to add symbols!");
return LDPS_ERR;
}
}
- if (code_gen)
- lto_codegen_add_module(code_gen, M);
+ // @LOCALMOD-BEGIN
+ // Do not merge the module if it's a PSO.
+ // If the PSO's soname is set, add it to DepLibs.
+ cf.is_linked_in = false;
+ if (code_gen) {
+ if (is_shared) {
+ if (soname && strlen(soname) > 0) {
+ DepLibs.push_back(soname);
+ }
+ } else {
+ if (options::gather_then_link) {
+ lto_codegen_gather_module_for_link(code_gen, M);
+ } else {
+ lto_codegen_add_module(code_gen, M);
+ }
+ cf.is_linked_in = true;
+ }
+ }
- lto_module_dispose(M);
+ // With gather_then_link, the modules are disposed when linking.
+ if (!options::gather_then_link)
+ lto_module_dispose(M);
+ // @LOCALMOD-END
return LDPS_OK;
}
@@ -367,6 +488,12 @@ static ld_plugin_status all_symbols_read_hook(void) {
std::ofstream api_file;
assert(code_gen);
+ // @LOCALMOD-BEGIN
+ if (options::gather_then_link) {
+ lto_codegen_link_gathered_modules_and_dispose(code_gen);
+ }
+ // @LOCALMOD-END
+
if (options::generate_api_file) {
api_file.open("apifile.txt", std::ofstream::out | std::ofstream::trunc);
if (!api_file.is_open()) {
@@ -381,12 +508,45 @@ static ld_plugin_status all_symbols_read_hook(void) {
continue;
(*get_symbols)(I->handle, I->syms.size(), &I->syms[0]);
for (unsigned i = 0, e = I->syms.size(); i != e; i++) {
+ // @LOCALMOD-BEGIN
+ // Don't process the symbols inside a dynamic object.
+ if (!I->is_linked_in)
+ continue;
+ // @LOCALMOD-END
+
if (I->syms[i].resolution == LDPR_PREVAILING_DEF) {
+ // @LOCALMOD-BEGIN
+ // Set the symbol version in the module.
+ if (linker_output != LDPO_REL && I->syms[i].version) {
+ // NOTE: This may change the name of the symbol, so it must happen
+ // before the call to lto_codegen_add_must_preserve_symbols() below.
+ I->syms[i].name = const_cast<char *>(
+ lto_codegen_set_symbol_def_version(code_gen, I->syms[i].name,
+ I->syms[i].version,
+ I->syms[i].is_default));
+ }
lto_codegen_add_must_preserve_symbol(code_gen, I->syms[i].name);
+ // @LOCALMOD-END
if (options::generate_api_file)
api_file << I->syms[i].name << "\n";
}
+ // @LOCALMOD-BEGIN
+ else if (linker_output != LDPO_REL &&
+ (I->syms[i].resolution == LDPR_RESOLVED_DYN ||
+ I->syms[i].resolution == LDPR_UNDEF)) {
+ // This symbol is provided by an external object.
+ // Set the version and source dynamic file for it.
+ const char *ver = I->syms[i].version;
+ const char *dynfile = I->syms[i].dynfile;
+ dynfile = get_basename(dynfile);
+ // NOTE: This may change the name of the symbol.
+ I->syms[i].name = const_cast<char *>(
+ lto_codegen_set_symbol_needed(code_gen, I->syms[i].name,
+ ver ? ver : "",
+ dynfile ? dynfile : ""));
+ }
+ // @LOCALMOD-END
}
}
@@ -398,6 +558,11 @@ static ld_plugin_status all_symbols_read_hook(void) {
if (!options::mcpu.empty())
lto_codegen_set_cpu(code_gen, options::mcpu.c_str());
+ // @LOCALMOD-BEGIN (COMMENT)
+ // "extra" will always be empty below, because we process the extra
+ // options earlier, at the end of onload().
+ // @LOCALMOD-END
+
// Pass through extra options to the code generator.
if (!options::extra.empty()) {
for (std::vector<std::string>::iterator it = options::extra.begin();
@@ -406,6 +571,57 @@ static ld_plugin_status all_symbols_read_hook(void) {
}
}
+ // @LOCALMOD-BEGIN
+ // Store the linker output format into the bitcode.
+ lto_output_format format;
+ switch (linker_output) {
+ case LDPO_REL:
+ format = LTO_OUTPUT_FORMAT_OBJECT;
+ break;
+ case LDPO_DYN:
+ format = LTO_OUTPUT_FORMAT_SHARED;
+ break;
+ case LDPO_EXEC:
+ format = LTO_OUTPUT_FORMAT_EXEC;
+ break;
+ default:
+ (*message)(LDPL_FATAL, "Unknown linker output format (gold-plugin)");
+ abort();
+ break;
+ }
+ lto_codegen_set_merged_module_output_format(code_gen, format);
+ // @LOCALMOD-END
+
+ // @LOCALMOD-BEGIN
+ // For -shared linking, store the soname into the bitcode.
+ if (linker_output == LDPO_DYN) {
+ const char *soname = (*get_output_soname)();
+ lto_codegen_set_merged_module_soname(code_gen, soname);
+ }
+ // @LOCALMOD-END
+
+ // @LOCALMOD-BEGIN
+ // Add the needed libraries to the bitcode.
+ unsigned int num_needed = (*get_num_needed)();
+ for (unsigned i=0; i < num_needed; ++i) {
+ const char *soname = (*get_needed)(i);
+ soname = get_basename(soname);
+ lto_codegen_add_merged_module_library_dep(code_gen, soname);
+ }
+ for (std::vector<std::string>::iterator I = DepLibs.begin(),
+ E = DepLibs.end(); I != E; ++I) {
+ lto_codegen_add_merged_module_library_dep(code_gen, I->c_str());
+ }
+ // @LOCALMOD-END
+
+ // @LOCALMOD-BEGIN
+ // Perform symbol wrapping.
+ unsigned int num_wrapped = (*get_num_wrapped)();
+ for (unsigned i=0; i < num_wrapped; ++i) {
+ const char *sym = (*get_wrapped)(i);
+ lto_codegen_wrap_symbol_in_merged_module(code_gen, sym);
+ }
+ // @LOCALMOD-END
if (options::generate_bc_file != options::BC_NO) {
std::string path;
if (options::generate_bc_file == options::BC_ONLY)
diff --git a/tools/llvm-as/llvm-as.cpp b/tools/llvm-as/llvm-as.cpp
index d6f191961d..bb9afce271 100644
--- a/tools/llvm-as/llvm-as.cpp
+++ b/tools/llvm-as/llvm-as.cpp
@@ -77,8 +77,11 @@ static void WriteOutputFile(const Module *M) {
exit(1);
}
- if (Force || !CheckBitcodeOutputToConsole(Out->os(), true))
+ // @LOCALMOD-BEGIN
+ if (Force || !CheckBitcodeOutputToConsole(Out->os(), true)) {
WriteBitcodeToFile(M, Out->os());
+ }
+ // @LOCALMOD-END
// Declare success.
Out->keep();
diff --git a/tools/llvm-dis/CMakeLists.txt b/tools/llvm-dis/CMakeLists.txt
index 9f12ecb666..d9883a2147 100644
--- a/tools/llvm-dis/CMakeLists.txt
+++ b/tools/llvm-dis/CMakeLists.txt
@@ -1,4 +1,4 @@
-set(LLVM_LINK_COMPONENTS bitreader analysis)
+set(LLVM_LINK_COMPONENTS bitreader naclbitreader analysis)
add_llvm_tool(llvm-dis
llvm-dis.cpp
diff --git a/tools/llvm-dis/LLVMBuild.txt b/tools/llvm-dis/LLVMBuild.txt
index 4525010c1f..cf1cbf7a40 100644
--- a/tools/llvm-dis/LLVMBuild.txt
+++ b/tools/llvm-dis/LLVMBuild.txt
@@ -19,4 +19,4 @@
type = Tool
name = llvm-dis
parent = Tools
-required_libraries = Analysis BitReader
+required_libraries = Analysis BitReader NaClBitReader
diff --git a/tools/llvm-dis/Makefile b/tools/llvm-dis/Makefile
index aeeeed0d68..0719006a15 100644
--- a/tools/llvm-dis/Makefile
+++ b/tools/llvm-dis/Makefile
@@ -9,7 +9,7 @@
LEVEL := ../..
TOOLNAME := llvm-dis
-LINK_COMPONENTS := bitreader analysis
+LINK_COMPONENTS := bitreader naclbitreader analysis
# This tool has no plugins, optimize startup time.
TOOL_NO_EXPORTS := 1
diff --git a/tools/llvm-dis/llvm-dis.cpp b/tools/llvm-dis/llvm-dis.cpp
index 067955e5cc..db9ca40f45 100644
--- a/tools/llvm-dis/llvm-dis.cpp
+++ b/tools/llvm-dis/llvm-dis.cpp
@@ -19,10 +19,12 @@
#include "llvm/IR/LLVMContext.h"
#include "llvm/Assembly/AssemblyAnnotationWriter.h"
#include "llvm/Bitcode/ReaderWriter.h"
+#include "llvm/Bitcode/NaCl/NaClReaderWriter.h" // @LOCALMOD
#include "llvm/DebugInfo.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"
+#include "llvm/IRReader/IRReader.h" // @LOCALMOD
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/DataStream.h"
#include "llvm/Support/FormattedStream.h"
@@ -51,6 +53,23 @@ static cl::opt<bool>
ShowAnnotations("show-annotations",
cl::desc("Add informational comments to the .ll file"));
+// @LOCALMOD-BEGIN
+// Print bitcode metadata only, in text format.
+// (includes output format, soname, and dependencies).
+static cl::opt<bool>
+DumpMetadata("dump-metadata", cl::desc("Dump bitcode metadata"));
+
+static cl::opt<NaClFileFormat>
+InputFileFormat(
+ "bitcode-format",
+ cl::desc("Define format of input bitcode file:"),
+ cl::values(
+ clEnumValN(LLVMFormat, "llvm", "LLVM bitcode file (default)"),
+ clEnumValN(PNaClFormat, "pnacl", "PNaCl bitcode file"),
+ clEnumValEnd),
+ cl::init(LLVMFormat));
+// @LOCALMOD-END
+
namespace {
static void printDebugLoc(const DebugLoc &DL, formatted_raw_ostream &OS) {
@@ -133,8 +152,22 @@ int main(int argc, char **argv) {
DisplayFilename = "<stdin>";
else
DisplayFilename = InputFilename;
- M.reset(getStreamedBitcodeModule(DisplayFilename, streamer, Context,
- &ErrorMessage));
+
+ // @LOCALMOD-BEGIN
+ switch (InputFileFormat) {
+ case LLVMFormat:
+ M.reset(getStreamedBitcodeModule(DisplayFilename, streamer, Context,
+ &ErrorMessage));
+ break;
+ case PNaClFormat:
+ M.reset(getNaClStreamedBitcodeModule(DisplayFilename, streamer, Context,
+ &ErrorMessage));
+ break;
+ default:
+ ErrorMessage = "Don't understand specified bitcode format";
+ break;
+ }
+ // @LOCALMOD-END
if(M.get() != 0 && M->MaterializeAllPermanently(&ErrorMessage)) {
M.reset();
}
@@ -154,7 +187,7 @@ int main(int argc, char **argv) {
OutputFilename = "-";
if (OutputFilename.empty()) { // Unspecified output, infer it.
- if (InputFilename == "-") {
+ if (InputFilename == "-" || DumpMetadata) { // @LOCALMOD
OutputFilename = "-";
} else {
const std::string &IFN = InputFilename;
@@ -176,6 +209,14 @@ int main(int argc, char **argv) {
return 1;
}
+ // @LOCALMOD-BEGIN
+ if (DumpMetadata) {
+ M->dumpMeta(Out->os());
+ Out->keep();
+ return 0;
+ }
+ // @LOCALMOD-END
+
OwningPtr<AssemblyAnnotationWriter> Annotator;
if (ShowAnnotations)
Annotator.reset(new CommentWriter());
diff --git a/tools/llvm-extract/llvm-extract.cpp b/tools/llvm-extract/llvm-extract.cpp
index 2f45b4eae5..8108996996 100644
--- a/tools/llvm-extract/llvm-extract.cpp
+++ b/tools/llvm-extract/llvm-extract.cpp
@@ -22,6 +22,8 @@
#include "llvm/IRReader/IRReader.h"
#include "llvm/PassManager.h"
#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h" // @LOCALMOD
+#include "llvm/Support/IRReader.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Regex.h"
@@ -48,6 +50,18 @@ Force("f", cl::desc("Enable binary output on terminals"));
static cl::opt<bool>
DeleteFn("delete", cl::desc("Delete specified Globals from Module"));
+// @LOCALMOD-BEGIN
+static cl::opt<unsigned>
+Divisor("divisor",
+ cl::init(0),
+ cl::desc("select GV by position (pos % divisor = remainder "));
+
+static cl::opt<unsigned>
+Remainder("remainder",
+ cl::init(0),
+ cl::desc("select GV by position (pos % divisor = remainder "));
+// @LOCALMOD-END
+
// ExtractFuncs - The functions to extract from the module.
static cl::list<std::string>
ExtractFuncs("func", cl::desc("Specify function to extract"),
@@ -179,6 +193,24 @@ int main(int argc, char **argv) {
}
}
+ // @LOCALMOD-BEGIN
+ // Extract globals via modulo operation.
+ size_t count_globals = 0;
+ if (Divisor != 0) {
+ size_t pos = 0;
+ for (Module::global_iterator GV = M->global_begin(), E = M->global_end();
+ GV != E;
+ GV++, pos++) {
+ if (pos % Divisor == Remainder) {
+ GVs.insert(&*GV);
+ }
+ }
+ dbgs() << "total globals: " << pos << "\n";
+ count_globals = GVs.size();
+ dbgs() << "selected globals: " << count_globals << "\n";
+ }
+ // @LOCALMOD-END
+
// Figure out which functions we should extract.
for (size_t i = 0, e = ExtractFuncs.size(); i != e; ++i) {
GlobalValue *GV = M->getFunction(ExtractFuncs[i]);
@@ -213,6 +245,22 @@ int main(int argc, char **argv) {
}
}
+ // @LOCALMOD-BEGIN
+ // Extract functions via modulo operation.
+ if (Divisor != 0) {
+ size_t pos = 0;
+ for (Module::iterator F = M->begin(), E = M->end();
+ F != E;
+ F++, pos++) {
+ if (pos % Divisor == Remainder) {
+ GVs.insert(&*F);
+ }
+ }
+ dbgs() << "total functions: " << pos << "\n";
+ dbgs() << "selected functions: " << GVs.size() - count_globals << "\n";
+ }
+ // @LOCALMOD-END
+
// Materialize requisite global values.
if (!DeleteFn)
for (size_t i = 0, e = GVs.size(); i != e; ++i) {
diff --git a/tools/llvm-link/CMakeLists.txt b/tools/llvm-link/CMakeLists.txt
index 4df53564e1..a414e5ac7f 100644
--- a/tools/llvm-link/CMakeLists.txt
+++ b/tools/llvm-link/CMakeLists.txt
@@ -1,4 +1,4 @@
-set(LLVM_LINK_COMPONENTS linker bitreader bitwriter asmparser irreader)
+set(LLVM_LINK_COMPONENTS linker bitreader bitwriter naclbitwriter asmparser irreader)
add_llvm_tool(llvm-link
llvm-link.cpp
diff --git a/tools/llvm-mc/llvm-mc.cpp b/tools/llvm-mc/llvm-mc.cpp
index 4b01c33504..db2628fbf8 100644
--- a/tools/llvm-mc/llvm-mc.cpp
+++ b/tools/llvm-mc/llvm-mc.cpp
@@ -19,6 +19,7 @@
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCInstPrinter.h"
#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCNaCl.h"
#include "llvm/MC/MCObjectFileInfo.h"
#include "llvm/MC/MCParser/AsmLexer.h"
#include "llvm/MC/MCRegisterInfo.h"
@@ -450,6 +451,11 @@ int main(int argc, char **argv) {
Str.reset(TheTarget->createMCObjectStreamer(TripleName, Ctx, *MAB,
FOS, CE, RelaxAll,
NoExecStack));
+ // @LOCALMOD-BEGIN
+ Triple T(TripleName);
+ if (T.isOSNaCl())
+ initializeNaClMCStreamer(*Str.get(), Ctx, T);
+ // @LOCALMOD-END
}
int Res = 1;
diff --git a/tools/llvm-nm/CMakeLists.txt b/tools/llvm-nm/CMakeLists.txt
index b6cd80b477..de06ca28d9 100644
--- a/tools/llvm-nm/CMakeLists.txt
+++ b/tools/llvm-nm/CMakeLists.txt
@@ -1,4 +1,4 @@
-set(LLVM_LINK_COMPONENTS archive bitreader object)
+set(LLVM_LINK_COMPONENTS archive bitreader naclbitreader object)
add_llvm_tool(llvm-nm
llvm-nm.cpp
diff --git a/tools/llvm-nm/LLVMBuild.txt b/tools/llvm-nm/LLVMBuild.txt
index 38ecbfd2e6..baba9ca50b 100644
--- a/tools/llvm-nm/LLVMBuild.txt
+++ b/tools/llvm-nm/LLVMBuild.txt
@@ -19,4 +19,4 @@
type = Tool
name = llvm-nm
parent = Tools
-required_libraries = Archive BitReader Object
+required_libraries = Archive BitReader NaClBitReader Object
diff --git a/tools/llvm-nm/Makefile b/tools/llvm-nm/Makefile
index d9cee98995..fe208a8f24 100644
--- a/tools/llvm-nm/Makefile
+++ b/tools/llvm-nm/Makefile
@@ -9,7 +9,7 @@
LEVEL := ../..
TOOLNAME := llvm-nm
-LINK_COMPONENTS := archive bitreader object
+LINK_COMPONENTS := archive bitreader naclbitreader object
# This tool has no plugins, optimize startup time.
TOOL_NO_EXPORTS := 1
diff --git a/tools/llvm-nm/llvm-nm.cpp b/tools/llvm-nm/llvm-nm.cpp
index a24aae6061..a4f9ab0730 100644
--- a/tools/llvm-nm/llvm-nm.cpp
+++ b/tools/llvm-nm/llvm-nm.cpp
@@ -19,6 +19,8 @@
#include "llvm/IR/LLVMContext.h"
#include "llvm/Bitcode/Archive.h"
#include "llvm/Bitcode/ReaderWriter.h"
+#include "llvm/Bitcode/NaCl/NaClReaderWriter.h" // @LOCALMOD
+#include "llvm/IRReader/IRReader.h" // @LOCALMOD
#include "llvm/IR/Module.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/ObjectFile.h"
@@ -122,6 +124,18 @@ namespace {
bool MultipleFiles = false;
std::string ToolName;
+
+ // @LOCALMOD-BEGIN
+ cl::opt<NaClFileFormat>
+ InputFileFormat(
+ "bitcode-format",
+ cl::desc("Define format of input file:"),
+ cl::values(
+ clEnumValN(LLVMFormat, "llvm", "LLVM file (default)"),
+ clEnumValN(PNaClFormat, "pnacl", "PNaCl bitcode file"),
+ clEnumValEnd),
+ cl::init(LLVMFormat));
+ // @LOCALMOD-END
}
@@ -345,7 +359,20 @@ static void DumpSymbolNamesFromFile(std::string &Filename) {
LLVMContext &Context = getGlobalContext();
std::string ErrorMessage;
- if (magic == sys::fs::file_magic::bitcode) {
+ // @LOCALMOD-BEGIN
+ // Support parsing PNaCl bitcode files
+ if (InputFileFormat == PNaClFormat) {
+ Module *Result = NaClParseBitcodeFile(Buffer.get(), Context, &ErrorMessage);
+ if (Result) {
+ DumpSymbolNamesFromModule(Result);
+ delete Result;
+ } else {
+ error(ErrorMessage, Filename);
+ return;
+ }
+ }
+ // @LOCALMOD-END
+ else if (magic == sys::fs::file_magic::bitcode) {
Module *Result = 0;
Result = ParseBitcodeFile(Buffer.get(), Context, &ErrorMessage);
if (Result) {
diff --git a/tools/lto/LTOCodeGenerator.cpp b/tools/lto/LTOCodeGenerator.cpp
index 57e7a2d07f..75c718c019 100644
--- a/tools/lto/LTOCodeGenerator.cpp
+++ b/tools/lto/LTOCodeGenerator.cpp
@@ -98,6 +98,68 @@ bool LTOCodeGenerator::addModule(LTOModule* mod, std::string& errMsg) {
return ret;
}
+// @LOCALMOD-BEGIN
+/// Add a module that will be merged with the final output module.
+/// The merging does not happen until linkGatheredModulesAndDispose().
+void LTOCodeGenerator::gatherModuleForLinking(LTOModule* mod) {
+ _gatheredModules.push_back(mod);
+}
+
+/// Merge all modules gathered from gatherModuleForLinking(), and
+/// destroy the source modules in the process.
+bool LTOCodeGenerator::linkGatheredModulesAndDispose(std::string& errMsg) {
+
+ // We gather the asm undefs earlier than addModule() does,
+ // since we delete the modules during linking, and would not be
+ // able to do this after linking. The undefs vector contain lists
+ // of global variable names which are considered "used", which will be
+ // appended into the "llvm.compiler.used" list. The names must be the
+ // same before linking as they are after linking, since we have switched
+ // the order.
+ for (unsigned i = 0, ei = _gatheredModules.size(); i != ei; ++i) {
+ const std::vector<const char*> &undefs =
+ _gatheredModules[i]->getAsmUndefinedRefs();
+ for (int j = 0, ej = undefs.size(); j != ej; ++j) {
+ _asmUndefinedRefs[undefs[j]] = 1;
+ }
+ }
+
+ // Tree-reduce the mods, re-using the incoming mods as scratch
+ // intermediate results. Module i is linked with (i + stride), with i as
+ // the dest. We begin with a stride of 1, and double each time. E.g.,
+ // after the first round, only the even-indexed modules are still available,
+ // and after the second, only those with index that are a multiple of 4
+ // are available. Eventually the Module with the content of all other modules
+ // will be Module 0.
+ // NOTE: we may be able to be smarter about linking if we did not do them
+ // pairwise using Linker::LinkModules. We also disregard module sizes
+ // and try our best to keep the modules in order (linking adjacent modules).
+ for (unsigned stride = 1, len = _gatheredModules.size();
+ stride < len;
+ stride *= 2) {
+ for (unsigned i = 0; i + stride < len; i = i + (stride * 2)) {
+ if (Linker::LinkModules(_gatheredModules[i]->getLLVVMModule(),
+ _gatheredModules[i+stride]->getLLVVMModule(),
+ Linker::DestroySource, &errMsg)) {
+ errs() << "LinkModules " << i << " w/ " << i + stride << " failed...\n";
+ // We leak the memory in this case...
+ return true;
+ }
+ delete _gatheredModules[i+stride];
+ }
+ }
+
+ // Finally, link Node 0 with the Dest and delete Node 0.
+ if (_linker.LinkInModule(_gatheredModules[0]->getLLVVMModule(), &errMsg)) {
+ errs() << "LinkModules Dst w/ _gatheredModules[0] failed...\n";
+ return true;
+ }
+ delete _gatheredModules[0];
+
+ return false;
+}
+// @LOCALMOD-END
+
bool LTOCodeGenerator::setDebugInfo(lto_debug_model debug,
std::string& errMsg) {
switch (debug) {
@@ -124,6 +186,83 @@ bool LTOCodeGenerator::setCodePICModel(lto_codegen_model model,
llvm_unreachable("Unknown PIC model!");
}
+// @LOCALMOD-BEGIN
+void LTOCodeGenerator::setMergedModuleOutputFormat(lto_output_format format)
+{
+ Module::OutputFormat outputFormat;
+ switch (format) {
+ case LTO_OUTPUT_FORMAT_OBJECT:
+ outputFormat = Module::ObjectOutputFormat;
+ break;
+ case LTO_OUTPUT_FORMAT_SHARED:
+ outputFormat = Module::SharedOutputFormat;
+ break;
+ case LTO_OUTPUT_FORMAT_EXEC:
+ outputFormat = Module::ExecutableOutputFormat;
+ break;
+ default:
+ llvm_unreachable("Unexpected output format");
+ }
+ Module *mergedModule = _linker.getModule();
+ mergedModule->setOutputFormat(outputFormat);
+}
+
+void LTOCodeGenerator::setMergedModuleSOName(const char *soname)
+{
+ Module *mergedModule = _linker.getModule();
+ mergedModule->setSOName(soname);
+}
+
+void LTOCodeGenerator::addLibraryDep(const char *lib)
+{
+ Module *mergedModule = _linker.getModule();
+ mergedModule->addLibrary(lib);
+}
+
+void LTOCodeGenerator::wrapSymbol(const char *sym)
+{
+ Module *mergedModule = _linker.getModule();
+ mergedModule->wrapSymbol(sym);
+}
+
+const char* LTOCodeGenerator::setSymbolDefVersion(const char *sym,
+ const char *ver,
+ bool is_default)
+{
+ Module *mergedModule = _linker.getModule();
+ GlobalValue *GV = mergedModule->getNamedValue(sym);
+ if (!GV) {
+ llvm_unreachable("Invalid global in setSymbolDefVersion");
+ }
+ GV->setVersionDef(ver, is_default);
+ return strdup(GV->getName().str().c_str());
+}
+
+const char* LTOCodeGenerator::setSymbolNeeded(const char *sym,
+ const char *ver,
+ const char *dynfile)
+{
+ Module *mergedModule = _linker.getModule();
+ GlobalValue *GV = mergedModule->getNamedValue(sym);
+ if (!GV) {
+ // Symbol lookup may have failed because this symbol was already
+ // renamed for versioning. Make sure this is the case.
+ if (strchr(sym, '@') != NULL || ver == NULL || ver[0] == '\0') {
+ llvm_unreachable("Unexpected condition in setSymbolNeeded");
+ }
+ std::string NewName = std::string(sym) + "@" + ver;
+ GV = mergedModule->getNamedValue(NewName);
+ }
+ if (!GV) {
+ // Ignore failures due to unused declarations.
+ // This caused a falure to build libppruntime.so for glibc.
+ // TODO(sehr): better document under which circumstances this is needed.
+ return sym;
+ }
+ GV->setNeeded(ver, dynfile);
+ return strdup(GV->getName().str().c_str());
+}
+// @LOCALMOD-END
bool LTOCodeGenerator::writeMergedModules(const char *path,
std::string &errMsg) {
if (determineTarget(errMsg))
@@ -142,7 +281,6 @@ bool LTOCodeGenerator::writeMergedModules(const char *path,
return true;
}
- // write bitcode to it
WriteBitcodeToFile(_linker.getModule(), Out.os());
Out.os().close();
diff --git a/tools/lto/LTOCodeGenerator.h b/tools/lto/LTOCodeGenerator.h
index a4ade9fd26..4cc3928340 100644
--- a/tools/lto/LTOCodeGenerator.h
+++ b/tools/lto/LTOCodeGenerator.h
@@ -41,6 +41,12 @@ struct LTOCodeGenerator {
~LTOCodeGenerator();
bool addModule(struct LTOModule*, std::string &errMsg);
+ // @LOCALMOD-BEGIN
+ // Alternative methods of adding modules, which delay merging modules until
+ // all modules are available.
+ void gatherModuleForLinking(struct LTOModule*);
+ bool linkGatheredModulesAndDispose(std::string &errMsg);
+ // @LOCALMOD-END
bool setDebugInfo(lto_debug_model, std::string &errMsg);
bool setCodePICModel(lto_codegen_model, std::string &errMsg);
@@ -51,6 +57,16 @@ struct LTOCodeGenerator {
}
bool writeMergedModules(const char *path, std::string &errMsg);
+ // @LOCALMOD-BEGIN
+ void setMergedModuleOutputFormat(lto_output_format format);
+ void setMergedModuleSOName(const char *soname);
+ void addLibraryDep(const char *lib);
+ void wrapSymbol(const char *sym);
+ const char* setSymbolDefVersion(const char *sym, const char *ver,
+ bool is_default);
+ const char* setSymbolNeeded(const char *sym, const char *ver,
+ const char *dynfile);
+ // @LOCALMOD-END
bool compile_to_file(const char **name, std::string &errMsg);
const void *compile(size_t *length, std::string &errMsg);
void setCodeGenDebugOptions(const char *opts);
@@ -78,6 +94,9 @@ private:
std::vector<char*> _codegenOptions;
std::string _mCpu;
std::string _nativeObjectPath;
+
+ // @LOCALMOD
+ std::vector<LTOModule*> _gatheredModules;
};
#endif // LTO_CODE_GENERATOR_H
diff --git a/tools/lto/LTOModule.cpp b/tools/lto/LTOModule.cpp
index d805f49f9a..2f98517c1c 100644
--- a/tools/lto/LTOModule.cpp
+++ b/tools/lto/LTOModule.cpp
@@ -28,6 +28,7 @@
#include "llvm/MC/MCTargetAsmParser.h"
#include "llvm/MC/SubtargetFeature.h"
#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/ErrorHandling.h" // @LOCALMOD
#include "llvm/Support/Host.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
@@ -271,7 +272,7 @@ LTOModule *LTOModule::makeLTOModule(MemoryBuffer *buffer,
}
// parse bitcode buffer
- OwningPtr<Module> m(getLazyBitcodeModule(buffer, getGlobalContext(),
+ OwningPtr<Module> m(ParseBitcodeFile(buffer, getGlobalContext(), // @LOCALMOD
&errMsg));
if (!m) {
delete buffer;
@@ -304,6 +305,7 @@ LTOModule *LTOModule::makeLTOModule(MemoryBuffer *buffer,
getTargetOptions(Options);
TargetMachine *target = march->createTargetMachine(TripleStr, CPU, FeatureStr,
Options);
+
LTOModule *Ret = new LTOModule(m.take(), target);
if (Ret->parseSymbols(errMsg)) {
delete Ret;
@@ -319,6 +321,36 @@ MemoryBuffer *LTOModule::makeBuffer(const void *mem, size_t length) {
return MemoryBuffer::getMemBuffer(StringRef(startPtr, length), "", false);
}
+// @LOCALMOD-BEGIN
+lto_output_format LTOModule::getOutputFormat() {
+ Module::OutputFormat format = _module->getOutputFormat();
+ switch (format) {
+ case Module::ObjectOutputFormat: return LTO_OUTPUT_FORMAT_OBJECT;
+ case Module::SharedOutputFormat: return LTO_OUTPUT_FORMAT_SHARED;
+ case Module::ExecutableOutputFormat: return LTO_OUTPUT_FORMAT_EXEC;
+ }
+ llvm_unreachable("Unknown output format in LTOModule");
+}
+
+const char *LTOModule::getSOName() {
+ return _module->getSOName().c_str();
+}
+
+const char* LTOModule::getLibraryDep(uint32_t index) {
+ /* make it compile until we bring back deplibs
+ const Module::LibraryListType &Libs = _module->getLibraries();
+ if (index < Libs.size())
+ return Libs[index].c_str();
+ */
+ return NULL;
+}
+
+uint32_t LTOModule::getNumLibraryDeps() {
+ //return _module->getLibraries().size();
+ return 0;
+}
+// @LOCALMOD-END
+
/// objcClassNameFromExpression - Get string that the data pointer points to.
bool
LTOModule::objcClassNameFromExpression(const Constant *c, std::string &name) {
@@ -614,6 +646,14 @@ LTOModule::addPotentialUndefinedSymbol(const GlobalValue *decl, bool isFunc) {
if (decl->getName().startswith("llvm."))
return;
+ // @LOCALMOD-BEGIN
+ // Bitcode modules may have declarations for functions or globals
+ // which are unused. Ignore them here so that gold does not mistake
+ // them for undefined symbols.
+ if (decl->use_empty())
+ return;
+ // @LOCALMOD-END
+
// ignore all aliases
if (isa<GlobalAlias>(decl))
return;
@@ -800,6 +840,7 @@ namespace {
unsigned MaxBytesToEmit) {}
virtual bool EmitValueToOffset(const MCExpr *Offset,
unsigned char Value ) { return false; }
+
virtual void EmitFileDirective(StringRef Filename) {}
virtual void EmitDwarfAdvanceLineAddr(int64_t LineDelta,
const MCSymbol *LastLabel,
diff --git a/tools/lto/LTOModule.h b/tools/lto/LTOModule.h
index 83f3a7def1..6f97699e90 100644
--- a/tools/lto/LTOModule.h
+++ b/tools/lto/LTOModule.h
@@ -99,6 +99,14 @@ public:
_module->setTargetTriple(triple);
}
+ // @LOCALMOD-BEGIN
+ lto_output_format getOutputFormat();
+ const char* getSOName();
+ const char* getLibraryDep(uint32_t index);
+ uint32_t getNumLibraryDeps();
+ // @LOCALMOD-END
+
+
/// getSymbolCount - Get the number of symbols
uint32_t getSymbolCount() {
return _symbols.size();
diff --git a/tools/lto/Makefile b/tools/lto/Makefile
index ab2e16e5fa..c13a0ba7f6 100644
--- a/tools/lto/Makefile
+++ b/tools/lto/Makefile
@@ -57,3 +57,11 @@ ifeq ($(HOST_OS),Darwin)
-Wl,-object_path_lto -Wl,$(TempFile)
endif
endif
+
+#@ LOCALMOD-BEGIN
+# This is to fix an upstream bug. It is in the process of being upstreamed.
+# This line can be removed after it has been fixed upstream and we've merged.
+ifneq ($(HOST_OS),Darwin)
+ LLVMLibsOptions := $(LLVMLibsOptions) -Wl,-soname=$(SharedPrefix)LTO$(SHLIBEXT)
+endif
+#@ LOCALMOD-END
diff --git a/tools/lto/lto.cpp b/tools/lto/lto.cpp
index 11ad532be8..1915acbdae 100644
--- a/tools/lto/lto.cpp
+++ b/tools/lto/lto.cpp
@@ -13,6 +13,8 @@
//===----------------------------------------------------------------------===//
#include "llvm-c/lto.h"
+#include "llvm/Support/CommandLine.h" // @LOCALMOD
+
#include "LTOCodeGenerator.h"
#include "LTOModule.h"
#include "llvm-c/Core.h"
@@ -22,6 +24,25 @@
// *** Not thread safe ***
static std::string sLastErrorString;
+// @LOCALMOD-BEGIN
+static std::vector<const char*> lto_options;
+extern void lto_add_command_line_option(const char* opt)
+{
+ // ParseCommandLineOptions() expects argv[0] to be program name.
+ if (lto_options.empty())
+ lto_options.push_back("libLTO");
+
+ lto_options.push_back(strdup(opt));
+}
+
+extern void lto_parse_command_line_options()
+{
+ if ( !lto_options.empty() )
+ llvm::cl::ParseCommandLineOptions(lto_options.size(),
+ const_cast<char **>(&lto_options[0]));
+}
+// @LOCALMOD-END
+
/// lto_get_version - Returns a printable string.
extern const char* lto_get_version() {
return LTOCodeGenerator::getVersionString();
@@ -106,6 +127,45 @@ void lto_module_set_target_triple(lto_module_t mod, const char *triple) {
return mod->setTargetTriple(triple);
}
+// @LOCALMOD-BEGIN
+
+//
+// Get the module format for this module
+//
+lto_output_format lto_module_get_output_format(lto_module_t mod)
+{
+ return mod->getOutputFormat();
+}
+
+//
+// Get the module soname
+//
+const char* lto_module_get_soname(lto_module_t mod)
+{
+ return mod->getSOName();
+}
+
+//
+// Get the i'th library dependency.
+// Returns NULL if i >= lto_module_get_num_library_deps()
+//
+const char *
+lto_module_get_library_dep(lto_module_t mod, unsigned int i)
+{
+ return mod->getLibraryDep(i);
+}
+
+//
+// Return the number of library dependencies of this module.
+//
+unsigned int
+lto_module_get_num_library_deps(lto_module_t mod)
+{
+ return mod->getNumLibraryDeps();
+}
+
+// @LOCALMOD-END
+
/// lto_module_get_num_symbols - Returns the number of symbols in the object
/// module.
unsigned int lto_module_get_num_symbols(lto_module_t mod) {
@@ -144,6 +204,16 @@ bool lto_codegen_add_module(lto_code_gen_t cg, lto_module_t mod) {
return cg->addModule(mod, sLastErrorString);
}
+// @LOCALMOD-BEGIN
+void lto_codegen_gather_module_for_link(lto_code_gen_t cg, lto_module_t mod) {
+ cg->gatherModuleForLinking(mod);
+}
+
+bool lto_codegen_link_gathered_modules_and_dispose(lto_code_gen_t cg) {
+ return cg->linkGatheredModulesAndDispose(sLastErrorString);
+}
+// @LOCALMOD-END
+
/// lto_codegen_set_debug_model - Sets what if any format of debug info should
/// be generated. Returns true on error (check lto_get_error_message() for
/// details).
@@ -182,6 +252,77 @@ void lto_codegen_add_must_preserve_symbol(lto_code_gen_t cg,
cg->addMustPreserveSymbol(symbol);
}
+// @LOCALMOD-BEGIN
+
+//
+// Set the module format for the merged module
+//
+void lto_codegen_set_merged_module_output_format(lto_code_gen_t cg,
+ lto_output_format format)
+{
+ cg->setMergedModuleOutputFormat(format);
+}
+
+//
+// Set the module soname (for shared library bitcode)
+//
+void lto_codegen_set_merged_module_soname(lto_code_gen_t cg,
+ const char* soname)
+{
+ cg->setMergedModuleSOName(soname);
+}
+
+//
+// Add a library dependency to the linked bitcode module.
+//
+void lto_codegen_add_merged_module_library_dep(lto_code_gen_t cg,
+ const char* soname)
+{
+ cg->addLibraryDep(soname);
+}
+
+//
+// Apply symbol wrapping in the linked bitcode module.
+//
+void lto_codegen_wrap_symbol_in_merged_module(lto_code_gen_t cg,
+ const char* sym) {
+ cg->wrapSymbol(sym);
+}
+
+//
+// Set the symbol version of defined symbol 'sym'.
+// 'sym' is the name of the GlobalValue, exactly as it is
+// in the LLVM module. It may already have a version suffix.
+// In that case, this function verifies that the old version
+// and new version match.
+// Returns a reference to the new name.
+//
+const char *
+lto_codegen_set_symbol_def_version(lto_code_gen_t cg,
+ const char *sym,
+ const char *version,
+ bool is_default) {
+ return cg->setSymbolDefVersion(sym, version, is_default);
+}
+
+//
+// Set the symbol version of needed symbol 'sym' from file 'dynfile'.
+// 'sym' is the name of the GlobalValue, exactly as it is
+// in the LLVM module. It may already have a version suffix.
+// In that case, this function verifies that the old version
+// and new version match.
+// In any case, it adds a NeededRecord entry.
+// Returns a reference to the new name.
+//
+const char*
+lto_codegen_set_symbol_needed(lto_code_gen_t cg,
+ const char *sym,
+ const char *version,
+ const char *dynfile) {
+ return cg->setSymbolNeeded(sym, version, dynfile);
+}
+// @LOCALMOD-END
+
/// lto_codegen_write_merged_modules - Writes a new file at the specified path
/// that contains the merged contents of all modules added so far. Returns true
/// on error (check lto_get_error_message() for details).
diff --git a/tools/lto/lto.exports b/tools/lto/lto.exports
index 46d0d74c82..10d2fe03f6 100644
--- a/tools/lto/lto.exports
+++ b/tools/lto/lto.exports
@@ -1,3 +1,5 @@
+lto_add_command_line_option
+lto_parse_command_line_options
lto_get_error_message
lto_get_version
lto_initialize_disassembler
@@ -10,16 +12,25 @@ lto_module_get_symbol_attribute
lto_module_get_symbol_name
lto_module_get_target_triple
lto_module_set_target_triple
+lto_module_get_output_format
+lto_module_get_soname
+lto_module_get_library_dep
+lto_module_get_num_library_deps
lto_module_is_object_file
lto_module_is_object_file_for_target
lto_module_is_object_file_in_memory
lto_module_is_object_file_in_memory_for_target
lto_module_dispose
lto_codegen_add_module
+lto_codegen_gather_module_for_link
+lto_codegen_link_gathered_modules_and_dispose
lto_codegen_add_must_preserve_symbol
lto_codegen_compile
lto_codegen_create
lto_codegen_dispose
+lto_codegen_set_assembler_args
+lto_codegen_set_assembler_path
+lto_codegen_set_cpu
lto_codegen_set_debug_model
lto_codegen_set_pic_model
lto_codegen_write_merged_modules
@@ -27,6 +38,12 @@ lto_codegen_debug_options
lto_codegen_set_assembler_args
lto_codegen_set_assembler_path
lto_codegen_set_cpu
+lto_codegen_set_merged_module_output_format
+lto_codegen_set_merged_module_soname
+lto_codegen_add_merged_module_library_dep
+lto_codegen_set_symbol_def_version
+lto_codegen_set_symbol_needed
+lto_codegen_wrap_symbol_in_merged_module
lto_codegen_compile_to_file
LLVMCreateDisasm
LLVMCreateDisasmCPU
diff --git a/tools/opt/CMakeLists.txt b/tools/opt/CMakeLists.txt
index 91959119e4..b308fa7264 100644
--- a/tools/opt/CMakeLists.txt
+++ b/tools/opt/CMakeLists.txt
@@ -1,4 +1,4 @@
-set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} bitreader asmparser bitwriter irreader instrumentation scalaropts objcarcopts ipo vectorize)
+set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} bitreader asmparser bitwriter irreader naclbitwriter naclbitreader instrumentation naclanalysis nacltransforms scalaropts objcarcopts ipo vectorize)
add_llvm_tool(opt
AnalysisWrappers.cpp
diff --git a/tools/opt/LLVMBuild.txt b/tools/opt/LLVMBuild.txt
index 77b94469ed..6cf3a79219 100644
--- a/tools/opt/LLVMBuild.txt
+++ b/tools/opt/LLVMBuild.txt
@@ -19,4 +19,4 @@
type = Tool
name = opt
parent = Tools
-required_libraries = AsmParser BitReader BitWriter IRReader IPO Instrumentation Scalar ObjCARC all-targets
+required_libraries = AsmParser BitReader BitWriter IRReader NaClBitWriter IPO Instrumentation Scalar ObjCARC all-targets NaClTransforms NaClAnalysis
diff --git a/tools/opt/Makefile b/tools/opt/Makefile
index a451005574..5413125972 100644
--- a/tools/opt/Makefile
+++ b/tools/opt/Makefile
@@ -9,6 +9,6 @@
LEVEL := ../..
TOOLNAME := opt
-LINK_COMPONENTS := bitreader bitwriter asmparser irreader instrumentation scalaropts objcarcopts ipo vectorize all-targets
+LINK_COMPONENTS := bitreader bitwriter naclbitwriter asmparser irreader instrumentation scalaropts objcarcopts ipo vectorize nacltransforms naclanalysis all-targets
include $(LEVEL)/Makefile.common
diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp
index e385d7f577..1e8fb65e51 100644
--- a/tools/opt/opt.cpp
+++ b/tools/opt/opt.cpp
@@ -22,22 +22,23 @@
#include "llvm/Analysis/Verifier.h"
#include "llvm/Assembly/PrintModulePass.h"
#include "llvm/Bitcode/ReaderWriter.h"
+#include "llvm/Bitcode/NaCl/NaClReaderWriter.h" // @LOCALMOD
#include "llvm/CodeGen/CommandFlags.h"
#include "llvm/DebugInfo.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Module.h"
-#include "llvm/IRReader/IRReader.h"
+#include "llvm/IRReader/IRReader.h" // @LOCALMOD
#include "llvm/LinkAllIR.h"
#include "llvm/LinkAllPasses.h"
#include "llvm/MC/SubtargetFeature.h"
#include "llvm/PassManager.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/IRReader.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/PassNameParser.h"
#include "llvm/Support/PluginLoader.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Signals.h"
-#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/SystemUtils.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
@@ -45,6 +46,7 @@
#include "llvm/Target/TargetLibraryInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#include "llvm/Transforms/NaCl.h" // @LOCALMOD
#include <algorithm>
#include <memory>
using namespace llvm;
@@ -127,6 +129,18 @@ static cl::opt<bool>
OptLevelO3("O3",
cl::desc("Optimization level 3. Similar to clang -O3"));
+// @LOCALMOD-BEGIN
+static cl::opt<bool>
+PNaClABISimplifyPreOpt(
+ "pnacl-abi-simplify-preopt",
+ cl::desc("PNaCl ABI simplifications for before optimizations"));
+
+static cl::opt<bool>
+PNaClABISimplifyPostOpt(
+ "pnacl-abi-simplify-postopt",
+ cl::desc("PNaCl ABI simplifications for after optimizations"));
+// @LOCALMOD-END
+
static cl::opt<std::string>
TargetTriple("mtriple", cl::desc("Override target triple for module"));
@@ -157,6 +171,18 @@ DefaultDataLayout("default-data-layout",
cl::desc("data layout string to use if not specified by module"),
cl::value_desc("layout-string"), cl::init(""));
+// @LOCALMOD-BEGIN
+static cl::opt<NaClFileFormat>
+OutputFileFormat(
+ "bitcode-format",
+ cl::desc("Define format of generated bitcode file:"),
+ cl::values(
+ clEnumValN(LLVMFormat, "llvm", "LLVM bitcode file (default)"),
+ clEnumValN(PNaClFormat, "pnacl", "PNaCl bitcode file"),
+ clEnumValEnd),
+ cl::init(LLVMFormat));
+// @LOCALMOD-END
+
// ---------- Define Printers for module and function passes ------------
namespace {
@@ -577,6 +603,34 @@ int main(int argc, char **argv) {
initializeInstCombine(Registry);
initializeInstrumentation(Registry);
initializeTarget(Registry);
+ // @LOCALMOD-BEGIN
+ initializeAddPNaClExternalDeclsPass(Registry);
+ initializeCanonicalizeMemIntrinsicsPass(Registry);
+ initializeExpandArithWithOverflowPass(Registry);
+ initializeExpandByValPass(Registry);
+ initializeExpandConstantExprPass(Registry);
+ initializeExpandCtorsPass(Registry);
+ initializeExpandGetElementPtrPass(Registry);
+ initializeExpandSmallArgumentsPass(Registry);
+ initializeExpandStructRegsPass(Registry);
+ initializeExpandTlsPass(Registry);
+ initializeExpandTlsConstantExprPass(Registry);
+ initializeExpandVarArgsPass(Registry);
+ initializeFlattenGlobalsPass(Registry);
+ initializeGlobalCleanupPass(Registry);
+ initializeInsertDivideCheckPass(Registry);
+ initializePNaClABIVerifyFunctionsPass(Registry);
+ initializePNaClABIVerifyModulePass(Registry);
+ initializePromoteI1OpsPass(Registry);
+ initializePromoteIntegersPass(Registry);
+ initializeReplacePtrsWithIntsPass(Registry);
+ initializeResolveAliasesPass(Registry);
+ initializeResolvePNaClIntrinsicsPass(Registry);
+ initializeRewriteLLVMIntrinsicsPass(Registry);
+ initializeRewritePNaClLibraryCallsPass(Registry);
+ initializeStripAttributesPass(Registry);
+ initializeStripMetadataPass(Registry);
+ // @LOCALMOD-END
cl::ParseCommandLineOptions(argc, argv,
"llvm .bc -> .bc modular optimizer and analysis printer\n");
@@ -733,6 +787,20 @@ int main(int argc, char **argv) {
OptLevelO3 = false;
}
+ // @LOCALMOD-BEGIN
+ if (PNaClABISimplifyPreOpt &&
+ PNaClABISimplifyPreOpt.getPosition() < PassList.getPosition(i)) {
+ PNaClABISimplifyAddPreOptPasses(Passes);
+ PNaClABISimplifyPreOpt = false;
+ }
+
+ if (PNaClABISimplifyPostOpt &&
+ PNaClABISimplifyPostOpt.getPosition() < PassList.getPosition(i)) {
+ PNaClABISimplifyAddPostOptPasses(Passes);
+ PNaClABISimplifyPostOpt = false;
+ }
+ // @LOCALMOD-END
+
const PassInfo *PassInf = PassList[i];
Pass *P = 0;
if (PassInf->getNormalCtor())
@@ -805,6 +873,14 @@ int main(int argc, char **argv) {
FPasses->doFinalization();
}
+ // @LOCALMOD-BEGIN
+ if (PNaClABISimplifyPreOpt)
+ PNaClABISimplifyAddPreOptPasses(Passes);
+
+ if (PNaClABISimplifyPostOpt)
+ PNaClABISimplifyAddPostOptPasses(Passes);
+ // @LOCALMOD-END
+
// Check that the module is well formed on completion of optimization
if (!NoVerify && !VerifyEach)
Passes.add(createVerifierPass());
@@ -813,8 +889,7 @@ int main(int argc, char **argv) {
if (!NoOutput && !AnalyzeOnly) {
if (OutputAssembly)
Passes.add(createPrintModulePass(&Out->os()));
- else
- Passes.add(createBitcodeWriterPass(Out->os()));
+ // @LOCALMOD
}
// Before executing passes, print the final values of the LLVM options.
@@ -823,6 +898,23 @@ int main(int argc, char **argv) {
// Now that we have all of the passes ready, run them.
Passes.run(*M.get());
+// @LOCALMOD-BEGIN
+ // Write bitcode to the output.
+ if (!NoOutput && !AnalyzeOnly && !OutputAssembly) {
+ switch (OutputFileFormat) {
+ case LLVMFormat:
+ WriteBitcodeToFile(M.get(), Out->os());
+ break;
+ case PNaClFormat:
+ NaClWriteBitcodeToFile(M.get(), Out->os());
+ break;
+ default:
+ errs() << "Don't understand bitcode format for generated bitcode.\n";
+ return 1;
+ }
+ }
+// @LOCALMOD-END
+
// Declare success.
if (!NoOutput || PrintBreakpoints)
Out->keep();
diff --git a/tools/pnacl-abicheck/CMakeLists.txt b/tools/pnacl-abicheck/CMakeLists.txt
new file mode 100644
index 0000000000..fda6d26ac8
--- /dev/null
+++ b/tools/pnacl-abicheck/CMakeLists.txt
@@ -0,0 +1,5 @@
+set(LLVM_LINK_COMPONENTS bitreader naclbitreader irreader asmparser naclanalysis)
+
+add_llvm_tool(pnacl-abicheck
+ pnacl-abicheck.cpp
+ )
diff --git a/tools/pnacl-abicheck/LLVMBuild.txt b/tools/pnacl-abicheck/LLVMBuild.txt
new file mode 100644
index 0000000000..9e45f87f0a
--- /dev/null
+++ b/tools/pnacl-abicheck/LLVMBuild.txt
@@ -0,0 +1,22 @@
+;===- ./tools/pnacl-abicheck/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-abicheck
+parent = Tools
+required_libraries = AsmParser BitReader NaClBitReader IRReader NaClAnalysis
diff --git a/tools/pnacl-abicheck/Makefile b/tools/pnacl-abicheck/Makefile
new file mode 100644
index 0000000000..97e2d22399
--- /dev/null
+++ b/tools/pnacl-abicheck/Makefile
@@ -0,0 +1,16 @@
+#===- tools/pnacl-abicheck/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-abicheck
+LINK_COMPONENTS := bitreader asmparser naclbitreader irreader naclanalysis
+
+include $(LEVEL)/Makefile.common
+
+
diff --git a/tools/pnacl-abicheck/pnacl-abicheck.cpp b/tools/pnacl-abicheck/pnacl-abicheck.cpp
new file mode 100644
index 0000000000..8b96f17954
--- /dev/null
+++ b/tools/pnacl-abicheck/pnacl-abicheck.cpp
@@ -0,0 +1,87 @@
+//===-- pnacl-abicheck.cpp - Check PNaCl bitcode ABI ----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This tool checks files for compliance with the PNaCl bitcode ABI
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/Analysis/NaCl.h"
+#include "llvm/IRReader/IRReader.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FormattedStream.h"
+#include "llvm/Support/IRReader.h"
+#include <string>
+
+using namespace llvm;
+
+static cl::opt<std::string>
+InputFilename(cl::Positional, cl::desc("<input bitcode>"), cl::init("-"));
+
+static cl::opt<bool>
+Quiet("q", cl::desc("Do not print error messages"));
+
+static cl::opt<NaClFileFormat>
+InputFileFormat(
+ "bitcode-format",
+ cl::desc("Define format of input file:"),
+ cl::values(
+ clEnumValN(LLVMFormat, "llvm", "LLVM file (default)"),
+ clEnumValN(PNaClFormat, "pnacl", "PNaCl bitcode file"),
+ clEnumValEnd),
+ cl::init(LLVMFormat));
+
+// Print any errors collected by the error reporter. Return true if
+// there were any.
+static bool CheckABIVerifyErrors(PNaClABIErrorReporter &Reporter,
+ const Twine &Name) {
+ bool HasErrors = Reporter.getErrorCount() > 0;
+ if (HasErrors) {
+ if (!Quiet) {
+ outs() << "ERROR: " << Name << " is not valid PNaCl bitcode:\n";
+ Reporter.printErrors(outs());
+ }
+ }
+ Reporter.reset();
+ return HasErrors;
+}
+
+int main(int argc, char **argv) {
+ LLVMContext &Context = getGlobalContext();
+ SMDiagnostic Err;
+ cl::ParseCommandLineOptions(argc, argv, "PNaCl Bitcode ABI checker\n");
+
+ OwningPtr<Module> Mod(
+ NaClParseIRFile(InputFilename, InputFileFormat, Err, Context));
+ if (Mod.get() == 0) {
+ Err.print(argv[0], errs());
+ return 1;
+ }
+ PNaClABIErrorReporter ABIErrorReporter;
+ ABIErrorReporter.setNonFatal();
+ bool ErrorsFound = false;
+ // Manually run the passes so we can tell the user which function had the
+ // error. No need for a pass manager since it's just one pass.
+ OwningPtr<ModulePass> ModuleChecker(
+ createPNaClABIVerifyModulePass(&ABIErrorReporter));
+ ModuleChecker->runOnModule(*Mod);
+ ErrorsFound |= CheckABIVerifyErrors(ABIErrorReporter, "Module");
+ OwningPtr<FunctionPass> FunctionChecker(
+ createPNaClABIVerifyFunctionsPass(&ABIErrorReporter));
+ for (Module::iterator MI = Mod->begin(), ME = Mod->end(); MI != ME; ++MI) {
+ FunctionChecker->runOnFunction(*MI);
+ ErrorsFound |= CheckABIVerifyErrors(ABIErrorReporter,
+ "Function " + MI->getName());
+ }
+
+ return ErrorsFound ? 1 : 0;
+}
diff --git a/tools/pnacl-bcanalyzer/CMakeLists.txt b/tools/pnacl-bcanalyzer/CMakeLists.txt
new file mode 100644
index 0000000000..0cf17b8886
--- /dev/null
+++ b/tools/pnacl-bcanalyzer/CMakeLists.txt
@@ -0,0 +1,5 @@
+set(LLVM_LINK_COMPONENTS naclbitreader)
+
+add_llvm_tool(pnacl-bcanalyzer
+ pnacl-bcanalyzer.cpp
+ )
diff --git a/tools/pnacl-bcanalyzer/LLVMBuild.txt b/tools/pnacl-bcanalyzer/LLVMBuild.txt
new file mode 100644
index 0000000000..2944fca4b0
--- /dev/null
+++ b/tools/pnacl-bcanalyzer/LLVMBuild.txt
@@ -0,0 +1,22 @@
+;===- ./tools/pnacl-bcanalyzer/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-bcanalyzer
+parent = Tools
+required_libraries = NaClBitReader
diff --git a/tools/pnacl-bcanalyzer/Makefile b/tools/pnacl-bcanalyzer/Makefile
new file mode 100644
index 0000000000..d3ec1a81a9
--- /dev/null
+++ b/tools/pnacl-bcanalyzer/Makefile
@@ -0,0 +1,17 @@
+##===- tools/pnacl-bcanalyzer/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-bcanalyzer
+LINK_COMPONENTS := naclbitreader
+
+# This tool has no plugins, optimize startup time.
+TOOL_NO_EXPORTS := 1
+
+include $(LEVEL)/Makefile.common
diff --git a/tools/pnacl-bcanalyzer/pnacl-bcanalyzer.cpp b/tools/pnacl-bcanalyzer/pnacl-bcanalyzer.cpp
new file mode 100644
index 0000000000..225827e47b
--- /dev/null
+++ b/tools/pnacl-bcanalyzer/pnacl-bcanalyzer.cpp
@@ -0,0 +1,641 @@
+//===-- pnacl-bcanalyzer.cpp - Bitcode Analyzer -------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This tool may be invoked in the following manner:
+// pnacl-bcanalyzer [options] - Read frozen PNaCl bitcode from stdin
+// pnacl-bcanalyzer [options] x.bc - Read frozen PNaCl bitcode from the x.bc
+// file
+//
+// Options:
+// --help - Output information about command line switches
+// --dump - Dump low-level bitcode structure in readable format
+//
+// This tool provides analytical information about a bitcode file. It is
+// intended as an aid to developers of bitcode reading and writing software. It
+// produces on std::out a summary of the bitcode file that shows various
+// statistics about the contents of the file. By default this information is
+// detailed and contains information about individual bitcode blocks and the
+// functions in the module.
+// The tool is also able to print a bitcode file in a straight forward text
+// format that shows the containment and relationships of the information in
+// the bitcode file (-dump option).
+//
+//===----------------------------------------------------------------------===//
+
+#define DEBUG_TYPE "pnacl-bcanalyzer"
+
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/Analysis/Verifier.h"
+#include "llvm/Bitcode/NaCl/NaClBitcodeHeader.h"
+#include "llvm/Bitcode/NaCl/NaClBitstreamReader.h"
+#include "llvm/Bitcode/NaCl/NaClLLVMBitCodes.h"
+#include "llvm/Bitcode/NaCl/NaClReaderWriter.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/system_error.h"
+#include <algorithm>
+#include <map>
+using namespace llvm;
+
+static cl::opt<std::string>
+ InputFilename(cl::Positional, cl::desc("<input bitcode>"), cl::init("-"));
+
+static cl::opt<bool> Dump("dump", cl::desc("Dump low level bitcode trace"));
+
+static cl::opt<unsigned> OpsPerLine(
+ "operands-per-line",
+ cl::desc("Number of operands to print per dump line. 0 implies "
+ "all operands will be printed on the same line (default)"),
+ cl::init(0));
+
+//===----------------------------------------------------------------------===//
+// Bitcode specific analysis.
+//===----------------------------------------------------------------------===//
+
+static cl::opt<bool> NoHistogram("disable-histogram",
+ cl::desc("Do not print per-code histogram"));
+
+static cl::opt<bool>
+NonSymbolic("non-symbolic",
+ cl::desc("Emit numeric info in dump even if"
+ " symbolic info is available"));
+
+
+/// GetBlockName - Return a symbolic block name if known, otherwise return
+/// null.
+static const char *GetBlockName(unsigned BlockID,
+ const NaClBitstreamReader &StreamFile) {
+ // Standard blocks for all bitcode files.
+ if (BlockID < naclbitc::FIRST_APPLICATION_BLOCKID) {
+ if (BlockID == naclbitc::BLOCKINFO_BLOCK_ID)
+ return "BLOCKINFO_BLOCK";
+ return 0;
+ }
+
+ // Check to see if we have a blockinfo record for this block, with a name.
+ if (const NaClBitstreamReader::BlockInfo *Info =
+ StreamFile.getBlockInfo(BlockID)) {
+ if (!Info->Name.empty())
+ return Info->Name.c_str();
+ }
+
+ switch (BlockID) {
+ default: return 0;
+ case naclbitc::MODULE_BLOCK_ID: return "MODULE_BLOCK";
+ case naclbitc::PARAMATTR_BLOCK_ID: return "PARAMATTR_BLOCK";
+ case naclbitc::PARAMATTR_GROUP_BLOCK_ID: return "PARAMATTR_GROUP_BLOCK_ID";
+ case naclbitc::TYPE_BLOCK_ID_NEW: return "TYPE_BLOCK_ID";
+ case naclbitc::CONSTANTS_BLOCK_ID: return "CONSTANTS_BLOCK";
+ case naclbitc::FUNCTION_BLOCK_ID: return "FUNCTION_BLOCK";
+ case naclbitc::VALUE_SYMTAB_BLOCK_ID: return "VALUE_SYMTAB";
+ case naclbitc::METADATA_BLOCK_ID: return "METADATA_BLOCK";
+ case naclbitc::METADATA_ATTACHMENT_ID: return "METADATA_ATTACHMENT_BLOCK";
+ case naclbitc::USELIST_BLOCK_ID: return "USELIST_BLOCK_ID";
+ case naclbitc::GLOBALVAR_BLOCK_ID: return "GLOBALVAR_BLOCK";
+ }
+}
+
+/// GetCodeName - Return a symbolic code name if known, otherwise return
+/// null.
+static const char *GetCodeName(unsigned CodeID, unsigned BlockID,
+ const NaClBitstreamReader &StreamFile) {
+ // Standard blocks for all bitcode files.
+ if (BlockID < naclbitc::FIRST_APPLICATION_BLOCKID) {
+ if (BlockID == naclbitc::BLOCKINFO_BLOCK_ID) {
+ switch (CodeID) {
+ default: return 0;
+ case naclbitc::BLOCKINFO_CODE_SETBID: return "SETBID";
+ case naclbitc::BLOCKINFO_CODE_BLOCKNAME: return "BLOCKNAME";
+ case naclbitc::BLOCKINFO_CODE_SETRECORDNAME: return "SETRECORDNAME";
+ }
+ }
+ return 0;
+ }
+
+ // Check to see if we have a blockinfo record for this record, with a name.
+ if (const NaClBitstreamReader::BlockInfo *Info =
+ StreamFile.getBlockInfo(BlockID)) {
+ for (unsigned i = 0, e = Info->RecordNames.size(); i != e; ++i)
+ if (Info->RecordNames[i].first == CodeID)
+ return Info->RecordNames[i].second.c_str();
+ }
+
+ switch (BlockID) {
+ default: return 0;
+ case naclbitc::MODULE_BLOCK_ID:
+ switch (CodeID) {
+ default: return 0;
+ case naclbitc::MODULE_CODE_VERSION: return "VERSION";
+ case naclbitc::MODULE_CODE_TRIPLE: return "TRIPLE";
+ case naclbitc::MODULE_CODE_DATALAYOUT: return "DATALAYOUT";
+ case naclbitc::MODULE_CODE_ASM: return "ASM";
+ case naclbitc::MODULE_CODE_SECTIONNAME: return "SECTIONNAME";
+ case naclbitc::MODULE_CODE_DEPLIB: return "DEPLIB"; // FIXME: Remove in 4.0
+ case naclbitc::MODULE_CODE_GLOBALVAR: return "GLOBALVAR";
+ case naclbitc::MODULE_CODE_FUNCTION: return "FUNCTION";
+ case naclbitc::MODULE_CODE_ALIAS: return "ALIAS";
+ case naclbitc::MODULE_CODE_PURGEVALS: return "PURGEVALS";
+ case naclbitc::MODULE_CODE_GCNAME: return "GCNAME";
+ }
+ case naclbitc::PARAMATTR_BLOCK_ID:
+ switch (CodeID) {
+ default: return 0;
+ case naclbitc::PARAMATTR_CODE_ENTRY_OLD: return "ENTRY";
+ case naclbitc::PARAMATTR_CODE_ENTRY: return "ENTRY";
+ case naclbitc::PARAMATTR_GRP_CODE_ENTRY: return "ENTRY";
+ }
+ case naclbitc::TYPE_BLOCK_ID_NEW:
+ switch (CodeID) {
+ default: return 0;
+ case naclbitc::TYPE_CODE_NUMENTRY: return "NUMENTRY";
+ case naclbitc::TYPE_CODE_VOID: return "VOID";
+ case naclbitc::TYPE_CODE_FLOAT: return "FLOAT";
+ case naclbitc::TYPE_CODE_DOUBLE: return "DOUBLE";
+ case naclbitc::TYPE_CODE_LABEL: return "LABEL";
+ case naclbitc::TYPE_CODE_OPAQUE: return "OPAQUE";
+ case naclbitc::TYPE_CODE_INTEGER: return "INTEGER";
+ case naclbitc::TYPE_CODE_POINTER: return "POINTER";
+ case naclbitc::TYPE_CODE_ARRAY: return "ARRAY";
+ case naclbitc::TYPE_CODE_VECTOR: return "VECTOR";
+ case naclbitc::TYPE_CODE_X86_FP80: return "X86_FP80";
+ case naclbitc::TYPE_CODE_FP128: return "FP128";
+ case naclbitc::TYPE_CODE_PPC_FP128: return "PPC_FP128";
+ case naclbitc::TYPE_CODE_METADATA: return "METADATA";
+ case naclbitc::TYPE_CODE_STRUCT_ANON: return "STRUCT_ANON";
+ case naclbitc::TYPE_CODE_STRUCT_NAME: return "STRUCT_NAME";
+ case naclbitc::TYPE_CODE_STRUCT_NAMED: return "STRUCT_NAMED";
+ case naclbitc::TYPE_CODE_FUNCTION: return "FUNCTION";
+ }
+
+ case naclbitc::CONSTANTS_BLOCK_ID:
+ switch (CodeID) {
+ default: return 0;
+ case naclbitc::CST_CODE_SETTYPE: return "SETTYPE";
+ case naclbitc::CST_CODE_NULL: return "NULL";
+ case naclbitc::CST_CODE_UNDEF: return "UNDEF";
+ case naclbitc::CST_CODE_INTEGER: return "INTEGER";
+ case naclbitc::CST_CODE_WIDE_INTEGER: return "WIDE_INTEGER";
+ case naclbitc::CST_CODE_FLOAT: return "FLOAT";
+ case naclbitc::CST_CODE_AGGREGATE: return "AGGREGATE";
+ case naclbitc::CST_CODE_STRING: return "STRING";
+ case naclbitc::CST_CODE_CSTRING: return "CSTRING";
+ case naclbitc::CST_CODE_CE_BINOP: return "CE_BINOP";
+ case naclbitc::CST_CODE_CE_CAST: return "CE_CAST";
+ case naclbitc::CST_CODE_CE_GEP: return "CE_GEP";
+ case naclbitc::CST_CODE_CE_INBOUNDS_GEP: return "CE_INBOUNDS_GEP";
+ case naclbitc::CST_CODE_CE_SELECT: return "CE_SELECT";
+ case naclbitc::CST_CODE_CE_EXTRACTELT: return "CE_EXTRACTELT";
+ case naclbitc::CST_CODE_CE_INSERTELT: return "CE_INSERTELT";
+ case naclbitc::CST_CODE_CE_SHUFFLEVEC: return "CE_SHUFFLEVEC";
+ case naclbitc::CST_CODE_CE_CMP: return "CE_CMP";
+ case naclbitc::CST_CODE_INLINEASM: return "INLINEASM";
+ case naclbitc::CST_CODE_CE_SHUFVEC_EX: return "CE_SHUFVEC_EX";
+ case naclbitc::CST_CODE_BLOCKADDRESS: return "CST_CODE_BLOCKADDRESS";
+ case naclbitc::CST_CODE_DATA: return "DATA";
+ }
+ case naclbitc::FUNCTION_BLOCK_ID:
+ switch (CodeID) {
+ default: return 0;
+ case naclbitc::FUNC_CODE_DECLAREBLOCKS: return "DECLAREBLOCKS";
+
+ case naclbitc::FUNC_CODE_INST_BINOP: return "INST_BINOP";
+ case naclbitc::FUNC_CODE_INST_CAST: return "INST_CAST";
+ case naclbitc::FUNC_CODE_INST_GEP: return "INST_GEP";
+ case naclbitc::FUNC_CODE_INST_INBOUNDS_GEP: return "INST_INBOUNDS_GEP";
+ case naclbitc::FUNC_CODE_INST_SELECT: return "INST_SELECT";
+ case naclbitc::FUNC_CODE_INST_EXTRACTELT: return "INST_EXTRACTELT";
+ case naclbitc::FUNC_CODE_INST_INSERTELT: return "INST_INSERTELT";
+ case naclbitc::FUNC_CODE_INST_SHUFFLEVEC: return "INST_SHUFFLEVEC";
+ case naclbitc::FUNC_CODE_INST_CMP: return "INST_CMP";
+
+ case naclbitc::FUNC_CODE_INST_RET: return "INST_RET";
+ case naclbitc::FUNC_CODE_INST_BR: return "INST_BR";
+ case naclbitc::FUNC_CODE_INST_SWITCH: return "INST_SWITCH";
+ case naclbitc::FUNC_CODE_INST_INVOKE: return "INST_INVOKE";
+ case naclbitc::FUNC_CODE_INST_UNREACHABLE: return "INST_UNREACHABLE";
+
+ case naclbitc::FUNC_CODE_INST_PHI: return "INST_PHI";
+ case naclbitc::FUNC_CODE_INST_ALLOCA: return "INST_ALLOCA";
+ case naclbitc::FUNC_CODE_INST_LOAD: return "INST_LOAD";
+ case naclbitc::FUNC_CODE_INST_VAARG: return "INST_VAARG";
+ case naclbitc::FUNC_CODE_INST_STORE: return "INST_STORE";
+ case naclbitc::FUNC_CODE_INST_EXTRACTVAL: return "INST_EXTRACTVAL";
+ case naclbitc::FUNC_CODE_INST_INSERTVAL: return "INST_INSERTVAL";
+ case naclbitc::FUNC_CODE_INST_CMP2: return "INST_CMP2";
+ case naclbitc::FUNC_CODE_INST_VSELECT: return "INST_VSELECT";
+ case naclbitc::FUNC_CODE_DEBUG_LOC_AGAIN: return "DEBUG_LOC_AGAIN";
+ case naclbitc::FUNC_CODE_INST_CALL: return "INST_CALL";
+ case naclbitc::FUNC_CODE_DEBUG_LOC: return "DEBUG_LOC";
+ case naclbitc::FUNC_CODE_INST_FORWARDTYPEREF: return "FORWARDTYPEREF";
+ }
+ case naclbitc::VALUE_SYMTAB_BLOCK_ID:
+ switch (CodeID) {
+ default: return 0;
+ case naclbitc::VST_CODE_ENTRY: return "ENTRY";
+ case naclbitc::VST_CODE_BBENTRY: return "BBENTRY";
+ }
+ case naclbitc::METADATA_ATTACHMENT_ID:
+ switch(CodeID) {
+ default:return 0;
+ case naclbitc::METADATA_ATTACHMENT: return "METADATA_ATTACHMENT";
+ }
+ case naclbitc::METADATA_BLOCK_ID:
+ switch(CodeID) {
+ default:return 0;
+ case naclbitc::METADATA_STRING: return "METADATA_STRING";
+ case naclbitc::METADATA_NAME: return "METADATA_NAME";
+ case naclbitc::METADATA_KIND: return "METADATA_KIND";
+ case naclbitc::METADATA_NODE: return "METADATA_NODE";
+ case naclbitc::METADATA_FN_NODE: return "METADATA_FN_NODE";
+ case naclbitc::METADATA_NAMED_NODE: return "METADATA_NAMED_NODE";
+ }
+ case naclbitc::USELIST_BLOCK_ID:
+ switch(CodeID) {
+ default:return 0;
+ case naclbitc::USELIST_CODE_ENTRY: return "USELIST_CODE_ENTRY";
+ }
+ case naclbitc::GLOBALVAR_BLOCK_ID:
+ switch (CodeID) {
+ default: return 0;
+ case naclbitc::GLOBALVAR_VAR: return "VAR";
+ case naclbitc::GLOBALVAR_COMPOUND: return "COMPOUND";
+ case naclbitc::GLOBALVAR_ZEROFILL: return "ZEROFILL";
+ case naclbitc::GLOBALVAR_DATA: return "DATA";
+ case naclbitc::GLOBALVAR_RELOC: return "RELOC";
+ case naclbitc::GLOBALVAR_COUNT: return "COUNT";
+ }
+ }
+}
+
+struct PerRecordStats {
+ unsigned NumInstances;
+ unsigned NumAbbrev;
+ uint64_t TotalBits;
+
+ PerRecordStats() : NumInstances(0), NumAbbrev(0), TotalBits(0) {}
+};
+
+struct PerBlockIDStats {
+ /// NumInstances - This the number of times this block ID has been seen.
+ unsigned NumInstances;
+
+ /// NumBits - The total size in bits of all of these blocks.
+ uint64_t NumBits;
+
+ /// NumSubBlocks - The total number of blocks these blocks contain.
+ unsigned NumSubBlocks;
+
+ /// NumAbbrevs - The total number of abbreviations.
+ unsigned NumAbbrevs;
+
+ /// NumRecords - The total number of records these blocks contain, and the
+ /// number that are abbreviated.
+ unsigned NumRecords, NumAbbreviatedRecords;
+
+ /// CodeFreq - Keep track of the number of times we see each code.
+ std::vector<PerRecordStats> CodeFreq;
+
+ PerBlockIDStats()
+ : NumInstances(0), NumBits(0),
+ NumSubBlocks(0), NumAbbrevs(0), NumRecords(0), NumAbbreviatedRecords(0) {}
+};
+
+static std::map<unsigned, PerBlockIDStats> BlockIDStats;
+
+
+
+/// Error - All bitcode analysis errors go through this function, making this a
+/// good place to breakpoint if debugging.
+static bool Error(const std::string &Err) {
+ errs() << Err << "\n";
+ return true;
+}
+
+/// ParseBlock - Read a block, updating statistics, etc.
+static bool ParseBlock(NaClBitstreamCursor &Stream, unsigned BlockID,
+ unsigned IndentLevel) {
+ std::string Indent(IndentLevel*2, ' ');
+ DEBUG(dbgs() << Indent << "-> ParseBlock(" << BlockID << ")\n");
+ uint64_t BlockBitStart = Stream.GetCurrentBitNo();
+
+ // Get the statistics for this BlockID.
+ PerBlockIDStats &BlockStats = BlockIDStats[BlockID];
+
+ BlockStats.NumInstances++;
+
+ // BLOCKINFO is a special part of the stream.
+ if (BlockID == naclbitc::BLOCKINFO_BLOCK_ID) {
+ if (Dump) outs() << Indent << "<BLOCKINFO_BLOCK/>\n";
+ if (Stream.ReadBlockInfoBlock())
+ return Error("Malformed BlockInfoBlock");
+ uint64_t BlockBitEnd = Stream.GetCurrentBitNo();
+ BlockStats.NumBits += BlockBitEnd-BlockBitStart;
+ DEBUG(dbgs() << Indent << "<- ParseBlock\n");
+ return false;
+ }
+
+ unsigned NumWords = 0;
+ if (Stream.EnterSubBlock(BlockID, &NumWords))
+ return Error("Malformed block record");
+
+ const char *BlockName = 0;
+ if (Dump) {
+ outs() << Indent << "<";
+ if ((BlockName = GetBlockName(BlockID, *Stream.getBitStreamReader())))
+ outs() << BlockName;
+ else
+ outs() << "UnknownBlock" << BlockID;
+
+ if (NonSymbolic && BlockName)
+ outs() << " BlockID=" << BlockID;
+
+ outs() << " NumWords=" << NumWords
+ << " BlockCodeSize=" << Stream.getAbbrevIDWidth() << ">\n";
+ }
+
+ SmallVector<uint64_t, 64> Record;
+
+ // Read all the records for this block.
+ while (1) {
+ if (Stream.AtEndOfStream())
+ return Error("Premature end of bitstream");
+
+ uint64_t RecordStartBit = Stream.GetCurrentBitNo();
+
+ NaClBitstreamEntry Entry =
+ Stream.advance(NaClBitstreamCursor::AF_DontAutoprocessAbbrevs);
+
+ switch (Entry.Kind) {
+ case NaClBitstreamEntry::Error:
+ return Error("malformed bitcode file");
+ case NaClBitstreamEntry::EndBlock: {
+ uint64_t BlockBitEnd = Stream.GetCurrentBitNo();
+ BlockStats.NumBits += BlockBitEnd-BlockBitStart;
+ if (Dump) {
+ outs() << Indent << "</";
+ if (BlockName)
+ outs() << BlockName << ">\n";
+ else
+ outs() << "UnknownBlock" << BlockID << ">\n";
+ }
+ DEBUG(dbgs() << Indent << "<- ParseBlock\n");
+ return false;
+ }
+
+ case NaClBitstreamEntry::SubBlock: {
+ uint64_t SubBlockBitStart = Stream.GetCurrentBitNo();
+ if (ParseBlock(Stream, Entry.ID, IndentLevel+1))
+ return true;
+ ++BlockStats.NumSubBlocks;
+ uint64_t SubBlockBitEnd = Stream.GetCurrentBitNo();
+
+ // Don't include subblock sizes in the size of this block.
+ BlockBitStart += SubBlockBitEnd-SubBlockBitStart;
+ continue;
+ }
+ case NaClBitstreamEntry::Record:
+ // The interesting case.
+ break;
+ }
+
+ if (Entry.ID == naclbitc::DEFINE_ABBREV) {
+ Stream.ReadAbbrevRecord();
+ ++BlockStats.NumAbbrevs;
+ continue;
+ }
+
+ Record.clear();
+
+ ++BlockStats.NumRecords;
+
+ StringRef Blob;
+ unsigned Code = Stream.readRecord(Entry.ID, Record, &Blob);
+
+ // Increment the # occurrences of this code.
+ if (BlockStats.CodeFreq.size() <= Code)
+ BlockStats.CodeFreq.resize(Code+1);
+ BlockStats.CodeFreq[Code].NumInstances++;
+ BlockStats.CodeFreq[Code].TotalBits +=
+ Stream.GetCurrentBitNo()-RecordStartBit;
+ if (Entry.ID != naclbitc::UNABBREV_RECORD) {
+ BlockStats.CodeFreq[Code].NumAbbrev++;
+ ++BlockStats.NumAbbreviatedRecords;
+ }
+
+ if (Dump) {
+ outs() << Indent << " <";
+ const char *CodeName =
+ GetCodeName(Code, BlockID, *Stream.getBitStreamReader());
+ if (CodeName)
+ outs() << CodeName;
+ else
+ outs() << "UnknownCode" << Code;
+ if (NonSymbolic && CodeName)
+ outs() << " codeid=" << Code;
+ if (Entry.ID != naclbitc::UNABBREV_RECORD)
+ outs() << " abbrevid=" << Entry.ID;
+
+ for (unsigned i = 0, e = Record.size(); i != e; ++i) {
+ if (OpsPerLine && (i % OpsPerLine) == 0 && i > 0) {
+ outs() << "\n" << Indent << " ";
+ if (CodeName) {
+ for (unsigned j = 0; j < strlen(CodeName); ++j)
+ outs() << " ";
+ } else {
+ outs() << " ";
+ }
+ }
+ outs() << " op" << i << "=" << (int64_t)Record[i];
+ }
+
+ outs() << "/>";
+
+ if (Blob.data()) {
+ outs() << " blob data = ";
+ bool BlobIsPrintable = true;
+ for (unsigned i = 0, e = Blob.size(); i != e; ++i)
+ if (!isprint(static_cast<unsigned char>(Blob[i]))) {
+ BlobIsPrintable = false;
+ break;
+ }
+
+ if (BlobIsPrintable)
+ outs() << "'" << Blob << "'";
+ else
+ outs() << "unprintable, " << Blob.size() << " bytes.";
+ }
+
+ outs() << "\n";
+ }
+ }
+}
+
+static void PrintSize(double Bits) {
+ outs() << format("%.2f/%.2fB/%luW", Bits, Bits/8,(unsigned long)(Bits/32));
+}
+static void PrintSize(uint64_t Bits) {
+ outs() << format("%lub/%.2fB/%luW", (unsigned long)Bits,
+ (double)Bits/8, (unsigned long)(Bits/32));
+}
+
+
+/// AnalyzeBitcode - Analyze the bitcode file specified by InputFilename.
+static int AnalyzeBitcode() {
+ DEBUG(dbgs() << "-> AnalyzeBitcode\n");
+ // Read the input file.
+ OwningPtr<MemoryBuffer> MemBuf;
+
+ if (error_code ec =
+ MemoryBuffer::getFileOrSTDIN(InputFilename.c_str(), MemBuf))
+ return Error("Error reading '" + InputFilename + "': " + ec.message());
+
+ if (MemBuf->getBufferSize() & 3)
+ return Error("Bitcode stream should be a multiple of 4 bytes in length");
+
+ const unsigned char *BufPtr = (const unsigned char *)MemBuf->getBufferStart();
+ const unsigned char *EndBufPtr = BufPtr+MemBuf->getBufferSize();
+
+ NaClBitcodeHeader Header;
+ if (Header.Read(BufPtr, EndBufPtr))
+ return Error("Invalid PNaCl bitcode header");
+
+ if (!Header.IsSupported())
+ errs() << "Warning: " << Header.Unsupported() << "\n";
+
+ if (!Header.IsReadable())
+ Error("Bitcode file is not readable");
+
+ NaClBitstreamReader StreamFile(BufPtr, EndBufPtr);
+ NaClBitstreamCursor Stream(StreamFile);
+ StreamFile.CollectBlockInfoNames();
+
+ unsigned NumTopBlocks = 0;
+
+ // Print out header information.
+ for (size_t i = 0, limit = Header.NumberFields(); i < limit; ++i) {
+ outs() << Header.GetField(i)->Contents() << "\n";
+ }
+ if (Header.NumberFields()) outs() << "\n";
+
+ // Parse the top-level structure. We only allow blocks at the top-level.
+ while (!Stream.AtEndOfStream()) {
+ unsigned Code = Stream.ReadCode();
+ if (Code != naclbitc::ENTER_SUBBLOCK)
+ return Error("Invalid record at top-level");
+
+ unsigned BlockID = Stream.ReadSubBlockID();
+
+ if (ParseBlock(Stream, BlockID, 0))
+ return true;
+ ++NumTopBlocks;
+ }
+
+ if (Dump) outs() << "\n\n";
+
+ uint64_t BufferSizeBits = (EndBufPtr-BufPtr)*CHAR_BIT;
+ // Print a summary of the read file.
+ outs() << "Summary of " << InputFilename << ":\n";
+ outs() << " Total size: ";
+ PrintSize(BufferSizeBits);
+ outs() << "\n";
+ outs() << " # Toplevel Blocks: " << NumTopBlocks << "\n";
+ outs() << "\n";
+
+ // Emit per-block stats.
+ outs() << "Per-block Summary:\n";
+ for (std::map<unsigned, PerBlockIDStats>::iterator I = BlockIDStats.begin(),
+ E = BlockIDStats.end(); I != E; ++I) {
+ outs() << " Block ID #" << I->first;
+ if (const char *BlockName = GetBlockName(I->first, StreamFile))
+ outs() << " (" << BlockName << ")";
+ outs() << ":\n";
+
+ const PerBlockIDStats &Stats = I->second;
+ outs() << " Num Instances: " << Stats.NumInstances << "\n";
+ outs() << " Total Size: ";
+ PrintSize(Stats.NumBits);
+ outs() << "\n";
+ double pct = (Stats.NumBits * 100.0) / BufferSizeBits;
+ outs() << " Percent of file: " << format("%2.4f%%", pct) << "\n";
+ if (Stats.NumInstances > 1) {
+ outs() << " Average Size: ";
+ PrintSize(Stats.NumBits/(double)Stats.NumInstances);
+ outs() << "\n";
+ outs() << " Tot/Avg SubBlocks: " << Stats.NumSubBlocks << "/"
+ << Stats.NumSubBlocks/(double)Stats.NumInstances << "\n";
+ outs() << " Tot/Avg Abbrevs: " << Stats.NumAbbrevs << "/"
+ << Stats.NumAbbrevs/(double)Stats.NumInstances << "\n";
+ outs() << " Tot/Avg Records: " << Stats.NumRecords << "/"
+ << Stats.NumRecords/(double)Stats.NumInstances << "\n";
+ } else {
+ outs() << " Num SubBlocks: " << Stats.NumSubBlocks << "\n";
+ outs() << " Num Abbrevs: " << Stats.NumAbbrevs << "\n";
+ outs() << " Num Records: " << Stats.NumRecords << "\n";
+ }
+ if (Stats.NumRecords) {
+ double pct = (Stats.NumAbbreviatedRecords * 100.0) / Stats.NumRecords;
+ outs() << " Percent Abbrevs: " << format("%2.4f%%", pct) << "\n";
+ }
+ outs() << "\n";
+
+ // Print a histogram of the codes we see.
+ if (!NoHistogram && !Stats.CodeFreq.empty()) {
+ std::vector<std::pair<unsigned, unsigned> > FreqPairs; // <freq,code>
+ for (unsigned i = 0, e = Stats.CodeFreq.size(); i != e; ++i)
+ if (unsigned Freq = Stats.CodeFreq[i].NumInstances)
+ FreqPairs.push_back(std::make_pair(Freq, i));
+ std::stable_sort(FreqPairs.begin(), FreqPairs.end());
+ std::reverse(FreqPairs.begin(), FreqPairs.end());
+
+ outs() << "\tRecord Histogram:\n";
+ outs() << "\t\t Count # Bits %% Abv Record Kind\n";
+ for (unsigned i = 0, e = FreqPairs.size(); i != e; ++i) {
+ const PerRecordStats &RecStats = Stats.CodeFreq[FreqPairs[i].second];
+
+ outs() << format("\t\t%7d %9lu",
+ RecStats.NumInstances,
+ (unsigned long)RecStats.TotalBits);
+
+ if (RecStats.NumAbbrev)
+ outs() <<
+ format("%7.2f ",
+ (double)RecStats.NumAbbrev/RecStats.NumInstances*100);
+ else
+ outs() << " ";
+
+ if (const char *CodeName =
+ GetCodeName(FreqPairs[i].second, I->first, StreamFile))
+ outs() << CodeName << "\n";
+ else
+ outs() << "UnknownCode" << FreqPairs[i].second << "\n";
+ }
+ outs() << "\n";
+
+ }
+ }
+ DEBUG(dbgs() << "<- AnalyzeBitcode\n");
+ return 0;
+}
+
+
+int main(int argc, char **argv) {
+ // Print a stack trace if we signal out.
+ sys::PrintStackTraceOnErrorSignal();
+ PrettyStackTraceProgram X(argc, argv);
+ llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
+ cl::ParseCommandLineOptions(argc, argv, "pnacl-bcanalyzer file analyzer\n");
+
+ return AnalyzeBitcode();
+}
diff --git a/tools/pnacl-freeze/CMakeLists.txt b/tools/pnacl-freeze/CMakeLists.txt
new file mode 100644
index 0000000000..fca58c7d5a
--- /dev/null
+++ b/tools/pnacl-freeze/CMakeLists.txt
@@ -0,0 +1,5 @@
+set(LLVM_LINK_COMPONENTS bitreader naclbitwriter naclbitreader)
+
+add_llvm_tool(pnacl-freeze
+ pnacl-freeze.cpp
+ )
diff --git a/tools/pnacl-freeze/LLVMBuild.txt b/tools/pnacl-freeze/LLVMBuild.txt
new file mode 100644
index 0000000000..8e3499b991
--- /dev/null
+++ b/tools/pnacl-freeze/LLVMBuild.txt
@@ -0,0 +1,16 @@
+;===- ./tools/pnacl-freeze/LLVMBuild.txt -----------------------*- Conf -*--===;
+;===------------------------------------------------------------------------===;
+;
+; 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-freeze
+parent = Tools
+required_libraries = NaClBitWriter BitReader
diff --git a/tools/pnacl-freeze/Makefile b/tools/pnacl-freeze/Makefile
new file mode 100644
index 0000000000..5872f1cd15
--- /dev/null
+++ b/tools/pnacl-freeze/Makefile
@@ -0,0 +1,17 @@
+##===- tools/pnacl-freeze/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-freeze
+LINK_COMPONENTS := naclbitwriter bitreader
+
+# This tool has no plugins, optimize startup time.
+TOOL_NO_EXPORTS := 1
+
+include $(LEVEL)/Makefile.common
diff --git a/tools/pnacl-freeze/pnacl-freeze.cpp b/tools/pnacl-freeze/pnacl-freeze.cpp
new file mode 100644
index 0000000000..297edb85a7
--- /dev/null
+++ b/tools/pnacl-freeze/pnacl-freeze.cpp
@@ -0,0 +1,95 @@
+/* Copyright 2013 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.
+ */
+
+//===-- pnacl-freeze.cpp - The low-level NaCl bitcode freezer --------===//
+//
+//===----------------------------------------------------------------------===//
+//
+// Generates NaCl pexe wire format.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/IR/LLVMContext.h"
+// Note: We need the following to provide the API for calling the NaCl
+// Bitcode Writer to generate the frozen file.
+#include "llvm/Bitcode/NaCl/NaClReaderWriter.h"
+// Note: We need the following to provide the API for calling the (LLVM)
+// Bitcode Reader to read in the corresonding pexe file to freeze.
+#include "llvm/Bitcode/ReaderWriter.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/DataStream.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/ToolOutputFile.h"
+
+using namespace llvm;
+
+
+static cl::opt<std::string>
+OutputFilename("o", cl::desc("Specify output filename"),
+ cl::value_desc("filename"), cl::init("-"));
+
+static cl::opt<std::string>
+InputFilename(cl::Positional, cl::desc("<pexe file>"), cl::init("-"));
+
+static void WriteOutputFile(const Module *M) {
+
+ std::string ErrorInfo;
+ OwningPtr<tool_output_file> Out
+ (new tool_output_file(OutputFilename.c_str(), ErrorInfo,
+ raw_fd_ostream::F_Binary));
+ if (!ErrorInfo.empty()) {
+ errs() << ErrorInfo << '\n';
+ exit(1);
+ }
+
+ NaClWriteBitcodeToFile(M, Out->os());
+
+ // Declare success.
+ Out->keep();
+}
+
+int main(int argc, char **argv) {
+ // Print a stack trace if we signal out.
+ sys::PrintStackTraceOnErrorSignal();
+ PrettyStackTraceProgram X(argc, argv);
+
+ LLVMContext &Context = getGlobalContext();
+ llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
+
+ cl::ParseCommandLineOptions(argc, argv, "Generates NaCl pexe wire format\n");
+
+ std::string ErrorMessage;
+ std::auto_ptr<Module> M;
+
+ // Use the bitcode streaming interface
+ DataStreamer *streamer = getDataFileStreamer(InputFilename, &ErrorMessage);
+ if (streamer) {
+ std::string DisplayFilename;
+ if (InputFilename == "-")
+ DisplayFilename = "<stdin>";
+ else
+ DisplayFilename = InputFilename;
+ M.reset(getStreamedBitcodeModule(DisplayFilename, streamer, Context,
+ &ErrorMessage));
+ if(M.get() != 0 && M->MaterializeAllPermanently(&ErrorMessage)) {
+ M.reset();
+ }
+ }
+
+ if (M.get() == 0) {
+ errs() << argv[0] << ": ";
+ if (ErrorMessage.size())
+ errs() << ErrorMessage << "\n";
+ else
+ errs() << "bitcode didn't read correctly.\n";
+ return 1;
+ }
+
+ WriteOutputFile(M.get());
+ return 0;
+}
diff --git a/tools/pnacl-llc/CMakeLists.txt b/tools/pnacl-llc/CMakeLists.txt
new file mode 100644
index 0000000000..9e53a28aff
--- /dev/null
+++ b/tools/pnacl-llc/CMakeLists.txt
@@ -0,0 +1,9 @@
+set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} bitreader naclbitreader
+ irreader 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..8d441f5a70
--- /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 NaClBitReader IRReader all-targets NaClAnalysis
diff --git a/tools/pnacl-llc/Makefile b/tools/pnacl-llc/Makefile
new file mode 100644
index 0000000000..bf4a0e8be8
--- /dev/null
+++ b/tools/pnacl-llc/Makefile
@@ -0,0 +1,16 @@
+#===- 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 naclbitreader irreader \
+ asmparser naclanalysis nacltransforms
+
+include $(LEVEL)/Makefile.common
+
diff --git a/tools/pnacl-llc/SRPCStreamer.cpp b/tools/pnacl-llc/SRPCStreamer.cpp
new file mode 100644
index 0000000000..c41650c89a
--- /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__)
+#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..8ae0399476
--- /dev/null
+++ b/tools/pnacl-llc/nacl_file.cpp
@@ -0,0 +1,399 @@
+/* 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__)
+
+#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 "native_client/src/untrusted/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;
+
+// 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;
+}
+
+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;
+ }
+ // TODO(eliben): We don't really use shared libraries now. At some
+ // point this should be cleaned up from SRPC as well.
+ out_args[0]->u.ival = false;
+ // SRPC deletes the strings returned when the closure is invoked.
+ // Therefore we need to use strdup.
+ out_args[1]->arrays.str = strdup("");
+ out_args[2]->arrays.str = strdup("");
+ 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..6292001ab1
--- /dev/null
+++ b/tools/pnacl-llc/pnacl-llc.cpp
@@ -0,0 +1,563 @@
+//===-- 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/Bitcode/NaCl/NaClReaderWriter.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/IRReader/IRReader.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 "llvm/Transforms/NaCl.h"
+#include <memory>
+
+
+using namespace llvm;
+
+// NOTE: When __native_client__ is defined it means pnacl-llc is built as a
+// sandboxed translator (from pnacl-llc.pexe to pnacl-llc.nexe). In this mode
+// it uses SRPC operations instead of direct OS intefaces.
+#if defined(__native_client__)
+int GetObjectFileFD();
+DataStreamer* NaClBitcodeStreamer;
+#endif
+
+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"));
+
+cl::opt<NaClFileFormat>
+InputFileFormat(
+ "bitcode-format",
+ cl::desc("Define format of input file:"),
+ cl::values(
+ clEnumValN(LLVMFormat, "llvm", "LLVM file (default)"),
+ clEnumValN(PNaClFormat, "pnacl", "PNaCl bitcode file"),
+ clEnumValEnd),
+ cl::init(LLVMFormat));
+
+// 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>
+UserDefinedTriple("mtriple", cl::desc("Set target triple"));
+
+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;
+ OwningPtr<tool_output_file> FDOut(
+ new tool_output_file(OutputFilename.c_str(), error, OpenFlags));
+ if (!error.empty()) {
+ errs() << error << '\n';
+ return 0;
+ }
+
+ return FDOut.take();
+}
+
+// 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();
+#if !defined(__native_client__)
+ // Prune asm parsing from sandboxed translator.
+ // Do not prune "AsmPrinters" because that includes
+ // the direct object emission.
+ InitializeAllAsmParsers();
+#endif
+
+ // Initialize codegen and IR passes used by llc so that the -print-after,
+ // -print-before, and -stop-after options work.
+ PassRegistry *Registry = PassRegistry::getPassRegistry();
+ initializeCore(*Registry);
+ initializeCodeGen(*Registry);
+ initializeLoopStrengthReducePass(*Registry);
+ initializeLowerIntrinsicsPass(*Registry);
+ initializeUnreachableBlockElimPass(*Registry);
+
+ // Register the target printer for --version.
+ cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion);
+
+ // Enable the PNaCl ABI verifier by default in sandboxed mode.
+#if defined(__native_client__)
+ PNaClABIVerify = true;
+ PNaClABIVerifyFatalErrors = true;
+#endif
+
+ cl::ParseCommandLineOptions(argc, argv, "pnacl-llc\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;
+}
+
+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();
+}
+
+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;
+
+ PNaClABIErrorReporter ABIErrorReporter;
+
+#if defined(__native_client__)
+ if (LazyBitcode) {
+ std::string StrError;
+ M.reset(getNaClStreamedBitcodeModule(
+ std::string("<SRPC stream>"),
+ NaClBitcodeStreamer, Context, &StrError));
+ if (!StrError.empty())
+ Err = SMDiagnostic(InputFilename, SourceMgr::DK_Error, StrError);
+ } else {
+ llvm_unreachable("native client SRPC only supports streaming");
+ }
+#else
+ {
+ // TODO: after the next merge this can be removed.
+ // https://code.google.com/p/nativeclient/issues/detail?id=3349
+ NamedRegionTimer T(TimeIRParsingName, TimeIRParsingGroupName,
+ TimeIRParsingIsEnabled);
+ M.reset(NaClParseIRFile(InputFilename, InputFileFormat, Err, Context));
+ }
+#endif
+
+ mod = M.get();
+ if (mod == 0) {
+ Err.print(argv[0], errs());
+ return 1;
+ }
+
+ if (PNaClABIVerify) {
+ // Verify the module (but not the functions yet)
+ ModulePass *VerifyPass = createPNaClABIVerifyModulePass(&ABIErrorReporter,
+ LazyBitcode);
+ VerifyPass->runOnModule(*mod);
+ CheckABIVerifyErrors(ABIErrorReporter, "Module");
+ }
+
+ // Add declarations for external functions required by PNaCl. The
+ // ResolvePNaClIntrinsics function pass running during streaming
+ // depends on these declarations being in the module.
+ OwningPtr<ModulePass> AddPNaClExternalDeclsPass(
+ createAddPNaClExternalDeclsPass());
+ AddPNaClExternalDeclsPass->runOnModule(*mod);
+
+ if (UserDefinedTriple.empty()) {
+ report_fatal_error("-mtriple must be set to a target triple for pnacl-llc");
+ } else {
+ mod->setTargetTriple(Triple::normalize(UserDefinedTriple));
+ TheTriple = Triple(mod->getTargetTriple());
+ }
+
+ // 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;
+ 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(__native_client__)
+ // 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.
+ 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);
+ }
+
+ // Add the intrinsic resolution pass. It assumes ABI-conformant code.
+ PM->add(createResolvePNaClIntrinsicsPass());
+
+ // Add an appropriate TargetLibraryInfo pass for the module's triple.
+ TargetLibraryInfo *TLI = new TargetLibraryInfo(TheTriple);
+ if (DisableSimplifyLibCalls)
+ TLI->disableAllFunctions();
+ PM->add(TLI);
+
+ // 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__
+ {
+ 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(__native_client__)
+int
+main (int argc, char **argv) {
+ return llc_main(argc, argv);
+}
+#else
+// main() is in nacl_file.cpp.
+#endif
diff --git a/tools/pnacl-thaw/CMakeLists.txt b/tools/pnacl-thaw/CMakeLists.txt
new file mode 100644
index 0000000000..91b818efe6
--- /dev/null
+++ b/tools/pnacl-thaw/CMakeLists.txt
@@ -0,0 +1,5 @@
+set(LLVM_LINK_COMPONENTS bitwriter naclbitreader)
+
+add_llvm_tool(pnacl-thaw
+ pnacl-thaw.cpp
+ )
diff --git a/tools/pnacl-thaw/LLVMBuild.txt b/tools/pnacl-thaw/LLVMBuild.txt
new file mode 100644
index 0000000000..864da2cbd5
--- /dev/null
+++ b/tools/pnacl-thaw/LLVMBuild.txt
@@ -0,0 +1,16 @@
+;===- ./tools/pnacl-thaw/LLVMBuild.txt -----------------------*- Conf -*--===;
+;===------------------------------------------------------------------------===;
+;
+; 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-thaw
+parent = Tools
+required_libraries = BitWriter NaClBitReader
diff --git a/tools/pnacl-thaw/Makefile b/tools/pnacl-thaw/Makefile
new file mode 100644
index 0000000000..8e7699e185
--- /dev/null
+++ b/tools/pnacl-thaw/Makefile
@@ -0,0 +1,17 @@
+##===- tools/pnacl-thaw/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-thaw
+LINK_COMPONENTS := bitwriter naclbitreader
+
+# This tool has no plugins, optimize startup time.
+TOOL_NO_EXPORTS := 1
+
+include $(LEVEL)/Makefile.common
diff --git a/tools/pnacl-thaw/pnacl-thaw.cpp b/tools/pnacl-thaw/pnacl-thaw.cpp
new file mode 100644
index 0000000000..7f27bd58fc
--- /dev/null
+++ b/tools/pnacl-thaw/pnacl-thaw.cpp
@@ -0,0 +1,96 @@
+/* Copyright 2013 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.
+ */
+
+//===-- pnacl-thaw.cpp - The low-level NaCl bitcode thawer ----------------===//
+//
+//===----------------------------------------------------------------------===//
+//
+// Converts NaCl wire format back to LLVM bitcode.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/IR/LLVMContext.h"
+// Note: We need the following to provide the API for calling the NaCl
+// Bitcode Reader to read the frozen file.
+#include "llvm/Bitcode/NaCl/NaClReaderWriter.h"
+// Note: We need the following to provide the API for calling the (LLVM)
+// Bitcode Writer to generate the corresponding LLVM bitcode file.
+#include "llvm/Bitcode/ReaderWriter.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/DataStream.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/ToolOutputFile.h"
+
+using namespace llvm;
+
+static cl::opt<std::string>
+OutputFilename("o", cl::desc("Specify thawed pexe filename"),
+ cl::value_desc("filename"), cl::init("-"));
+
+static cl::opt<std::string>
+InputFilename(cl::Positional, cl::desc("<frozen file>"), cl::init("-"));
+
+static void WriteOutputFile(const Module *M) {
+
+ std::string ErrorInfo;
+ OwningPtr<tool_output_file> Out
+ (new tool_output_file(OutputFilename.c_str(), ErrorInfo,
+ raw_fd_ostream::F_Binary));
+ if (!ErrorInfo.empty()) {
+ errs() << ErrorInfo << '\n';
+ exit(1);
+ }
+
+ WriteBitcodeToFile(M, Out->os());
+
+ // Declare success.
+ Out->keep();
+}
+
+int main(int argc, char **argv) {
+ // Print a stack trace if we signal out.
+ sys::PrintStackTraceOnErrorSignal();
+ PrettyStackTraceProgram X(argc, argv);
+
+ LLVMContext &Context = getGlobalContext();
+ llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
+
+ cl::ParseCommandLineOptions(
+ argc, argv, "Converts NaCl pexe wire format into LLVM bitcode format\n");
+
+ std::string ErrorMessage;
+ std::auto_ptr<Module> M;
+
+ // Use the bitcode streaming interface
+ DataStreamer *streamer = getDataFileStreamer(InputFilename, &ErrorMessage);
+ if (streamer) {
+ std::string DisplayFilename;
+ if (InputFilename == "-")
+ DisplayFilename = "<stdin>";
+ else
+ DisplayFilename = InputFilename;
+ M.reset(getNaClStreamedBitcodeModule(
+ DisplayFilename, streamer, Context,
+ &ErrorMessage, /*AcceptSupportedOnly=*/false));
+ if(M.get() != 0 && M->MaterializeAllPermanently(&ErrorMessage)) {
+ M.reset();
+ }
+ }
+
+ if (M.get() == 0) {
+ errs() << argv[0] << ": ";
+ if (ErrorMessage.size())
+ errs() << ErrorMessage << "\n";
+ else
+ errs() << "bitcode didn't read correctly.\n";
+ return 1;
+ }
+
+ WriteOutputFile(M.get());
+ return 0;
+}
diff --git a/tools/pso-stub/CMakeLists.txt b/tools/pso-stub/CMakeLists.txt
new file mode 100644
index 0000000000..4b2f779cb0
--- /dev/null
+++ b/tools/pso-stub/CMakeLists.txt
@@ -0,0 +1,5 @@
+set(LLVM_LINK_COMPONENTS bitreader bitwriter object support analysis)
+
+add_llvm_tool(pso-stub
+ pso-stub.cpp
+ )
diff --git a/tools/pso-stub/LLVMBuild.txt b/tools/pso-stub/LLVMBuild.txt
new file mode 100644
index 0000000000..e643053dbf
--- /dev/null
+++ b/tools/pso-stub/LLVMBuild.txt
@@ -0,0 +1,22 @@
+;===- ./tools/pso-stub/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 = pso-stub
+parent = Tools
+required_libraries = BitReader BitWriter Object Support Analysis
diff --git a/tools/pso-stub/Makefile b/tools/pso-stub/Makefile
new file mode 100644
index 0000000000..c2860e65f6
--- /dev/null
+++ b/tools/pso-stub/Makefile
@@ -0,0 +1,18 @@
+##===- tools/pso-stub/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 := pso-stub
+LINK_COMPONENTS := bitreader bitwriter object support analysis
+
+# This tool has no plugins, optimize startup time.
+TOOL_NO_EXPORTS := 1
+
+include $(LEVEL)/Makefile.common
+
diff --git a/tools/pso-stub/pso-stub.cpp b/tools/pso-stub/pso-stub.cpp
new file mode 100644
index 0000000000..26ce0c5056
--- /dev/null
+++ b/tools/pso-stub/pso-stub.cpp
@@ -0,0 +1,309 @@
+/*===- pso-stub.c - Create bitcode shared object stubs -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Create a bitcode stub for a native shared object.
+// Usage: pso-stub <input.so> -o <output.pso>
+//
+// The stub bitcode file contains the same dynamic symbols as the input shared
+// object, with identical attributes (e.g. weak, undefined, TLS).
+//
+// Undefined functions become declarations in the bitcode.
+// Undefined variables become external variable declarations in the bitcode.
+// Defined functions become trivial stub functions in the bitcode (which do
+// nothing but "ret void").
+// Defined object/tls symbols became dummy variable definitions (int foo = 0).
+//
+// The generated bitcode is suitable for linking against (as a shared object),
+// but nothing else.
+//
+// TODO(pdox): Implement GNU symbol versioning.
+// TODO(pdox): Mark IFUNC symbols as functions, and store
+// this attribute as metadata.
+//===----------------------------------------------------------------------===*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/GlobalValue.h"
+#include "llvm/IR/Type.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Constant.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Analysis/Verifier.h"
+#include "llvm/Bitcode/ReaderWriter.h"
+#include "llvm/Support/ToolOutputFile.h"
+#include "llvm/Support/ELF.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/FormattedStream.h"
+#include "llvm/ADT/APInt.h"
+
+using namespace llvm;
+using namespace llvm::object;
+
+namespace {
+
+cl::opt<std::string>
+InputFilename(cl::Positional, cl::desc("<input native shared object>"),
+ cl::init(""));
+
+cl::opt<std::string>
+OutputFilename("o", cl::desc("Output filename"), cl::value_desc("filename"));
+
+// Variables / declarations to place in llvm.used array.
+std::vector<GlobalValue*> LLVMUsed;
+
+void AddUsedGlobal(GlobalValue *GV) {
+ // Clang normally asserts that these are not decls. We do need
+ // decls to survive though, and those are really the ones we
+ // worry about, so only add those.
+ // We run verifyModule() below, so that we know this is somewhat valid.
+ if (GV->isDeclaration()) {
+ LLVMUsed.push_back(GV);
+ }
+}
+
+// Emit llvm.used array.
+// This is almost exactly like clang/lib/CodeGen/CodeGenModule.cpp::EmitLLVMUsed
+void EmitLLVMUsed(Module *M) {
+ // Don't create llvm.used if there is no need.
+ if (LLVMUsed.empty())
+ return;
+
+ Type *Int8PtrTy = Type::getInt8PtrTy(M->getContext());
+ // Convert LLVMUsed to what ConstantArray needs.
+ SmallVector<llvm::Constant*, 8> UsedArray;
+ UsedArray.resize(LLVMUsed.size());
+ for (unsigned i = 0, e = LLVMUsed.size(); i != e; ++i) {
+ UsedArray[i] =
+ llvm::ConstantExpr::getBitCast(cast<llvm::Constant>(&*LLVMUsed[i]),
+ Int8PtrTy);
+ }
+
+ if (UsedArray.empty())
+ return;
+ llvm::ArrayType *ATy = llvm::ArrayType::get(Int8PtrTy, UsedArray.size());
+
+ llvm::GlobalVariable *GV =
+ new llvm::GlobalVariable(*M, ATy, false,
+ llvm::GlobalValue::AppendingLinkage,
+ llvm::ConstantArray::get(ATy, UsedArray),
+ "llvm.used");
+
+ GV->setSection("llvm.metadata");
+}
+
+// Add a stub function definition or declaration
+void
+AddFunction(Module *M,
+ GlobalValue::LinkageTypes Linkage,
+ const StringRef &Name,
+ bool isDefine) {
+ // Create an empty function with no arguments.
+ // void Name(void);
+ Type *RetTy = Type::getVoidTy(M->getContext());
+ FunctionType *FT = FunctionType::get(RetTy, /*isVarArg=*/ false);
+ Function *F = Function::Create(FT, Linkage, Name, M);
+ if (isDefine) {
+ // Add a single basic block with "ret void"
+ BasicBlock *BB = BasicBlock::Create(F->getContext(), "", F);
+ BB->getInstList().push_back(ReturnInst::Create(F->getContext()));
+ }
+ AddUsedGlobal(F);
+}
+
+// Add a stub global variable declaration or definition.
+void
+AddGlobalVariable(Module *M,
+ GlobalValue::LinkageTypes Linkage,
+ const StringRef &Name,
+ bool isTLS,
+ bool isDefine) {
+ // Use 'int' as the dummy type.
+ Type *Ty = Type::getInt32Ty(M->getContext());
+
+ Constant *InitVal = NULL;
+ if (isDefine) {
+ // Define to dummy value, 0.
+ InitVal = Constant::getIntegerValue(Ty, APInt(32, 0));
+ }
+ GlobalVariable *GV =
+ new GlobalVariable(*M, Ty, /*isConstant=*/ false,
+ Linkage, /*Initializer=*/ InitVal,
+ Twine(Name), /*InsertBefore=*/ NULL,
+ isTLS ? GlobalVariable::GeneralDynamicTLSModel :
+ GlobalVariable::NotThreadLocal,
+ /*AddressSpace=*/ 0);
+ AddUsedGlobal(GV);
+}
+
+// Iterate through the ObjectFile's needed libraries, and
+// add them to the module.
+void TransferLibrariesNeeded(Module *M, const ObjectFile *obj) {
+ library_iterator it = obj->begin_libraries_needed();
+ library_iterator ie = obj->end_libraries_needed();
+ error_code ec;
+ for (; it != ie; it.increment(ec)) {
+ StringRef path;
+ it->getPath(path);
+ outs() << "Adding library " << path << "\n";
+ M->addLibrary(path);
+ }
+}
+
+// Set the Module's SONAME from the ObjectFile
+void TransferLibraryName(Module *M, const ObjectFile *obj) {
+ StringRef soname = obj->getLoadName();
+ outs() << "Setting soname to: " << soname << "\n";
+ M->setSOName(soname);
+}
+
+// Create stubs in the module for the dynamic symbols
+void TransferDynamicSymbols(Module *M, const ObjectFile *obj) {
+ // Iterate through the dynamic symbols in the ObjectFile.
+ symbol_iterator it = obj->begin_dynamic_symbols();
+ symbol_iterator ie = obj->end_dynamic_symbols();
+ error_code ec;
+ for (; it != ie; it.increment(ec)) {
+ const SymbolRef &sym = *it;
+ StringRef Name;
+ SymbolRef::Type Type;
+ uint32_t Flags;
+
+ sym.getName(Name);
+ sym.getType(Type);
+ sym.getFlags(Flags);
+
+ // Ignore debug info and section labels
+ if (Flags & SymbolRef::SF_FormatSpecific)
+ continue;
+
+ // Ignore local symbols
+ if (!(Flags & SymbolRef::SF_Global))
+ continue;
+ outs() << "Transferring symbol " << Name << "\n";
+
+ bool isFunc = (Type == SymbolRef::ST_Function);
+ bool isUndef = (Flags & SymbolRef::SF_Undefined);
+ bool isTLS = (Flags & SymbolRef::SF_ThreadLocal);
+ bool isCommon = (Flags & SymbolRef::SF_Common);
+ bool isWeak = (Flags & SymbolRef::SF_Weak);
+
+ if (Type == SymbolRef::ST_Unknown) {
+ // Weak symbols can be "v" according to NM, which are definitely
+ // data, but they may also be "w", which are of unknown type.
+ // Thus there is already a mechanism to say "weak object", but not
+ // for weak function. Assume unknown weak symbols are functions.
+ if (isWeak) {
+ outs() << "Warning: Symbol '" << Name <<
+ "' has unknown type (weak). Assuming function.\n";
+ Type = SymbolRef::ST_Function;
+ isFunc = true;
+ } else {
+ // If it is undef, we likely don't care, since it won't be used
+ // to bind to unresolved symbols in the real pexe and real pso.
+ // Other cases seen where it is not undef: _end, __bss_start,
+ // which are markers provided by the linker scripts.
+ outs() << "Warning: Symbol '" << Name <<
+ "' has unknown type (isUndef=" << isUndef << "). Assuming data.\n";
+ Type = SymbolRef::ST_Data;
+ isFunc = false;
+ }
+ }
+
+ // Determine Linkage type.
+ GlobalValue::LinkageTypes Linkage;
+ if (isWeak)
+ Linkage = isUndef ? GlobalValue::ExternalWeakLinkage :
+ GlobalValue::WeakAnyLinkage;
+ else if (isCommon)
+ Linkage = GlobalValue::CommonLinkage;
+ else
+ Linkage = GlobalValue::ExternalLinkage;
+
+ if (isFunc)
+ AddFunction(M, Linkage, Name, !isUndef);
+ else
+ AddGlobalVariable(M, Linkage, Name, isTLS, !isUndef);
+ }
+}
+
+} // namespace
+
+
+int main(int argc, const char** argv) {
+ sys::PrintStackTraceOnErrorSignal();
+ PrettyStackTraceProgram X(argc, argv);
+ LLVMContext &Context = getGlobalContext();
+ llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
+
+ cl::ParseCommandLineOptions(argc, argv,
+ "Portable Shared Object Stub Maker\n");
+
+ if (InputFilename.empty()) {
+ errs() << "Please specify an input filename\n";
+ return 1;
+ }
+ if (OutputFilename.empty()) {
+ errs() << "Please specify an output filename with -o\n";
+ return 1;
+ }
+
+ // Open the object file
+ OwningPtr<MemoryBuffer> File;
+ if (MemoryBuffer::getFile(InputFilename, File)) {
+ errs() << InputFilename << ": Open failed\n";
+ return 1;
+ }
+
+ ObjectFile *obj = ObjectFile::createObjectFile(File.take());
+ if (!obj) {
+ errs() << InputFilename << ": Object type not recognized\n";
+ }
+
+ // Create the new module
+ OwningPtr<Module> M(new Module(InputFilename, Context));
+
+ // Transfer the relevant ELF information
+ M->setOutputFormat(Module::SharedOutputFormat);
+ TransferLibrariesNeeded(M.get(), obj);
+ TransferLibraryName(M.get(), obj);
+ TransferDynamicSymbols(M.get(), obj);
+ EmitLLVMUsed(M.get());
+
+ // Verify the module
+ std::string Err;
+ if (verifyModule(*M.get(), ReturnStatusAction, &Err)) {
+ errs() << "Module created is invalid:\n";
+ errs() << Err;
+ return 1;
+ }
+
+ // Write the module to a file
+ std::string ErrorInfo;
+ OwningPtr<tool_output_file> Out(
+ new tool_output_file(OutputFilename.c_str(), ErrorInfo,
+ raw_fd_ostream::F_Binary));
+ if (!ErrorInfo.empty()) {
+ errs() << ErrorInfo << '\n';
+ return 1;
+ }
+ WriteBitcodeToFile(M.get(), Out->os());
+ Out->keep();
+ return 0;
+}