diff options
author | Eli Bendersky <eliben@chromium.org> | 2013-06-12 10:59:49 -0700 |
---|---|---|
committer | Eli Bendersky <eliben@chromium.org> | 2013-06-12 10:59:49 -0700 |
commit | 062f575e014d80540f28fa7f25eab152a8ac383a (patch) | |
tree | 9aaafcc8c8d8931fa2408b6ff2d87463df52afe3 /tools | |
parent | fa73be99dbaff288f473438093587ea9e2590c07 (diff) |
Revert llc to upstream
tools/llc is reset to revision 279b9184c2ff4fea93b198a3519b8cb3a1d8d195
from which the last LLVM merge was made. NaCl-specific files are
removed.
BUG=None
R=jvoung@chromium.org
Review URL: https://codereview.chromium.org/16510008
Diffstat (limited to 'tools')
-rw-r--r-- | tools/llc/CMakeLists.txt | 8 | ||||
-rw-r--r-- | tools/llc/ELFStub.h | 55 | ||||
-rw-r--r-- | tools/llc/LLVMBuild.txt | 2 | ||||
-rw-r--r-- | tools/llc/Makefile | 3 | ||||
-rw-r--r-- | tools/llc/SRPCStreamer.cpp | 142 | ||||
-rw-r--r-- | tools/llc/SRPCStreamer.h | 117 | ||||
-rw-r--r-- | tools/llc/StubMaker.cpp | 233 | ||||
-rw-r--r-- | tools/llc/StubMaker.h | 20 | ||||
-rw-r--r-- | tools/llc/TextStubWriter.cpp | 84 | ||||
-rw-r--r-- | tools/llc/TextStubWriter.h | 12 | ||||
-rw-r--r-- | tools/llc/llc.cpp | 357 | ||||
-rw-r--r-- | tools/llc/nacl_file.cpp | 422 |
12 files changed, 13 insertions, 1442 deletions
diff --git a/tools/llc/CMakeLists.txt b/tools/llc/CMakeLists.txt index da09babf46..683f29862d 100644 --- a/tools/llc/CMakeLists.txt +++ b/tools/llc/CMakeLists.txt @@ -1,11 +1,5 @@ -set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} bitreader naclbitreader - irreader asmparser naclanalysis) +set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} bitreader asmparser) add_llvm_tool(llc -# This file provides wrappers to lseek(2), read(2), etc. - nacl_file.cpp - SRPCStreamer.cpp - StubMaker.cpp - TextStubWriter.cpp llc.cpp ) diff --git a/tools/llc/ELFStub.h b/tools/llc/ELFStub.h deleted file mode 100644 index a79fecff0f..0000000000 --- a/tools/llc/ELFStub.h +++ /dev/null @@ -1,55 +0,0 @@ -// This file describes a simple high-level representation of an ELF stub. - -#ifndef __ELF_STUB_H -#define __ELF_STUB_H - -#include <llvm/Support/ELF.h> -#include <llvm/ADT/StringMap.h> -#include <string> -#include <vector> - -namespace llvm { - -struct SymbolStub; -struct VersionDefinition; - -using ELF::Elf32_Half; - -struct ELFStub { - Elf32_Half Machine; - std::string SOName; - std::vector<SymbolStub> Symbols; - std::vector<VersionDefinition> VerDefs; - - // These are used for constructing the version definitions. - // They are not directly emitted to the ELF stub. - StringMap<Elf32_Half> IndexMap; // Maps version name to version index. - Elf32_Half NextIndex; // Next available version index -}; - - -// Dynamic symbol entries -struct SymbolStub { - // Symbol Table info. - std::string Name; - unsigned char Type; // STT_* - unsigned char Binding; // STB_* - unsigned char Visibility; // STV_* - ELF::Elf32_Word Size; // Guess for st_size. - // st_value, etc. are stubbed out. - - // Version info matching each of the symbols. - Elf32_Half VersionIndex; // vd_ndx - bool IsDefault; -}; - -// Versions defined in this module -struct VersionDefinition { - Elf32_Half Index; // vd_ndx - bool IsWeak; // TODO(pdox): Implement this (for vd_flags) - std::string Name; // for vda_name, etc. - std::vector<std::string> Parents; // TODO(pdox): Implement this -}; - -} -#endif diff --git a/tools/llc/LLVMBuild.txt b/tools/llc/LLVMBuild.txt index ab1863a6eb..8c8794f620 100644 --- a/tools/llc/LLVMBuild.txt +++ b/tools/llc/LLVMBuild.txt @@ -19,4 +19,4 @@ type = Tool name = llc parent = Tools -required_libraries = AsmParser BitReader NaClBitReader IRReader all-targets NaClAnalysis +required_libraries = AsmParser BitReader all-targets diff --git a/tools/llc/Makefile b/tools/llc/Makefile index c15af18c34..b32d5575d5 100644 --- a/tools/llc/Makefile +++ b/tools/llc/Makefile @@ -9,8 +9,7 @@ LEVEL := ../.. TOOLNAME := llc -LINK_COMPONENTS := all-targets bitreader naclbitreader irreader \ - asmparser naclanalysis nacltransforms +LINK_COMPONENTS := all-targets bitreader asmparser include $(LEVEL)/Makefile.common diff --git a/tools/llc/SRPCStreamer.cpp b/tools/llc/SRPCStreamer.cpp deleted file mode 100644 index ae70a24822..0000000000 --- a/tools/llc/SRPCStreamer.cpp +++ /dev/null @@ -1,142 +0,0 @@ -//===-- SRPCStreamer.cpp - Stream bitcode over SRPC ----------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// -// -//===----------------------------------------------------------------------===// - -#if defined(__native_client__) && defined(NACL_SRPC) -#define DEBUG_TYPE "bitcode-stream" -#include "SRPCStreamer.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/raw_ostream.h" -#include <errno.h> - -using llvm::dbgs; - -const size_t QueueStreamer::queuesize_limit_; - -size_t QueueStreamer::GetBytes(unsigned char *buf, size_t len) { - size_t total_copied = 0; - pthread_mutex_lock(&Mutex); - while (!Done && queueSize() < len - total_copied) { - size_t size = queueSize(); - DEBUG(dbgs() << "QueueStreamer::GetBytes len " << len << " size " << - size << " << waiting\n"); - queueGet(buf + total_copied, size); - total_copied += size; - pthread_cond_signal(&Cond); - pthread_cond_wait(&Cond, &Mutex); - } - // If this is the last partial chunk, adjust len such that the amount we - // fetch will be just the remaining bytes. - if (Done && queueSize() < len - total_copied) { - len = queueSize() + total_copied; - } - queueGet(buf + total_copied, len - total_copied); - pthread_cond_signal(&Cond); - pthread_mutex_unlock(&Mutex); - return len; -} - -size_t QueueStreamer::PutBytes(unsigned char *buf, size_t len) { - size_t total_copied = 0; - pthread_mutex_lock(&Mutex); - while (capacityRemaining() < len - total_copied) { - if (Bytes.size() * 2 > queuesize_limit_) { - size_t space = capacityRemaining(); - queuePut(buf + total_copied, space); - total_copied += space; - pthread_cond_signal(&Cond); - pthread_cond_wait(&Cond, &Mutex); - } else { - queueResize(); - } - } - queuePut(buf + total_copied, len - total_copied); - pthread_cond_signal(&Cond); - pthread_mutex_unlock(&Mutex); - return len; -} - -void QueueStreamer::SetDone() { - // Still need the lock to avoid signaling between the check and - // the wait in GetBytes. - pthread_mutex_lock(&Mutex); - Done = true; - pthread_cond_signal(&Cond); - pthread_mutex_unlock(&Mutex); -} - -// Double the size of the queue. Called with Mutex to protect Cons/Prod/Bytes. -void QueueStreamer::queueResize() { - int leftover = Bytes.size() - Cons; - DEBUG(dbgs() << "resizing to " << Bytes.size() * 2 << " " << leftover << " " - << Prod << " " << Cons << "\n"); - Bytes.resize(Bytes.size() * 2); - if (Cons > Prod) { - // There are unread bytes left between Cons and the previous end of the - // buffer. Move them to the new end of the buffer. - memmove(&Bytes[Bytes.size() - leftover], &Bytes[Cons], leftover); - Cons = Bytes.size() - leftover; - } -} - -// Called with Mutex held to protect Cons, Prod, and Bytes -void QueueStreamer::queuePut(unsigned char *buf, size_t len) { - size_t EndSpace = std::min(len, Bytes.size() - Prod); - DEBUG(dbgs() << "put, len " << len << " Endspace " << EndSpace << " p " << - Prod << " c " << Cons << "\n"); - // Copy up to the end of the buffer - memcpy(&Bytes[Prod], buf, EndSpace); - // Wrap around if necessary - memcpy(&Bytes[0], buf + EndSpace, len - EndSpace); - Prod = (Prod + len) % Bytes.size(); -} - -// Called with Mutex held to protect Cons, Prod, and Bytes -void QueueStreamer::queueGet(unsigned char *buf, size_t len) { - assert(len <= queueSize()); - size_t EndSpace = std::min(len, Bytes.size() - Cons); - DEBUG(dbgs() << "get, len " << len << " Endspace " << EndSpace << " p " << - Prod << " c " << Cons << "\n"); - // Copy up to the end of the buffer - memcpy(buf, &Bytes[Cons], EndSpace); - // Wrap around if necessary - memcpy(buf + EndSpace, &Bytes[0], len - EndSpace); - Cons = (Cons + len) % Bytes.size(); -} - -llvm::DataStreamer *SRPCStreamer::init(void *(*Callback)(void *), void *arg, - std::string *ErrMsg) { - int err = pthread_create(&CompileThread, NULL, Callback, arg); - if (err) { - if (ErrMsg) *ErrMsg = std::string(strerror(errno)); - return NULL; - } - return &Q; -} - -size_t SRPCStreamer::gotChunk(unsigned char *bytes, size_t len) { - if (Error) return 0; - return Q.PutBytes(bytes, len); -} - -int SRPCStreamer::streamEnd(std::string *ErrMsg) { - Q.SetDone(); - int err = pthread_join(CompileThread, NULL); - if (err) { - if (ErrMsg) *ErrMsg = std::string(strerror(errno)); - return err; - } - if (Error && ErrMsg) *ErrMsg = std::string("compile failed."); - return Error; -} - -#endif diff --git a/tools/llc/SRPCStreamer.h b/tools/llc/SRPCStreamer.h deleted file mode 100644 index 4c1c6737e6..0000000000 --- a/tools/llc/SRPCStreamer.h +++ /dev/null @@ -1,117 +0,0 @@ -//===-- 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/llc/StubMaker.cpp b/tools/llc/StubMaker.cpp deleted file mode 100644 index d5ddf5f88f..0000000000 --- a/tools/llc/StubMaker.cpp +++ /dev/null @@ -1,233 +0,0 @@ -// Create a high-level representation of the needed library. - -#include "StubMaker.h" - -#include "llvm/ADT/StringMap.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/Triple.h" -#include "llvm/IR/DerivedTypes.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/Type.h" -#include "llvm/Support/ELF.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/Debug.h" -#include "ELFStub.h" - -using namespace llvm; - -// Extract the Name, Version, and IsDefault flag from the FullName string. -// e.g. foo@V1 --> foo, V1, false -// bar@@V2 --> bar, V2, true -static void ExtractVersion(StringRef FullName, - StringRef &Name, - StringRef &Version, - bool &IsDefault) { - size_t atpos = FullName.find('@'); - if (atpos == StringRef::npos) { - Name = FullName; - Version = ""; - IsDefault = false; - return; - } - Name = FullName.substr(0, atpos); - ++atpos; - if (FullName[atpos] == '@') { - IsDefault = true; - ++atpos; - } else { - IsDefault = false; - } - Version = FullName.substr(atpos); -} - - -// This implicitly creates a version record as a result of locating a symbol -// with this version. There is normally more information attached to a -// version definition: the parent version(s) and definition flags (weak -// or base). This information is currently not stored in the bitcode -// module. It may be necessary to add this in the future. -static Elf32_Half AddVersionDef(ELFStub *Stub, StringRef Name) { - VersionDefinition VD; - VD.Name = Name; - VD.Index = Stub->NextIndex++; - VD.IsWeak = false; // TODO(pdox): Implement - VD.Parents.clear(); // TODO(pdox): Implement - Stub->VerDefs.push_back(VD); - Stub->IndexMap[VD.Name] = VD.Index; - return VD.Index; -} - -static Elf32_Half GetVersionIndex(StringRef Version, ELFStub *Stub) { - // Handle unversioned symbols - if (Version.empty()) - return 1; /* ELF::VER_NDX_GLOBAL */ - // Find the version definition, if it already exists. - StringMap<Elf32_Half>::const_iterator I = Stub->IndexMap.find(Version); - if (I != Stub->IndexMap.end()) { - return I->second; - } - // If not, create it. - return AddVersionDef(Stub, Version); -} - -static Elf32_Half GetELFMachine(const Triple &T) { - switch (T.getArch()) { - default: llvm_unreachable("Unknown target triple in StubMaker.cpp"); - case Triple::x86_64: return ELF::EM_X86_64; - case Triple::x86: return ELF::EM_386; - case Triple::arm: return ELF::EM_ARM; - case Triple::mipsel: return ELF::EM_MIPS; - } -} - -static unsigned char GetELFVisibility(const GlobalValue *GV) { - switch (GV->getVisibility()) { - case GlobalValue::DefaultVisibility: return ELF::STV_DEFAULT; - case GlobalValue::HiddenVisibility: return ELF::STV_HIDDEN; - case GlobalValue::ProtectedVisibility: return ELF::STV_PROTECTED; - } - llvm_unreachable("Unknown visibility in GETELFVisibility"); -} - -static ELF::Elf32_Word GetElfSizeForType(const GlobalValue *GV, - const Type *ElemType) { - unsigned bit_size = ElemType->getPrimitiveSizeInBits(); - if (bit_size != 0) { - // Check against 0 to see if it was actually a primitive. - return bit_size / 8; - } - if (isa<PointerType>(ElemType)) { - // Pointers are 32-bit for NaCl. - return 4; - } - if (isa<FunctionType>(ElemType)) { - // This is not a data object, so just say unknown (0). - return 0; - } - if (const ArrayType *ATy = dyn_cast<ArrayType>(ElemType)) { - unsigned elem_size = GetElfSizeForType(GV, ATy->getElementType()); - unsigned num_elems = ATy->getNumElements(); - // TODO(jvoung): Come up with a test for what to do with 0-length arrays. - // Not sure what to do here actually. It may be that the 0-length - // array is meant to be an opaque type, which you can never check the - // "sizeof". For now, return 0 instead of asserting. - // Known instance of this in library code is in basic_string.h: - // static size_type _S_empty_rep_storage[]; - return elem_size * num_elems; - } - if (const VectorType *VTy = dyn_cast<VectorType>(ElemType)) { - unsigned bit_width = VTy->getBitWidth(); - if (bit_width) { - return bit_width / 8; - } else { - // It's a vector of pointers, and pointers are 32-bit in NaCl - return VTy->getNumElements() * 4; - } - } - if (const StructType *STy = dyn_cast<StructType>(ElemType)) { - // Alignment padding should have been added to the type in the front-end. - unsigned size_so_far = 0; - for (unsigned i = 0; i < STy->getNumElements(); ++i) { - size_so_far += GetElfSizeForType(GV, STy->getElementType(i)); - } - return size_so_far; - } - // Unknown type! - DEBUG({ - dbgs() << "Unknown GetELFSize for var="; - GV->dump(); - dbgs() << " type= "; - ElemType->dump(); - dbgs() << "\n"; - }); - llvm_unreachable("Unhandled type for GetELFSize"); - return 0; -} - -// Return a value for the symbol table's st_size, which is the number of bytes -// in a data object. Functions may report unknown size 0 (not data objects). -// This is known to be important for symbols that may sit in BSS -// with copy relocations (to know how much to copy). -static ELF::Elf32_Word GetELFSize(const GlobalValue *GV) { - const class PointerType *PT = GV->getType(); - const Type *ElemType = PT->getElementType(); - return GetElfSizeForType(GV, ElemType); -} - -static unsigned char GetELFType(const GlobalValue *GV) { - if (const GlobalVariable *GVar = dyn_cast<GlobalVariable>(GV)) { - return GVar->isThreadLocal() ? ELF::STT_TLS : ELF::STT_OBJECT; - } else if (isa<Function>(GV)) { - // TODO(pdox): Handle STT_GNU_IFUNC - return ELF::STT_FUNC; - } - // TODO(pdox): Do we need to resolve GlobalAliases? - llvm_unreachable("Unknown GlobalValue type in GetELFType!"); -} - -static unsigned char GetELFBinding(const GlobalValue *GV) { - // TODO(pdox): - // This information would ideally be made to match the symbol binding - // as declared in the original shared object. However, GV is only the - // declaration for this symbol, so we cannot derive the definition's - // binding here. But it seems like it should be fine to always set it to - // STB_GLOBAL, since we already know this symbol is the prevailing - // definition. - return ELF::STB_GLOBAL; -} - -static void MakeOneStub(const Module &M, - const Module::NeededRecord &NR, - ELFStub *Stub) { - Stub->SOName = NR.DynFile; - Stub->NextIndex = 2; // 0,1 are reserved - for (unsigned j = 0; j < NR.Symbols.size(); ++j) { - StringRef FullName = NR.Symbols[j]; - GlobalValue *GV = M.getNamedValue(FullName); - if (!GV) { - // The symbol may have been removed by optimization or dead code - // elimination, so this is not an error. - continue; - } - StringRef Name; - StringRef Version; - bool IsDefault; - ExtractVersion(FullName, Name, Version, IsDefault); - - SymbolStub SS; - SS.Name = Name; - SS.Type = GetELFType(GV); - SS.Binding = GetELFBinding(GV); - SS.Visibility = GetELFVisibility(GV); - SS.Size = GetELFSize(GV); - SS.VersionIndex = GetVersionIndex(Version, Stub); - SS.IsDefault = IsDefault; - Stub->Symbols.push_back(SS); - } -} - -namespace llvm { - -// For module M, make all the stubs neededs and insert them into StubList. -void MakeAllStubs(const Module &M, const Triple &T, - SmallVectorImpl<ELFStub*> *StubList) { - std::vector<Module::NeededRecord> NRList; - M.getNeededRecords(&NRList); - Elf32_Half Machine = GetELFMachine(T); - for (unsigned i = 0; i < NRList.size(); ++i) { - const Module::NeededRecord &NR = NRList[i]; - ELFStub *Stub = new ELFStub(); - Stub->Machine = Machine; - MakeOneStub(M, NR, Stub); - StubList->push_back(Stub); - } -} - -void FreeStubList(llvm::SmallVectorImpl<ELFStub*> *StubList) { - for (unsigned i = 0; i < StubList->size(); ++i) { - delete (*StubList)[i]; - } - StubList->clear(); -} - -} // namespace diff --git a/tools/llc/StubMaker.h b/tools/llc/StubMaker.h deleted file mode 100644 index 27e1e55d7f..0000000000 --- a/tools/llc/StubMaker.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef __STUB_MAKER_H -#define __STUB_MAKER_H - -#include "llvm/ADT/SmallVector.h" - -namespace llvm { - -class Module; -class Triple; -class ELFStub; - -// For module M, make all required ELF stubs and insert them into StubList. -void MakeAllStubs(const Module &M, - const Triple &T, - SmallVectorImpl<ELFStub*> *StubList); -void FreeStubList(SmallVectorImpl<ELFStub*> *StubList); - -} - -#endif diff --git a/tools/llc/TextStubWriter.cpp b/tools/llc/TextStubWriter.cpp deleted file mode 100644 index ae6e2f77d3..0000000000 --- a/tools/llc/TextStubWriter.cpp +++ /dev/null @@ -1,84 +0,0 @@ -// Using the high-level representation of an ELF stub, create a text version -// of the ELF stub object. - -#include "TextStubWriter.h" - -#include <sstream> - -#include "ELFStub.h" -#include "llvm/Support/ELF.h" - -using namespace llvm; - -namespace { - -std::string LibShortname(const std::string &fullname) { - std::string result = fullname; - if (result.find("lib") != std::string::npos) { - result = result.substr(3); - } - size_t so_pos = result.find(".so"); - if (so_pos != std::string::npos) { - result = result.substr(0, so_pos); - } - return result; -} - -const ELF::Elf32_Half kDummyCodeShndx = 5; -const ELF::Elf32_Half kDummyDataShndx = 6; - -} // namespace - -namespace llvm { - -// Write out the dynamic symbol table information. The format must be kept -// in sync with the changes in NaCl's version of gold (see gold/metadata.cc). -void WriteTextELFStub(const ELFStub *Stub, std::string *output) { - std::stringstream ss; - - ss << "#### Symtab for " << Stub->SOName << "\n"; - ss << "@obj " << LibShortname(Stub->SOName) << " " << Stub->SOName << "\n"; - - // st_value is usually a relative address for .so, and .exe files. - // So, make some up. - ELF::Elf32_Addr fake_relative_addr = 0; - for (size_t i = 0; i < Stub->Symbols.size(); ++i) { - const SymbolStub &sym = Stub->Symbols[i]; - - ELF::Elf32_Addr st_value = fake_relative_addr; - ELF::Elf32_Word st_size = sym.Size; - unsigned int st_info = sym.Type | (sym.Binding << 4); - unsigned int st_other = sym.Visibility; - ELF::Elf32_Half st_shndx = sym.Type == ELF::STT_FUNC ? - kDummyCodeShndx : kDummyDataShndx; - ELF::Elf32_Half vd_ndx = sym.VersionIndex; - // Mark non-default versions hidden. - if (!sym.IsDefault) { - vd_ndx |= ELF::VERSYM_HIDDEN; - } - - ss << "@sym " - << sym.Name << " " // Representative for st_name. - << (st_value) << " " - << (st_size) << " " - << (st_info) << " " - << (st_other) << " " - << (st_shndx) << " " - << (vd_ndx) << " " - << "\n"; - fake_relative_addr += (sym.Size == 0 ? 4 : sym.Size); - } - - // Now dump the version map. - ss << "#### VerDefs for " << Stub->SOName << "\n"; - for (size_t i = 0; i < Stub->VerDefs.size(); ++i) { - const VersionDefinition &verdef = Stub->VerDefs[i]; - ss << "@ver " << (Elf32_Half)(verdef.Index) << " " << verdef.Name << "\n"; - } - - ss << "\n"; - - output->append(ss.str()); -} - -} // namespace llvm diff --git a/tools/llc/TextStubWriter.h b/tools/llc/TextStubWriter.h deleted file mode 100644 index 4dbc5978b2..0000000000 --- a/tools/llc/TextStubWriter.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef __TEXT_STUB_WRITER_H -#define __TEXT_STUB_WRITER_H - -#include "ELFStub.h" - -namespace llvm { - -void WriteTextELFStub(const ELFStub *Stub, std::string *output); - -} - -#endif diff --git a/tools/llc/llc.cpp b/tools/llc/llc.cpp index 6d3d40cda2..aa65223473 100644 --- a/tools/llc/llc.cpp +++ b/tools/llc/llc.cpp @@ -15,17 +15,12 @@ #include "llvm/IR/LLVMContext.h" #include "llvm/ADT/Triple.h" -#include "llvm/Analysis/NaCl.h" // @LOCALMOD #include "llvm/Assembly/PrintModulePass.h" -#include "llvm/Support/DataStream.h" // @LOCALMOD -#include "llvm/Bitcode/NaCl/NaClReaderWriter.h" // @LOCALMOD #include "llvm/CodeGen/CommandFlags.h" -#include "llvm/CodeGen/IntrinsicLowering.h" // @LOCALMOD #include "llvm/CodeGen/LinkAllAsmWriterComponents.h" #include "llvm/CodeGen/LinkAllCodegenComponents.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Module.h" -#include "llvm/IRReader/IRReader.h" // @LOCALMOD #include "llvm/MC/SubtargetFeature.h" #include "llvm/Pass.h" #include "llvm/PassManager.h" @@ -35,10 +30,7 @@ #include "llvm/Support/Host.h" #include "llvm/Support/IRReader.h" #include "llvm/Support/ManagedStatic.h" -#include "llvm/Transforms/NaCl.h" // @LOCALMOD -#if !defined(__native_client__) #include "llvm/Support/PluginLoader.h" -#endif #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" #include "llvm/Support/TargetRegistry.h" @@ -47,54 +39,8 @@ #include "llvm/Target/TargetLibraryInfo.h" #include "llvm/Target/TargetMachine.h" #include <memory> - -// @LOCALMOD-BEGIN -#include "llvm/Support/Timer.h" -#include "StubMaker.h" -#include "TextStubWriter.h" -// @LOCALMOD-END - using namespace llvm; -// @LOCALMOD-BEGIN -// NOTE: this tool can be build as a "sandboxed" translator. -// There are two ways to build the translator -// SRPC-style: no file operations are allowed -// see nacl_file.cc for support code -// non-SRPC-style: some basic file operations are allowed -// This can be useful for debugging but will -// not be deployed. -#if defined(__native_client__) && defined(NACL_SRPC) -int GetObjectFileFD(); -// The following two functions communicate metadata to the SRPC wrapper for LLC. -void NaClRecordObjectInformation(bool is_shared, const std::string& soname); -void NaClRecordSharedLibraryDependency(const std::string& library_name); -DataStreamer* NaClBitcodeStreamer; -#endif -// @LOCALMOD-END - -// @LOCALMOD-BEGIN -const char *TimeIRParsingGroupName = "LLVM IR Parsing"; -const char *TimeIRParsingName = "Parse IR"; - -bool TimeIRParsingIsEnabled = false; -static cl::opt<bool,true> -EnableTimeIRParsing("time-ir-parsing", cl::location(TimeIRParsingIsEnabled), - cl::desc("Measure the time IR parsing takes")); -// @LOCALMOD-END - -// @LOCALMOD-BEGIN -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)); -// @LOCALMOD-END - // General options for llc. Other pass-specific options are specified // within the corresponding llc passes, and target-specific options // and back-end code generation options are specified with the target machine. @@ -109,39 +55,6 @@ static cl::opt<unsigned> TimeCompilations("time-compilations", cl::Hidden, cl::init(1u), cl::value_desc("N"), cl::desc("Repeat compilation N times for timing")); -// @LOCALMOD-BEGIN -static cl::opt<std::string> -MetadataTextFilename("metadata-text", cl::desc("Metadata as text, out filename"), - cl::value_desc("filename")); - -// 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)); -// @LOCALMOD-END // Determine optimization level. static cl::opt<char> @@ -243,60 +156,9 @@ static tool_output_file *GetOutputStream(const char *TargetName, return FDOut; } -// @LOCALMOD-BEGIN -#if defined(__native_client__) && defined(NACL_SRPC) -void RecordMetadataForSrpc(const Module &mod) { - bool is_shared = (mod.getOutputFormat() == Module::SharedOutputFormat); - std::string soname = mod.getSOName(); - NaClRecordObjectInformation(is_shared, soname); - for (Module::lib_iterator L = mod.lib_begin(), - E = mod.lib_end(); - L != E; ++L) { - NaClRecordSharedLibraryDependency(*L); - } -} -#endif // defined(__native_client__) && defined(NACL_SRPC) -// @LOCALMOD-END - - -// @LOCALMOD-BEGIN - -// Write the ELF Stubs to the metadata file, in text format -// Returns 0 on success, non-zero on error. -int WriteTextMetadataFile(const Module &M, const Triple &TheTriple) { - // Build the ELF stubs (in high level format) - SmallVector<ELFStub*, 8> StubList; - // NOTE: The triple is unnecessary for the text version. - MakeAllStubs(M, TheTriple, &StubList); - // For each stub, write the ELF object to the metadata file. - std::string s; - for (unsigned i = 0; i < StubList.size(); i++) { - WriteTextELFStub(StubList[i], &s); - } - FreeStubList(&StubList); - -#if defined(__native_client__) && defined(NACL_SRPC) - llvm_unreachable("Not yet implemented. Need a file handle to write to."); -#else - std::string error; - OwningPtr<tool_output_file> MOut( - new tool_output_file(MetadataTextFilename.c_str(), error, - raw_fd_ostream::F_Binary)); - if (!error.empty()) { - errs() << error << '\n'; - return 1; - } - MOut->os().write(s.data(), s.size()); - MOut->keep(); -#endif - return 0; -} - -// @LOCALMOD-END - // main - Entry point for the llc compiler. // -int llc_main(int argc, char **argv) { +int main(int argc, char **argv) { sys::PrintStackTraceOnErrorSignal(); PrettyStackTraceProgram X(argc, argv); @@ -310,14 +172,7 @@ int llc_main(int argc, char **argv) { InitializeAllTargets(); InitializeAllTargetMCs(); InitializeAllAsmPrinters(); -// @LOCALMOD-BEGIN -// Prune asm parsing from sandboxed translator. -// Do not prune "AsmPrinters" because that includes -// the direct object emission. - #if !defined(__native_client__) - InitializeAllAsmParsers(); -#endif -// @LOCALMOD-END + InitializeAllAsmParsers(); // Initialize codegen and IR passes used by llc so that the -print-after, // -print-before, and -stop-after options work. @@ -341,20 +196,6 @@ int llc_main(int argc, char **argv) { return 0; } -// @LOCALMOD-BEGIN -static void CheckABIVerifyErrors(PNaClABIErrorReporter &Reporter, - const Twine &Name) { - if (PNaClABIVerify && Reporter.getErrorCount() > 0) { - errs() << (PNaClABIVerifyFatalErrors ? "ERROR: " : "WARNING: "); - errs() << Name << " is not valid PNaCl bitcode:\n"; - Reporter.printErrors(errs()); - if (PNaClABIVerifyFatalErrors) - exit(1); - } - Reporter.reset(); -} -// @LOCALMOD-END - static int compileModule(char **argv, LLVMContext &Context) { // Load the module to be compiled... SMDiagnostic Err; @@ -365,98 +206,19 @@ static int compileModule(char **argv, LLVMContext &Context) { bool SkipModule = MCPU == "help" || (!MAttrs.empty() && MAttrs.front() == "help"); - PNaClABIErrorReporter ABIErrorReporter; // @LOCALMOD - // If user just wants to list available options, skip module loading if (!SkipModule) { - // @LOCALMOD-BEGIN -#if defined(__native_client__) && defined(NACL_SRPC) - if (LazyBitcode) { - std::string StrError; - switch (InputFileFormat) { - case LLVMFormat: - // TODO(kschimpf) Remove this case once we have fixed - // pnacl-finalize and the NaCl build system to only allow PNaCl - // bitcode files. - M.reset(getStreamedBitcodeModule( - std::string("<SRPC stream>"), - NaClBitcodeStreamer, Context, &StrError)); - break; - case PNaClFormat: - M.reset(getNaClStreamedBitcodeModule( - std::string("<SRPC stream>"), - NaClBitcodeStreamer, Context, &StrError)); - break; - default: - StrError = "Don't understand specified bitcode format"; - break; - } - if (!StrError.empty()) { - Err = SMDiagnostic(InputFilename, SourceMgr::DK_Error, StrError); - } - } else { - // Avoid using ParseIRFile to avoid pulling in the LLParser. - // Only handle binary bitcode. - llvm_unreachable("native client SRPC only supports streaming"); - } -#else - { - // @LOCALMOD: timing is temporary, until it gets properly added upstream - NamedRegionTimer T(TimeIRParsingName, TimeIRParsingGroupName, - TimeIRParsingIsEnabled); - M.reset(NaClParseIRFile(InputFilename, InputFileFormat, Err, Context)); - } -#endif - // @LOCALMOD-END - + M.reset(ParseIRFile(InputFilename, Err, Context)); mod = M.get(); if (mod == 0) { Err.print(argv[0], errs()); return 1; } - // @LOCALMOD-BEGIN - if (PNaClABIVerify) { - // Verify the module (but not the functions yet) - ModulePass *VerifyPass = createPNaClABIVerifyModulePass(&ABIErrorReporter); - VerifyPass->runOnModule(*mod); - CheckABIVerifyErrors(ABIErrorReporter, "Module"); - } - -#if defined(__native_client__) && defined(NACL_SRPC) - RecordMetadataForSrpc(*mod); - - // To determine if we should compile PIC or not, we needed to load at - // least the metadata. Since we've already constructed the commandline, - // we have to hack this in after commandline processing. - if (mod->getOutputFormat() == Module::SharedOutputFormat) { - RelocModel = Reloc::PIC_; - } - // Also set PIC_ for dynamic executables: - // BUG= http://code.google.com/p/nativeclient/issues/detail?id=2351 - if (mod->lib_size() > 0) { - RelocModel = Reloc::PIC_; - } -#endif // defined(__native_client__) && defined(NACL_SRPC) - // @LOCALMOD-END - // If we are supposed to override the target triple, do so now. if (!TargetTriple.empty()) mod->setTargetTriple(Triple::normalize(TargetTriple)); TheTriple = Triple(mod->getTargetTriple()); - - // @LOCALMOD-BEGIN - // Add declarations for external functions required by PNaCl. The - // ResolvePNaClIntrinsics function pass running during streaming - // depends on these declarations being in the module. - if (TheTriple.isOSNaCl()) { - // TODO(eliben): pnacl-llc presumably won't need the isOSNaCl - // test. - OwningPtr<ModulePass> AddPNaClExternalDeclsPass( - createAddPNaClExternalDeclsPass()); - AddPNaClExternalDeclsPass->runOnModule(*mod); - } - // @LOCALMOD-END } else { TheTriple = Triple(Triple::normalize(TargetTriple)); } @@ -477,11 +239,6 @@ static int compileModule(char **argv, LLVMContext &Context) { std::string FeaturesStr; if (MAttrs.size()) { SubtargetFeatures Features; - // @LOCALMOD-BEGIN - // Use the same default attribute settings as libLTO. - // TODO(pdox): Figure out why this isn't done for upstream llc. - Features.getDefaultSubtargetFeatures(TheTriple); - // @LOCALMOD-END for (unsigned i = 0; i != MAttrs.size(); ++i) Features.AddFeature(MAttrs[i]); FeaturesStr = Features.getString(); @@ -548,49 +305,28 @@ static int compileModule(char **argv, LLVMContext &Context) { TheTriple.isMacOSXVersionLT(10, 6)) Target.setMCUseLoc(false); -#if !defined(NACL_SRPC) // Figure out where we are going to send the output. OwningPtr<tool_output_file> Out (GetOutputStream(TheTarget->getName(), TheTriple.getOS(), argv[0])); if (!Out) return 1; -#endif // Build up all of the passes that we want to do to the module. - // @LOCALMOD-BEGIN - OwningPtr<PassManagerBase> PM; - if (LazyBitcode || ReduceMemoryFootprint) - PM.reset(new FunctionPassManager(mod)); - else - PM.reset(new PassManager()); - - // Add the ABI verifier pass before the analysis and code emission passes. - FunctionPass *FunctionVerifyPass = NULL; - if (PNaClABIVerify) { - FunctionVerifyPass = createPNaClABIVerifyFunctionsPass(&ABIErrorReporter); - PM->add(FunctionVerifyPass); - } - - if (TheTriple.isOSNaCl()) { - // Add the intrinsic resolution pass. It assumes ABI-conformant code. - PM->add(createResolvePNaClIntrinsicsPass()); - } - - // @LOCALMOD-END + PassManager PM; // Add an appropriate TargetLibraryInfo pass for the module's triple. TargetLibraryInfo *TLI = new TargetLibraryInfo(TheTriple); if (DisableSimplifyLibCalls) TLI->disableAllFunctions(); - PM->add(TLI); + PM.add(TLI); // Add intenal analysis passes from the target machine. - Target.addAnalysisPasses(*PM.get()); + Target.addAnalysisPasses(PM); // 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)); + PM.add(new DataLayout(*TD)); else - PM->add(new DataLayout(mod)); + PM.add(new DataLayout(mod)); // Override default to generate verbose assembly. Target.setAsmVerbosityDefault(true); @@ -603,39 +339,6 @@ static int compileModule(char **argv, LLVMContext &Context) { Target.setMCRelaxAll(true); } - -#if defined __native_client__ && defined(NACL_SRPC) - { - raw_fd_ostream ROS(GetObjectFileFD(), true); - ROS.SetBufferSize(1 << 20); - formatted_raw_ostream FOS(ROS); - - // Ask the target to add backend passes as necessary. - if (Target.addPassesToEmitFile(*PM, FOS, FileType, NoVerify)) { - errs() << argv[0] << ": target does not support generation of this" - << " file type!\n"; - return 1; - } - - if (LazyBitcode || ReduceMemoryFootprint) { - FunctionPassManager* P = static_cast<FunctionPassManager*>(PM.get()); - P->doInitialization(); - for (Module::iterator I = mod->begin(), E = mod->end(); I != E; ++I) { - P->run(*I); - CheckABIVerifyErrors(ABIErrorReporter, "Function " + I->getName()); - if (ReduceMemoryFootprint) { - I->Dematerialize(); - } - } - P->doFinalization(); - } else { - static_cast<PassManager*>(PM.get())->run(*mod); - } - FOS.flush(); - ROS.flush(); - } -#else - { formatted_raw_ostream FOS(Out->os()); @@ -660,7 +363,7 @@ static int compileModule(char **argv, LLVMContext &Context) { } // Ask the target to add backend passes as necessary. - if (Target.addPassesToEmitFile(*PM, FOS, FileType, NoVerify, + if (Target.addPassesToEmitFile(PM, FOS, FileType, NoVerify, StartAfterID, StopAfterID)) { errs() << argv[0] << ": target does not support generation of this" << " file type!\n"; @@ -670,51 +373,11 @@ static int compileModule(char **argv, LLVMContext &Context) { // 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); - } + PM.run(*mod); } // Declare success. Out->keep(); -#endif - - // @LOCALMOD-BEGIN - // Write out the metadata. - // - // We need to ensure that intrinsic prototypes are available, in case - // we have a NeededRecord for one of them. - // They may have been eliminated by the StripDeadPrototypes pass, - // or some other pass that is unaware of NeededRecords / IntrinsicLowering. - if (!MetadataTextFilename.empty()) { - IntrinsicLowering IL(*target->getDataLayout()); - IL.AddPrototypes(*M); - - int err = WriteTextMetadataFile(*M.get(), TheTriple); - if (err != 0) - return err; - } - // @LOCALMOD-END return 0; } - -#if !defined(NACL_SRPC) -int -main (int argc, char **argv) { - return llc_main(argc, argv); -} -#else -// main() is in nacl_file.cpp. -#endif diff --git a/tools/llc/nacl_file.cpp b/tools/llc/nacl_file.cpp deleted file mode 100644 index b7ecb407cd..0000000000 --- a/tools/llc/nacl_file.cpp +++ /dev/null @@ -1,422 +0,0 @@ -/* Copyright 2012 The Native Client Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can - * be found in the LICENSE file. - * - * This file provides wrappers to open() to use pre-opened file descriptors - * for the input bitcode and the output file. - * - * It also has the SRPC interfaces, but that should probably be refactored - * into a separate file. - */ - -#if defined(__native_client__) && defined(NACL_SRPC) - -#include <argz.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -// Headers which are not properly part of the SDK are included by their -// path in the nacl tree -#include "native_client/src/shared/srpc/nacl_srpc.h" -#ifdef __pnacl__ -#include <nacl/pnacl.h> -#endif -#include "SRPCStreamer.h" - -#include <string> -#include <map> -#include <vector> - -#include "llvm/ADT/OwningPtr.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/system_error.h" - - -using llvm::MemoryBuffer; -using llvm::StringRef; -using std::string; -using std::map; - -#define printerr(...) fprintf(stderr, __VA_ARGS__) -// printdbg is currently disabled to reduce spew. -#define printdbg(...) - -#define ARRAY_SIZE(array) (sizeof array / sizeof array[0]) - -namespace { - -typedef std::vector<std::string> string_vector; - -// True if the bitcode to be compiled is for a shared library. -// Used to return to the coordinator. -bool g_bitcode_is_shared_library; -// The soname of the current compilation unit, if it is a shared library. -// Empty string otherwise. -std::string* g_bitcode_soname = NULL; -// The newline separated list of libraries that the current bitcode compilation -// unit depends on. -std::string* g_bitcode_lib_dependencies = NULL; -// The filename used internally for looking up the bitcode file. -char kBitcodeFilename[] = "pnacl.pexe"; -// The filename used internally for looking up the object code file. -char kObjectFilename[] = "pnacl.o"; -// Object which manages streaming bitcode over SRPC and threading. -SRPCStreamer *srpc_streamer; -// FD of the object file. -int object_file_fd; - -} // namespace - -//TODO(dschuff): a little more elegant interface into llc than this? -extern llvm::DataStreamer* NaClBitcodeStreamer; - -extern int llc_main(int argc, char **argv); - -int GetObjectFileFD() { - return object_file_fd; -} - -void NaClRecordObjectInformation(bool is_shared, const std::string& soname) { - // This function is invoked to begin recording library information. - // To make it reentrant, we clean up what might be left over from last time. - delete g_bitcode_soname; - delete g_bitcode_lib_dependencies; - // Then remember the module global information. - g_bitcode_is_shared_library = is_shared; - g_bitcode_soname = new std::string(soname); - g_bitcode_lib_dependencies = new std::string(); -} - -void NaClRecordSharedLibraryDependency(const std::string& library_name) { - const std::string& kDelimiterString("\n"); - *g_bitcode_lib_dependencies += (library_name + kDelimiterString); -} - -namespace { - -int DoTranslate(string_vector* cmd_line_vec, int object_fd) { - if (cmd_line_vec == NULL) { - return 1; - } - object_file_fd = object_fd; - // Make an argv array from the input vector. - size_t argc = cmd_line_vec->size(); - char** argv = new char*[argc]; - for (size_t i = 0; i < argc; ++i) { - // llc_main will not mutate the command line, so this is safe. - argv[i] = const_cast<char*>((*cmd_line_vec)[i].c_str()); - } - argv[argc] = NULL; - // Call main. - return llc_main(static_cast<int>(argc), argv); -} - -string_vector* CommandLineFromArgz(char* str, size_t str_len) { - char* entry = str; - string_vector* vec = new string_vector; - while (entry != NULL) { - vec->push_back(entry); - entry = argz_next(str, str_len, entry); - } - return vec; -} - -void AddFixedArguments(string_vector* vec) { - // Add fixed arguments to the command line. These specify the bitcode - // and object code filenames, removing them from the contract with the - // coordinator. - vec->push_back(kBitcodeFilename); - vec->push_back("-o"); - vec->push_back(kObjectFilename); -} - -bool AddDefaultCPU(string_vector* vec) { -#if defined (__pnacl__) - switch (__builtin_nacl_target_arch()) { - case PnaclTargetArchitectureX86_32: { - vec->push_back("-mcpu=pentium4"); - break; - } - case PnaclTargetArchitectureX86_64: { - vec->push_back("-mcpu=core2"); - break; - } - case PnaclTargetArchitectureARM_32: { - vec->push_back("-mcpu=cortex-a9"); - break; - } - default: - printerr("no target architecture match.\n"); - return false; - } -// Some cases for building this with nacl-gcc. -#elif defined (__i386__) - vec->push_back("-mcpu=pentium4"); -#elif defined (__x86_64__) - vec->push_back("-mcpu=core2"); -#elif defined (__arm__) - vec->push_back("-mcpu=cortex-a9"); -#error "Unknown architecture" -#endif - return true; -} - -bool HasCPUOverride(string_vector* vec) { - std::string mcpu = std::string("-mcpu="); - size_t len = mcpu.length(); - for (size_t i = 0; i < vec->size(); ++i) { - std::string prefix = (*vec)[i].substr(0, len); - if (prefix.compare(mcpu) == 0) - return true; - } - return false; -} - -string_vector* GetDefaultCommandLine() { - string_vector* command_line = new string_vector; - size_t i; - // First, those common to all architectures. - static const char* common_args[] = { "pnacl_translator", - "-filetype=obj" }; - for (i = 0; i < ARRAY_SIZE(common_args); ++i) { - command_line->push_back(common_args[i]); - } - // Then those particular to a platform. - static const char* llc_args_x8632[] = { "-mtriple=i686-none-nacl-gnu", - NULL }; - static const char* llc_args_x8664[] = { "-mtriple=x86_64-none-nacl-gnu", - NULL }; - static const char* llc_args_arm[] = { "-mtriple=armv7a-none-nacl-gnueabi", - "-arm-reserve-r9", - "-sfi-disable-cp", - "-sfi-store", - "-sfi-load", - "-sfi-stack", - "-sfi-branch", - "-sfi-data", - "-mattr=+neon", - "-no-inline-jumptables", - "-float-abi=hard", - NULL }; - - const char **llc_args = NULL; -#if defined (__pnacl__) - switch (__builtin_nacl_target_arch()) { - case PnaclTargetArchitectureX86_32: { - llc_args = llc_args_x8632; - break; - } - case PnaclTargetArchitectureX86_64: { - llc_args = llc_args_x8664; - break; - } - case PnaclTargetArchitectureARM_32: { - llc_args = llc_args_arm; - break; - } - default: - printerr("no target architecture match.\n"); - delete command_line; - return NULL; - } -// Some cases for building this with nacl-gcc. -#elif defined (__i386__) - llc_args = llc_args_x8632; -#elif defined (__x86_64__) - llc_args = llc_args_x8664; -#elif defined (__arm__) - llc_args = llc_args_arm; -#else -#error "Unknown architecture" -#endif - for (i = 0; llc_args[i] != NULL; i++) command_line->push_back(llc_args[i]); - return command_line; -} - -// Data passed from main thread to compile thread. -// Takes ownership of the commandline vector. -class StreamingThreadData { - public: - StreamingThreadData(int object_fd, string_vector* cmd_line_vec) : - object_fd_(object_fd), cmd_line_vec_(cmd_line_vec) {} - int ObjectFD() const { return object_fd_; } - string_vector* CmdLineVec() const { return cmd_line_vec_.get(); } - const int object_fd_; - const llvm::OwningPtr<string_vector> cmd_line_vec_; -}; - -void *run_streamed(void *arg) { - StreamingThreadData* data = reinterpret_cast<StreamingThreadData*>(arg); - data->CmdLineVec()->push_back("-streaming-bitcode"); - if (DoTranslate(data->CmdLineVec(), data->ObjectFD()) != 0) { - printerr("DoTranslate failed.\n"); - srpc_streamer->setError(); - return NULL; - } - delete data; - return NULL; -} - -// Actually do the work for stream initialization. -void do_stream_init(NaClSrpcRpc *rpc, - NaClSrpcArg **in_args, - NaClSrpcArg **out_args, - NaClSrpcClosure *done, - string_vector* command_line_vec) { - NaClSrpcClosureRunner runner(done); - rpc->result = NACL_SRPC_RESULT_APP_ERROR; - srpc_streamer = new SRPCStreamer(); - std::string StrError; - StreamingThreadData* thread_data = new StreamingThreadData( - in_args[0]->u.hval, command_line_vec); - NaClBitcodeStreamer = srpc_streamer->init(run_streamed, - reinterpret_cast<void *>(thread_data), - &StrError); - if (NaClBitcodeStreamer) { - rpc->result = NACL_SRPC_RESULT_OK; - out_args[0]->arrays.str = strdup("no error"); - } else { - out_args[0]->arrays.str = strdup(StrError.c_str()); - } -} - -// Invoked by the StreamInit RPC to initialize bitcode streaming over SRPC. -// Under the hood it forks a new thread at starts the llc_main, which sets -// up the compilation and blocks when it tries to start reading the bitcode. -// Input arg is a file descriptor to write the output object file to. -// Returns a string, containing an error message if the call fails. -void stream_init(NaClSrpcRpc *rpc, - NaClSrpcArg **in_args, - NaClSrpcArg **out_args, - NaClSrpcClosure *done) { - // cmd_line_vec allocated by GetDefaultCommandLine() is freed by the - // translation thread in run_streamed() - string_vector* cmd_line_vec = GetDefaultCommandLine(); - if (!cmd_line_vec || !AddDefaultCPU(cmd_line_vec)) { - NaClSrpcClosureRunner runner(done); - rpc->result = NACL_SRPC_RESULT_APP_ERROR; - out_args[0]->arrays.str = strdup("Failed to get default commandline."); - return; - } - AddFixedArguments(cmd_line_vec); - do_stream_init(rpc, in_args, out_args, done, cmd_line_vec); -} - -// Invoked by StreamInitWithCommandLine RPC. Same as stream_init, but -// provides a command line to use instead of the default. -void stream_init_with_command_line(NaClSrpcRpc *rpc, - NaClSrpcArg **in_args, - NaClSrpcArg **out_args, - NaClSrpcClosure *done) { - char* command_line = in_args[1]->arrays.carr; - size_t command_line_len = in_args[1]->u.count; - string_vector* cmd_line_vec = - CommandLineFromArgz(command_line, command_line_len); - AddFixedArguments(cmd_line_vec); - // cmd_line_vec is freed by the translation thread in run_streamed - do_stream_init(rpc, in_args, out_args, done, cmd_line_vec); -} - -// Invoked by StreamInitWithOverrides RPC. Same as stream_init, but -// provides commandline flag overrides (appended to the default). -void stream_init_with_overrides(NaClSrpcRpc *rpc, - NaClSrpcArg **in_args, - NaClSrpcArg **out_args, - NaClSrpcClosure *done) { - string_vector* cmd_line_vec = GetDefaultCommandLine(); - if (!cmd_line_vec) { - NaClSrpcClosureRunner runner(done); - rpc->result = NACL_SRPC_RESULT_APP_ERROR; - out_args[0]->arrays.str = strdup("Failed to get default commandline."); - return; - } - AddFixedArguments(cmd_line_vec); - - char* command_line = in_args[1]->arrays.carr; - size_t command_line_len = in_args[1]->u.count; - llvm::OwningPtr<string_vector> extra_vec( - CommandLineFromArgz(command_line, command_line_len)); - cmd_line_vec->insert(cmd_line_vec->end(), - extra_vec->begin(), extra_vec->end()); - // Make sure some -mcpu override exists for now to prevent - // auto-cpu feature detection from triggering instructions that - // we do not validate yet. - if (!HasCPUOverride(extra_vec.get())) { - AddDefaultCPU(cmd_line_vec); - } - extra_vec.reset(NULL); - // cmd_line_vec is freed by the translation thread in run_streamed. - do_stream_init(rpc, in_args, out_args, done, cmd_line_vec); -} - -// Invoked by the StreamChunk RPC. Receives a chunk of the bitcode and -// buffers it for later retrieval by the compilation thread. -void stream_chunk(NaClSrpcRpc *rpc, - NaClSrpcArg **in_args, - NaClSrpcArg **out_args, - NaClSrpcClosure *done) { - NaClSrpcClosureRunner runner(done); - rpc->result = NACL_SRPC_RESULT_APP_ERROR; - size_t len = in_args[0]->u.count; - unsigned char *bytes = reinterpret_cast<unsigned char*>( - in_args[0]->arrays.carr); - if (srpc_streamer->gotChunk(bytes, len) != len) { - return; - } - rpc->result = NACL_SRPC_RESULT_OK; -} - -// Invoked by the StreamEnd RPC. Waits until the compilation finishes, -// then returns. Returns an int indicating whether the bitcode is a -// shared library, a string with the soname, a string with dependencies, -// and a string which contains an error message if applicable. -void stream_end(NaClSrpcRpc *rpc, - NaClSrpcArg **in_args, - NaClSrpcArg **out_args, - NaClSrpcClosure *done) { - NaClSrpcClosureRunner runner(done); - rpc->result = NACL_SRPC_RESULT_APP_ERROR; - std::string StrError; - if (srpc_streamer->streamEnd(&StrError)) { - out_args[3]->arrays.str = strdup(StrError.c_str()); - return; - } - out_args[0]->u.ival = g_bitcode_is_shared_library; - // SRPC deletes the strings returned when the closure is invoked. - // Therefore we need to use strdup. - out_args[1]->arrays.str = strdup(g_bitcode_soname->c_str()); - out_args[2]->arrays.str = strdup(g_bitcode_lib_dependencies->c_str()); - rpc->result = NACL_SRPC_RESULT_OK; -} - -const struct NaClSrpcHandlerDesc srpc_methods[] = { - // Protocol for streaming: - // (StreamInit(obj_fd) -> error_str | - // StreamInitWIthCommandLine(obj_fd, escaped_cmdline) -> error_str) - // StreamChunk(data) + - // StreamEnd() -> (is_shared_lib,soname,dependencies,error_str) - { "StreamInit:h:s", stream_init }, - { "StreamInitWithCommandLine:hC:s:", stream_init_with_command_line }, - { "StreamInitWithOverrides:hC:s:", stream_init_with_overrides }, - { "StreamChunk:C:", stream_chunk }, - { "StreamEnd::isss", stream_end }, - { NULL, NULL }, -}; - -} // namespace - -int -main() { - if (!NaClSrpcModuleInit()) { - return 1; - } - - if (!NaClSrpcAcceptClientConnection(srpc_methods)) { - return 1; - } - NaClSrpcModuleFini(); - return 0; -} - -#endif |