Subzero: Add necessary PNaCl files for standalone build.
The README.txt file is new; all other files under pnacl-llvm/ are copied verbatim from the pnacl-llvm repo.
BUG= none
R=kschimpf@google.com
Review URL: https://codereview.chromium.org/1960393002 .
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b786204..bc0175c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,14 +1,29 @@
+unset(PNACL_LLVM)
+# Define PNACL_LLVM for LLVM_VERSION <= 3.7
+if((NOT LLVM_VERSION_MAJOR GREATER 3) AND (NOT LLVM_VERSION_MINOR GREATER 7))
+ set(PNACL_LLVM 1)
+endif()
+
+if(PNACL_LLVM)
+ add_definitions(
+ -DPNACL_LLVM
+ )
+ set(PNACL_EXTRA_COMPONENTS NaClBitReader NaClBitTestUtils)
+else()
+ include_directories(pnacl-llvm/include)
+ file(GLOB pnacl_llvm_SRCS "pnacl-llvm/*.cpp")
+endif()
+
set(LLVM_LINK_COMPONENTS
${LLVM_TARGETS_TO_BUILD}
Core
IRReader
- NaClBitReader
- NaClBitTestUtils
Support
+ ${PNACL_EXTRA_COMPONENTS}
)
file(GLOB pnacl_sz_SRCS "src/*.cpp")
-add_llvm_tool(pnacl-sz ${pnacl_sz_SRCS})
+add_llvm_tool(pnacl-sz ${pnacl_sz_SRCS} ${pnacl_llvm_SRCS})
if(PNACL_BROWSER_TRANSLATOR)
add_definitions(
@@ -35,11 +50,4 @@
add_compile_options(-Wno-undefined-var-template)
endif()
-# Define PNACL_LLVM for LLVM_VERSION <= 3.7
-if((NOT LLVM_VERSION_MAJOR GREATER 3) AND (NOT LLVM_VERSION_MINOR GREATER 7))
- add_definitions(
- -DPNACL_LLVM
- )
-endif()
-
target_link_libraries(pnacl-sz pthread)
diff --git a/Makefile.standalone b/Makefile.standalone
index d6bfb8e..6799452 100644
--- a/Makefile.standalone
+++ b/Makefile.standalone
@@ -743,6 +743,7 @@
FORMAT_BLACKLIST += ! -name assembler_arm.h
FORMAT_BLACKLIST += ! -name assembler_arm.cc
FORMAT_BLACKLIST += ! -path "./wasm-install/*"
+FORMAT_BLACKLIST += ! -path "./pnacl-llvm/*"
format:
$(CLANG_FORMAT_PATH)/clang-format -style=LLVM -i \
`find . -regex '.*\.\(c\|h\|cpp\)' $(FORMAT_BLACKLIST)`
diff --git a/docs/README.rst b/docs/README.rst
index 0257558..922d99d 100644
--- a/docs/README.rst
+++ b/docs/README.rst
@@ -44,6 +44,27 @@
The result of the ``make`` command is the target ``pnacl-sz`` in the current
directory.
+Building within LLVM trunk
+--------------------------
+
+Subzero can also be built from within a standard LLVM trunk checkout. Here is
+an example of how it can be checked out and built::
+
+ mkdir llvm-git
+ cd llvm-git
+ git clone http://llvm.org/git/llvm.git
+ cd llvm/projects/
+ git clone https://chromium.googlesource.com/native_client/pnacl-subzero
+ cd ../..
+ mkdir build
+ cd build
+ cmake -G Ninja ../llvm/
+ ninja
+ ./bin/pnacl-sz -version
+
+This creates a default build of ``pnacl-sz``; currently any options such as
+``DEBUG=1`` or ``MINIMAL=1`` have to be added manually.
+
``pnacl-sz``
------------
diff --git a/pnacl-llvm/NaClBitCodes.cpp b/pnacl-llvm/NaClBitCodes.cpp
new file mode 100644
index 0000000..7267411
--- /dev/null
+++ b/pnacl-llvm/NaClBitCodes.cpp
@@ -0,0 +1,131 @@
+//===- NaClBitcodeHeader.cpp ----------------------------------------------===//
+// PNaCl bitcode header reader.
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implementation of Bitcode abbrevations.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Bitcode/NaCl/NaClBitCodes.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/ErrorHandling.h"
+
+using namespace llvm;
+
+const bool NaClBitCodeAbbrevOp::HasValueArray[] = {
+ true, // Literal
+ true, // Fixed
+ true, // VBR
+ false, // Array
+ false // Char6
+};
+
+const char *NaClBitCodeAbbrevOp::EncodingNameArray[] = {
+ "Literal",
+ "Fixed",
+ "VBR",
+ "Array",
+ "Char6"
+};
+
+NaClBitCodeAbbrevOp::NaClBitCodeAbbrevOp(Encoding E, uint64_t Data)
+ : Enc(E), Val(Data) {
+ if (isValid(E, Data)) return;
+ std::string Buffer;
+ raw_string_ostream StrBuf(Buffer);
+ StrBuf << "Invalid NaClBitCodeAbbrevOp(" << E << ", " << Data << ")";
+ report_fatal_error(StrBuf.str());
+}
+
+bool NaClBitCodeAbbrevOp::isValid(Encoding E, uint64_t Val) {
+ switch (NaClBitCodeAbbrevOp::Encoding(E)) {
+ case Literal:
+ return true;
+ case Fixed:
+ case VBR:
+ return Val <= naclbitc::MaxAbbrevWidth;
+ case Char6:
+ case Array:
+ return Val == 0;
+ }
+ llvm_unreachable("unhandled abbreviation");
+}
+
+void NaClBitCodeAbbrevOp::Print(raw_ostream& Stream) const {
+ if (Enc == Literal) {
+ Stream << getValue();
+ return;
+ }
+ Stream << getEncodingName(Enc);
+ if (!hasValue())
+ return;
+ Stream << "(" << Val << ")";
+}
+
+static void PrintExpression(raw_ostream &Stream,
+ const NaClBitCodeAbbrev *Abbrev,
+ unsigned &Index) {
+ // Bail out early, in case we are incrementally building the
+ // expression and the argument is not available yet.
+ if (Index >= Abbrev->getNumOperandInfos()) return;
+
+ const NaClBitCodeAbbrevOp &Op = Abbrev->getOperandInfo(Index);
+ Op.Print(Stream);
+ if (unsigned NumArgs = Op.NumArguments()) {
+ Stream << "(";
+ for (unsigned i = 0; i < NumArgs; ++i) {
+ ++Index;
+ if (i > 0) Stream << ",";
+ PrintExpression(Stream, Abbrev, Index);
+ }
+ Stream << ")";
+ }
+}
+
+void NaClBitCodeAbbrev::Print(raw_ostream &Stream, bool AddNewLine) const {
+ Stream << "[";
+ for (unsigned i = 0; i < getNumOperandInfos(); ++i) {
+ if (i > 0) Stream << ", ";
+ PrintExpression(Stream, this, i);
+ }
+ Stream << "]";
+ if (AddNewLine) Stream << "\n";
+}
+
+NaClBitCodeAbbrev *NaClBitCodeAbbrev::Simplify() const {
+ NaClBitCodeAbbrev *Abbrev = new NaClBitCodeAbbrev();
+ for (unsigned i = 0; i < OperandList.size(); ++i) {
+ const NaClBitCodeAbbrevOp &Op = OperandList[i];
+ // Simplify if possible. Currently, the only simplification known
+ // is to remove unnecessary operands appearing immediately before an
+ // array operator. That is, apply the simplification:
+ // Op Array(Op) -> Array(Op)
+ assert(!Op.isArrayOp() || i == OperandList.size()-2);
+ while (Op.isArrayOp() && !Abbrev->OperandList.empty() &&
+ Abbrev->OperandList.back() == OperandList[i+1]) {
+ Abbrev->OperandList.pop_back();
+ }
+ Abbrev->OperandList.push_back(Op);
+ }
+ return Abbrev;
+}
+
+bool NaClBitCodeAbbrev::isValid() const {
+ // Verify that an array op appears can only appear if it is the
+ // second to last element.
+ unsigned NumOperands = getNumOperandInfos();
+ if (NumOperands == 0) return false;
+ for (unsigned i = 0; i < NumOperands; ++i) {
+ const NaClBitCodeAbbrevOp &Op = getOperandInfo(i);
+ if (Op.isArrayOp() && i + 2 != NumOperands)
+ // Note: Unlike LLVM bitcode, we allow literals in arrays!
+ return false;
+ }
+ return true;
+}
diff --git a/pnacl-llvm/NaClBitcodeDecoders.cpp b/pnacl-llvm/NaClBitcodeDecoders.cpp
new file mode 100644
index 0000000..450499a
--- /dev/null
+++ b/pnacl-llvm/NaClBitcodeDecoders.cpp
@@ -0,0 +1,228 @@
+//===- NaClBitcodeDecoders.cpp --------------------------------------------===//
+// Internal implementation of decoder functions for PNaCl Bitcode files.
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Bitcode/NaCl/NaClBitcodeDecoders.h"
+
+namespace llvm {
+namespace naclbitc {
+
+bool DecodeCastOpcode(uint64_t NaClOpcode,
+ Instruction::CastOps &LLVMOpcode) {
+ switch (NaClOpcode) {
+ default:
+ LLVMOpcode = Instruction::BitCast;
+ return false;
+ case naclbitc::CAST_TRUNC:
+ LLVMOpcode = Instruction::Trunc;
+ return true;
+ case naclbitc::CAST_ZEXT:
+ LLVMOpcode = Instruction::ZExt;
+ return true;
+ case naclbitc::CAST_SEXT:
+ LLVMOpcode = Instruction::SExt;
+ return true;
+ case naclbitc::CAST_FPTOUI:
+ LLVMOpcode = Instruction::FPToUI;
+ return true;
+ case naclbitc::CAST_FPTOSI:
+ LLVMOpcode = Instruction::FPToSI;
+ return true;
+ case naclbitc::CAST_UITOFP:
+ LLVMOpcode = Instruction::UIToFP;
+ return true;
+ case naclbitc::CAST_SITOFP:
+ LLVMOpcode = Instruction::SIToFP;
+ return true;
+ case naclbitc::CAST_FPTRUNC:
+ LLVMOpcode = Instruction::FPTrunc;
+ return true;
+ case naclbitc::CAST_FPEXT:
+ LLVMOpcode = Instruction::FPExt;
+ return true;
+ case naclbitc::CAST_BITCAST:
+ LLVMOpcode = Instruction::BitCast;
+ return true;
+ }
+}
+
+bool DecodeLinkage(uint64_t NaClLinkage,
+ GlobalValue::LinkageTypes &LLVMLinkage) {
+ switch (NaClLinkage) {
+ default:
+ LLVMLinkage = GlobalValue::InternalLinkage;
+ return false;
+ case naclbitc::LINKAGE_EXTERNAL:
+ LLVMLinkage = GlobalValue::ExternalLinkage;
+ return true;
+ case naclbitc::LINKAGE_INTERNAL:
+ LLVMLinkage = GlobalValue::InternalLinkage;
+ return true;
+ }
+}
+
+bool DecodeBinaryOpcode(uint64_t NaClOpcode, Type *Ty,
+ Instruction::BinaryOps &LLVMOpcode) {
+ switch (NaClOpcode) {
+ default:
+ LLVMOpcode = Instruction::Add;
+ return false;
+ case naclbitc::BINOP_ADD:
+ LLVMOpcode = Ty->isFPOrFPVectorTy() ? Instruction::FAdd : Instruction::Add;
+ return true;
+ case naclbitc::BINOP_SUB:
+ LLVMOpcode = Ty->isFPOrFPVectorTy() ? Instruction::FSub : Instruction::Sub;
+ return true;
+ case naclbitc::BINOP_MUL:
+ LLVMOpcode = Ty->isFPOrFPVectorTy() ? Instruction::FMul : Instruction::Mul;
+ return true;
+ case naclbitc::BINOP_UDIV:
+ LLVMOpcode = Instruction::UDiv;
+ return true;
+ case naclbitc::BINOP_SDIV:
+ LLVMOpcode = Ty->isFPOrFPVectorTy() ? Instruction::FDiv : Instruction::SDiv;
+ return true;
+ case naclbitc::BINOP_UREM:
+ LLVMOpcode = Instruction::URem;
+ return true;
+ case naclbitc::BINOP_SREM:
+ LLVMOpcode = Ty->isFPOrFPVectorTy() ? Instruction::FRem : Instruction::SRem;
+ return true;
+ case naclbitc::BINOP_SHL:
+ LLVMOpcode = Instruction::Shl;
+ return true;
+ case naclbitc::BINOP_LSHR:
+ LLVMOpcode = Instruction::LShr;
+ return true;
+ case naclbitc::BINOP_ASHR:
+ LLVMOpcode = Instruction::AShr;
+ return true;
+ case naclbitc::BINOP_AND:
+ LLVMOpcode = Instruction::And;
+ return true;
+ case naclbitc::BINOP_OR:
+ LLVMOpcode = Instruction::Or;
+ return true;
+ case naclbitc::BINOP_XOR:
+ LLVMOpcode = Instruction::Xor;
+ return true;
+ }
+}
+
+bool DecodeCallingConv(uint64_t NaClCallingConv,
+ CallingConv::ID &LLVMCallingConv) {
+ switch (NaClCallingConv) {
+ default:
+ LLVMCallingConv = CallingConv::C;
+ return false;
+ case naclbitc::C_CallingConv:
+ LLVMCallingConv = CallingConv::C;
+ return true;
+ }
+}
+
+bool DecodeFcmpPredicate(uint64_t NaClPredicate,
+ CmpInst::Predicate &LLVMPredicate) {
+ switch (NaClPredicate) {
+ default:
+ LLVMPredicate = CmpInst::FCMP_FALSE;
+ return false;
+ case naclbitc::FCMP_FALSE:
+ LLVMPredicate = CmpInst::FCMP_FALSE;
+ return true;
+ case naclbitc::FCMP_OEQ:
+ LLVMPredicate = CmpInst::FCMP_OEQ;
+ return true;
+ case naclbitc::FCMP_OGT:
+ LLVMPredicate = CmpInst::FCMP_OGT;
+ return true;
+ case naclbitc::FCMP_OGE:
+ LLVMPredicate = CmpInst::FCMP_OGE;
+ return true;
+ case naclbitc::FCMP_OLT:
+ LLVMPredicate = CmpInst::FCMP_OLT;
+ return true;
+ case naclbitc::FCMP_OLE:
+ LLVMPredicate = CmpInst::FCMP_OLE;
+ return true;
+ case naclbitc::FCMP_ONE:
+ LLVMPredicate = CmpInst::FCMP_ONE;
+ return true;
+ case naclbitc::FCMP_ORD:
+ LLVMPredicate = CmpInst::FCMP_ORD;
+ return true;
+ case naclbitc::FCMP_UNO:
+ LLVMPredicate = CmpInst::FCMP_UNO;
+ return true;
+ case naclbitc::FCMP_UEQ:
+ LLVMPredicate = CmpInst::FCMP_UEQ;
+ return true;
+ case naclbitc::FCMP_UGT:
+ LLVMPredicate = CmpInst::FCMP_UGT;
+ return true;
+ case naclbitc::FCMP_UGE:
+ LLVMPredicate = CmpInst::FCMP_UGE;
+ return true;
+ case naclbitc::FCMP_ULT:
+ LLVMPredicate = CmpInst::FCMP_ULT;
+ return true;
+ case naclbitc::FCMP_ULE:
+ LLVMPredicate = CmpInst::FCMP_ULE;
+ return true;
+ case naclbitc::FCMP_UNE:
+ LLVMPredicate = CmpInst::FCMP_UNE;
+ return true;
+ case naclbitc::FCMP_TRUE:
+ LLVMPredicate = CmpInst::FCMP_TRUE;
+ return true;
+ }
+}
+
+bool DecodeIcmpPredicate(uint64_t NaClPredicate,
+ CmpInst::Predicate &LLVMPredicate) {
+ switch (NaClPredicate) {
+ default:
+ LLVMPredicate = CmpInst::ICMP_EQ;
+ return false;
+ case naclbitc::ICMP_EQ:
+ LLVMPredicate = CmpInst::ICMP_EQ;
+ return true;
+ case naclbitc::ICMP_NE:
+ LLVMPredicate = CmpInst::ICMP_NE;
+ return true;
+ case naclbitc::ICMP_UGT:
+ LLVMPredicate = CmpInst::ICMP_UGT;
+ return true;
+ case naclbitc::ICMP_UGE:
+ LLVMPredicate = CmpInst::ICMP_UGE;
+ return true;
+ case naclbitc::ICMP_ULT:
+ LLVMPredicate = CmpInst::ICMP_ULT;
+ return true;
+ case naclbitc::ICMP_ULE:
+ LLVMPredicate = CmpInst::ICMP_ULE;
+ return true;
+ case naclbitc::ICMP_SGT:
+ LLVMPredicate = CmpInst::ICMP_SGT;
+ return true;
+ case naclbitc::ICMP_SGE:
+ LLVMPredicate = CmpInst::ICMP_SGE;
+ return true;
+ case naclbitc::ICMP_SLT:
+ LLVMPredicate = CmpInst::ICMP_SLT;
+ return true;
+ case naclbitc::ICMP_SLE:
+ LLVMPredicate = CmpInst::ICMP_SLE;
+ return true;
+ }
+}
+
+
+}
+}
diff --git a/pnacl-llvm/NaClBitcodeHeader.cpp b/pnacl-llvm/NaClBitcodeHeader.cpp
new file mode 100644
index 0000000..8a65f50
--- /dev/null
+++ b/pnacl-llvm/NaClBitcodeHeader.cpp
@@ -0,0 +1,351 @@
+//===- NaClBitcodeHeader.cpp ----------------------------------------------===//
+// PNaCl bitcode header reader.
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Bitcode/NaCl/NaClBitcodeHeader.h"
+
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/Bitcode/NaCl/NaClReaderWriter.h"
+#include "llvm/Bitcode/ReaderWriter.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/StreamingMemoryObject.h"
+
+#include <cstring>
+#include <iomanip>
+#include <limits>
+
+using namespace llvm;
+
+namespace {
+
+// The name for each ID tag.
+static const char *TagName[] = {
+ "Invalid", // kInvalid
+ "PNaCl Version", // kPNaClVersion
+ "Align bitcode records" // kAlignBitcodeRecords
+};
+
+// The name for each field type.
+static const char *FieldTypeName[] = {
+ "uint8[]", // kBufferType
+ "uint32", // kUInt32Type
+ "flag", // kFlagType
+ "unknown" // kUnknownType
+};
+
+// The type associated with each ID tag.
+static const NaClBitcodeHeaderField::FieldType ExpectedType[] = {
+ NaClBitcodeHeaderField::kUnknownType, // kInvalid
+ NaClBitcodeHeaderField::kUInt32Type, // kPNaClVersion
+ NaClBitcodeHeaderField::kFlagType // kAlignBitcodeRecords
+};
+
+} // end of anonymous namespace
+
+const char *NaClBitcodeHeaderField::IDName(Tag ID) {
+ return ID > kTag_MAX ? "???" : TagName[ID];
+}
+
+const char *NaClBitcodeHeaderField::TypeName(FieldType FType) {
+ return FType > kFieldType_MAX ? "???" : FieldTypeName[FType];
+}
+
+NaClBitcodeHeaderField::NaClBitcodeHeaderField()
+ : ID(kInvalid), FType(kBufferType), Len(0), Data(0) {}
+
+NaClBitcodeHeaderField::NaClBitcodeHeaderField(Tag MyID)
+ : ID(MyID), FType(kFlagType), Len(0), Data(0) {
+ assert(MyID <= kTag_MAX);
+}
+
+NaClBitcodeHeaderField::NaClBitcodeHeaderField(Tag MyID, uint32_t MyValue)
+ : ID(MyID), FType(kUInt32Type), Len(4), Data(new uint8_t[4]) {
+ assert(MyID <= kTag_MAX);
+ Data[0] = static_cast<uint8_t>(MyValue & 0xFF);
+ Data[1] = static_cast<uint8_t>((MyValue >> 8) & 0xFF);
+ Data[2] = static_cast<uint8_t>((MyValue >> 16) & 0xFF);
+ Data[3] = static_cast<uint8_t>((MyValue >> 24) & 0xFF);
+}
+
+uint32_t NaClBitcodeHeaderField::GetUInt32Value() const {
+ assert(FType == kUInt32Type && "Header field must be uint32");
+ return static_cast<uint32_t>(Data[0]) |
+ (static_cast<uint32_t>(Data[1]) << 8) |
+ (static_cast<uint32_t>(Data[2]) << 16) |
+ (static_cast<uint32_t>(Data[2]) << 24);
+}
+
+NaClBitcodeHeaderField::NaClBitcodeHeaderField(Tag MyID, size_t MyLen,
+ uint8_t *MyData)
+ : ID(MyID), FType(kBufferType), Len(MyLen), Data(new uint8_t[MyLen]) {
+ assert(MyID <= kTag_MAX);
+ for (size_t i = 0; i < MyLen; ++i) {
+ Data[i] = MyData[i];
+ }
+}
+
+bool NaClBitcodeHeaderField::Write(uint8_t *Buf, size_t BufLen) const {
+ size_t FieldsLen = kTagLenSize + Len;
+ size_t PadLen = (WordSize - (FieldsLen & (WordSize-1))) & (WordSize-1);
+ // Ensure buffer is large enough and that length can be represented
+ // in 32 bits
+ if (BufLen < FieldsLen + PadLen ||
+ Len > std::numeric_limits<FixedSubfield>::max())
+ return false;
+
+ WriteFixedSubfield(EncodeTypedID(), Buf);
+ WriteFixedSubfield(static_cast<FixedSubfield>(Len),
+ Buf + sizeof(FixedSubfield));
+ memcpy(Buf + kTagLenSize, Data, Len);
+ // Pad out to word alignment
+ if (PadLen) {
+ memset(Buf + FieldsLen, 0, PadLen);
+ }
+ return true;
+}
+
+bool NaClBitcodeHeaderField::Read(const uint8_t *Buf, size_t BufLen) {
+ if (BufLen < kTagLenSize)
+ return false;
+ FixedSubfield IdField;
+ ReadFixedSubfield(&IdField, Buf);
+ FixedSubfield LengthField;
+ ReadFixedSubfield(&LengthField, Buf + sizeof(FixedSubfield));
+ size_t Length = static_cast<size_t>(LengthField);
+ if (BufLen < kTagLenSize + Length)
+ return false;
+ if (Len != Length) {
+ // Need to reallocate data buffer.
+ if (Data)
+ delete[] Data;
+ Data = new uint8_t[Length];
+ }
+ Len = Length;
+ DecodeTypedID(IdField, ID, FType);
+ memcpy(Data, Buf + kTagLenSize, Len);
+ return true;
+}
+
+std::string NaClBitcodeHeaderField::Contents() const {
+ std::string buffer;
+ raw_string_ostream ss(buffer);
+ ss << IDName() << ": ";
+ switch (FType) {
+ case kFlagType:
+ ss << "true";
+ break;
+ case kUInt32Type:
+ ss << GetUInt32Value();
+ break;
+ case kBufferType:
+ ss << "[";
+ for (size_t i = 0; i < Len; ++i) {
+ if (i)
+ ss << " ";
+ ss << format("%02x", Data[i]);
+ }
+ ss << "]";
+ break;
+ case kUnknownType:
+ ss << "unknown value";
+ break;
+ }
+ return ss.str();
+}
+
+NaClBitcodeHeader::NaClBitcodeHeader()
+ : HeaderSize(0), UnsupportedMessage(), IsSupportedFlag(false),
+ IsReadableFlag(false), PNaClVersion(0) {}
+
+NaClBitcodeHeader::~NaClBitcodeHeader() {
+ for (std::vector<NaClBitcodeHeaderField *>::const_iterator
+ Iter = Fields.begin(),
+ IterEnd = Fields.end();
+ Iter != IterEnd; ++Iter) {
+ delete *Iter;
+ }
+}
+
+bool NaClBitcodeHeader::ReadPrefix(const unsigned char *BufPtr,
+ const unsigned char *BufEnd,
+ unsigned &NumFields, unsigned &NumBytes) {
+ // Must contain PEXE.
+ if (!isNaClBitcode(BufPtr, BufEnd)) {
+ UnsupportedMessage = "Invalid PNaCl bitcode header";
+ if (isBitcode(BufPtr, BufEnd)) {
+ UnsupportedMessage += " (to run in Chrome, bitcode files must be "
+ "finalized using pnacl-finalize)";
+ }
+ return true;
+ }
+ BufPtr += WordSize;
+
+ // Read #Fields and number of bytes needed for the header.
+ if (BufPtr + WordSize > BufEnd)
+ return UnsupportedError("Bitcode read failure");
+ NumFields = static_cast<unsigned>(BufPtr[0]) |
+ (static_cast<unsigned>(BufPtr[1]) << 8);
+ NumBytes = static_cast<unsigned>(BufPtr[2]) |
+ (static_cast<unsigned>(BufPtr[3]) << 8);
+ BufPtr += WordSize;
+ return false;
+}
+
+bool NaClBitcodeHeader::ReadFields(const unsigned char *BufPtr,
+ const unsigned char *BufEnd,
+ unsigned NumFields, unsigned NumBytes) {
+ HeaderSize = NumBytes + (2 * WordSize);
+
+ // Read in each field.
+ for (size_t i = 0; i < NumFields; ++i) {
+ NaClBitcodeHeaderField *Field = new NaClBitcodeHeaderField();
+ Fields.push_back(Field);
+ if (!Field->Read(BufPtr, BufEnd - BufPtr))
+ return UnsupportedError("Bitcode read failure");
+ size_t FieldSize = Field->GetTotalSize();
+ BufPtr += FieldSize;
+ }
+ return false;
+}
+
+bool NaClBitcodeHeader::Read(const unsigned char *BufPtr,
+ const unsigned char *BufEnd) {
+ unsigned NumFields;
+ unsigned NumBytes;
+ if (ReadPrefix(BufPtr, BufEnd, NumFields, NumBytes))
+ return true; // ReadPrefix sets UnsupportedMessage
+ BufPtr += 2 * WordSize;
+
+ if (ReadFields(BufPtr, BufEnd, NumFields, NumBytes))
+ return true; // ReadFields sets UnsupportedMessage
+ BufPtr += NumBytes;
+ InstallFields();
+ return false;
+}
+
+bool NaClBitcodeHeader::Read(MemoryObject *Bytes) {
+ unsigned NumFields;
+ unsigned NumBytes;
+ // First, read the prefix, which is 2 * WordSize, to determine the
+ // NumBytes and NumFields.
+ {
+ unsigned char Buffer[2 * WordSize];
+ if (Bytes->readBytes(Buffer, sizeof(Buffer), 0) != sizeof(Buffer))
+ return UnsupportedError("Bitcode read failure");
+ if (ReadPrefix(Buffer, Buffer + sizeof(Buffer), NumFields, NumBytes))
+ return true; // ReadPrefix sets UnsupportedMessage
+ }
+ // Then read the rest, starting after the 2 * WordSize of the prefix.
+ uint8_t *Header = new uint8_t[NumBytes];
+ bool failed =
+ Bytes->readBytes(Header, NumBytes, 2 * WordSize) != NumBytes ||
+ ReadFields(Header, Header + NumBytes, NumFields, NumBytes);
+ delete[] Header;
+ if (failed)
+ return UnsupportedError("Bitcode read failure");
+ InstallFields();
+ return false;
+}
+
+NaClBitcodeHeaderField *
+NaClBitcodeHeader::GetTaggedField(NaClBitcodeHeaderField::Tag ID) const {
+ for (std::vector<NaClBitcodeHeaderField *>::const_iterator
+ Iter = Fields.begin(),
+ IterEnd = Fields.end();
+ Iter != IterEnd; ++Iter) {
+ if ((*Iter)->GetID() == ID) {
+ return *Iter;
+ }
+ }
+ return 0;
+}
+
+NaClBitcodeHeaderField *NaClBitcodeHeader::GetField(size_t index) const {
+ if (index >= Fields.size())
+ return 0;
+ return Fields[index];
+}
+
+NaClBitcodeHeaderField *GetPNaClVersionPtr(NaClBitcodeHeader *Header) {
+ if (NaClBitcodeHeaderField *Version =
+ Header->GetTaggedField(NaClBitcodeHeaderField::kPNaClVersion)) {
+ if (Version->GetType() == NaClBitcodeHeaderField::kUInt32Type) {
+ return Version;
+ }
+ }
+ return 0;
+}
+
+void NaClBitcodeHeader::InstallFields() {
+ IsSupportedFlag = true;
+ IsReadableFlag = true;
+ AlignBitcodeRecords = false;
+ PNaClVersion = 0;
+ UnsupportedMessage.clear();
+ SmallSet<unsigned, NaClBitcodeHeaderField::kTag_MAX> FieldIDs;
+
+ auto ReportProblem = [&](bool IsReadable) {
+ UnsupportedMessage.append("\n");
+ IsSupportedFlag = false;
+ IsReadableFlag = IsReadableFlag && IsReadable;
+ };
+
+ auto ReportProblemWithContents = [&](NaClBitcodeHeaderField *Field,
+ bool IsReadable) {
+ UnsupportedMessage.append(": ");
+ UnsupportedMessage.append(Field->Contents());
+ ReportProblem(IsReadable);
+ };
+
+ for (size_t i = 0, e = NumberFields(); i < e; ++i) {
+ // Start by checking expected properties for any field
+ NaClBitcodeHeaderField *Field = GetField(i);
+ if (!FieldIDs.insert(Field->GetID()).second) {
+ UnsupportedMessage.append("Specified multiple times: ");
+ UnsupportedMessage.append(Field->IDName());
+ ReportProblem(false);
+ continue;
+ }
+ NaClBitcodeHeaderField::FieldType ExpectedTy = ExpectedType[Field->GetID()];
+ if (Field->GetType() != ExpectedTy) {
+ UnsupportedMessage.append("Expects type ");
+ UnsupportedMessage.append(NaClBitcodeHeaderField::TypeName(ExpectedTy));
+ ReportProblemWithContents(Field, false);
+ continue;
+ }
+ if (Field->GetType() == NaClBitcodeHeaderField::kUnknownType) {
+ UnsupportedMessage.append("Unknown value");
+ ReportProblemWithContents(Field, false);
+ continue;
+ }
+
+ // Check specific ID values and install.
+ switch (Field->GetID()) {
+ case NaClBitcodeHeaderField::kInvalid:
+ UnsupportedMessage.append("Unsupported");
+ ReportProblemWithContents(Field, false);
+ continue;
+ case NaClBitcodeHeaderField::kPNaClVersion:
+ PNaClVersion = Field->GetUInt32Value();
+ if (PNaClVersion != 2) {
+ UnsupportedMessage.append("Unsupported");
+ ReportProblemWithContents(Field, false);
+ continue;
+ }
+ break;
+ case NaClBitcodeHeaderField::kAlignBitcodeRecords:
+ AlignBitcodeRecords = true;
+ UnsupportedMessage.append("Unsupported");
+ ReportProblemWithContents(Field, true);
+ continue;
+ }
+ }
+}
diff --git a/pnacl-llvm/NaClBitcodeParser.cpp b/pnacl-llvm/NaClBitcodeParser.cpp
new file mode 100644
index 0000000..30744ec
--- /dev/null
+++ b/pnacl-llvm/NaClBitcodeParser.cpp
@@ -0,0 +1,159 @@
+//===- NaClBitcodeParser.cpp ----------------------------------------------===//
+// Low-level bitcode driver to parse PNaCl bitcode files.
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Bitcode/NaCl/NaClBitcodeParser.h"
+
+using namespace llvm;
+
+void NaClBitcodeRecordData::Print(raw_ostream &os) const {
+ os << "[" << Code;
+ for (NaClRecordVector::const_iterator
+ Iter = Values.begin(), IterEnd = Values.end();
+ Iter != IterEnd; ++Iter) {
+ os << ", " << *Iter;
+ }
+ os << "]";
+}
+
+void NaClBitcodeRecord::Print(raw_ostream& os) const {
+ Block.Print(os);
+ os << ", Code " << Data.Code << ", EntryID " << Entry.ID << ", <";
+ for (unsigned i = 0, e = Data.Values.size(); i != e; ++i) {
+ if (i > 0) os << " ";
+ os << Data.Values[i];
+ }
+ os << ">";
+}
+
+NaClBitcodeBlock::NaClBitcodeBlock(unsigned BlockID,
+ const NaClBitcodeRecord &Record)
+ : NaClBitcodeData(Record),
+ BlockID(BlockID),
+ EnclosingBlock(&Record.GetBlock()),
+ LocalStartBit(Record.GetStartBit())
+{}
+
+void NaClBitcodeBlock::Print(raw_ostream &os) const {
+ os << "Block " << BlockID;
+}
+
+void NaClBitcodeParserListener::BeginBlockInfoBlock(unsigned NumWords) {
+ Parser->EnterBlock(NumWords);
+}
+
+void NaClBitcodeParserListener::SetBID() {
+ Parser->Record.SetStartBit(StartBit);
+ Parser->Record.Entry.Kind = NaClBitstreamEntry::Record;
+ Parser->Record.Entry.ID = naclbitc::UNABBREV_RECORD;
+ Parser->Record.Data.Code = naclbitc::BLOCKINFO_CODE_SETBID;
+ Parser->Record.Data.Values = Values;
+ GlobalBlockID = Values[0];
+ Parser->SetBID();
+ Values.clear();
+}
+
+void NaClBitcodeParserListener::EndBlockInfoBlock() {
+ Parser->Record.SetStartBit(StartBit);
+ Parser->Record.Entry.Kind = NaClBitstreamEntry::EndBlock;
+ Parser->Record.Entry.ID = naclbitc::END_BLOCK;
+ Parser->Record.Data.Code = naclbitc::END_BLOCK;
+ Parser->Record.Data.Values.clear();
+ GlobalBlockID = naclbitc::BLOCKINFO_BLOCK_ID;
+ Parser->ExitBlock();
+}
+
+void NaClBitcodeParserListener::
+ProcessAbbreviation(NaClBitCodeAbbrev *Abbrev, bool IsLocal) {
+ Parser->Record.SetStartBit(StartBit);
+ Parser->Record.Entry.Kind = NaClBitstreamEntry::Record;
+ Parser->Record.Entry.ID = naclbitc::DEFINE_ABBREV;
+ Parser->Record.Data.Code = naclbitc::BLK_CODE_DEFINE_ABBREV;
+ Parser->Record.Data.Values = Values;
+ Parser->ProcessAbbreviation(IsLocal ? Parser->GetBlockID() : GlobalBlockID,
+ Abbrev, IsLocal);
+}
+
+NaClBitcodeParser::~NaClBitcodeParser() {
+ if (EnclosingParser) {
+ EnclosingParser->Block.LocalStartBit += Block.GetNumBits();
+ }
+}
+
+bool NaClBitcodeParser::ErrorAt(
+ naclbitc::ErrorLevel Level, uint64_t BitPosition,
+ const std::string &Message) {
+ naclbitc::ErrorAt(*ErrStream, Level, BitPosition) << Message << "\n";
+ if (Level == naclbitc::Fatal)
+ report_fatal_error("Unable to continue");
+ return true;
+}
+
+bool NaClBitcodeParser::Parse() {
+ Record.ReadEntry();
+
+ if (Record.GetEntryKind() != NaClBitstreamEntry::SubBlock)
+ return Error("Expected block, but not found");
+
+ return ParseBlock(Record.GetEntryID());
+}
+
+bool NaClBitcodeParser::ParseBlockInfoInternal() {
+ // BLOCKINFO is a special part of the stream. Let the bitstream
+ // reader process this block.
+ bool Result = Record.GetCursor().ReadBlockInfoBlock(Listener);
+ if (Result) return Error("Malformed BlockInfoBlock");
+ return Result;
+}
+
+bool NaClBitcodeParser::ParseBlockInternal() {
+ // Regular block. Enter subblock.
+ unsigned NumWords;
+ if (Record.GetCursor().EnterSubBlock(GetBlockID(), &NumWords)) {
+ return Error("Malformed block record");
+ }
+
+ EnterBlock(NumWords);
+
+ // Process records.
+ while (1) {
+ if (Record.GetCursor().AtEndOfStream())
+ return Error("Premature end of bitstream");
+
+ // Read entry defining type of entry.
+ Record.ReadEntry();
+
+ switch (Record.GetEntryKind()) {
+ case NaClBitstreamEntry::Error:
+ return Error("malformed bitcode file");
+ case NaClBitstreamEntry::EndBlock: {
+ return false;
+ }
+ case NaClBitstreamEntry::SubBlock: {
+ if (ParseBlock(Record.GetEntryID())) return true;
+ break;
+ }
+ case NaClBitstreamEntry::Record:
+ // The interesting case.
+ if (Record.GetEntryID() == naclbitc::DEFINE_ABBREV) {
+ // Since this abbreviation is local, the listener doesn't
+ // have the start bit set (it is only set when processing
+ // the BlockInfo block). Fix this by setting it here.
+ if (Listener) Listener->StartBit = Record.GetStartBit();
+ Record.GetCursor().ReadAbbrevRecord(true, Listener);
+ } else {
+ // Read in a record.
+ Record.ReadValues();
+ ProcessRecord();
+ }
+ break;
+ }
+ }
+ return false;
+}
diff --git a/pnacl-llvm/NaClBitstreamReader.cpp b/pnacl-llvm/NaClBitstreamReader.cpp
new file mode 100644
index 0000000..8aab59d
--- /dev/null
+++ b/pnacl-llvm/NaClBitstreamReader.cpp
@@ -0,0 +1,444 @@
+//===- NaClBitstreamReader.cpp --------------------------------------------===//
+// NaClBitstreamReader implementation
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Bitcode/NaCl/NaClBitstreamReader.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+namespace {
+
+static const char *ErrorLevelName[] = {
+ "Warning",
+ "Error",
+ "Fatal"
+};
+
+} // End of anonymous namespace.
+
+std::string llvm::naclbitc::getBitAddress(uint64_t Bit) {
+ std::string Buffer;
+ raw_string_ostream Stream(Buffer);
+ Stream << (Bit / 8) << ":" << (Bit % 8);
+ return Stream.str();
+}
+
+raw_ostream &llvm::naclbitc::ErrorAt(
+ raw_ostream &Out, ErrorLevel Level, uint64_t BitPosition) {
+ assert(Level < array_lengthof(::ErrorLevelName));
+ return Out << ErrorLevelName[Level] << "("
+ << naclbitc::getBitAddress(BitPosition) << "): ";
+}
+
+//===----------------------------------------------------------------------===//
+// NaClBitstreamCursor implementation
+//===----------------------------------------------------------------------===//
+
+void NaClBitstreamCursor::ErrorHandler::
+Fatal(const std::string &ErrorMessage) const {
+ // Default implementation is simply print message, and the bit where
+ // the error occurred.
+ std::string Buffer;
+ raw_string_ostream StrBuf(Buffer);
+ naclbitc::ErrorAt(StrBuf, naclbitc::Fatal,
+ Cursor.getErrorBitNo(getCurrentBitNo())) << ErrorMessage;
+ report_fatal_error(StrBuf.str());
+}
+
+void NaClBitstreamCursor::reportInvalidAbbrevNumber(unsigned AbbrevNo) const {
+ std::string Buffer;
+ raw_string_ostream StrBuf(Buffer);
+ StrBuf << "Invalid abbreviation # " << AbbrevNo << " defined for record";
+ ErrHandler->Fatal(StrBuf.str());
+}
+
+void NaClBitstreamCursor::reportInvalidJumpToBit(uint64_t BitNo) const {
+ std::string Buffer;
+ raw_string_ostream StrBuf(Buffer);
+ StrBuf << "Invalid jump to bit " << BitNo;
+ ErrHandler->Fatal(StrBuf.str());
+}
+
+/// EnterSubBlock - Having read the ENTER_SUBBLOCK abbrevid, enter
+/// the block, and return true if the block has an error.
+bool NaClBitstreamCursor::EnterSubBlock(unsigned BlockID, unsigned *NumWordsP) {
+ const bool IsFixed = true;
+ NaClBitcodeSelectorAbbrev
+ CodeAbbrev(IsFixed, ReadVBR(naclbitc::CodeLenWidth));
+ BlockScope.push_back(Block(BitStream->getBlockInfo(BlockID), CodeAbbrev));
+ SkipToFourByteBoundary();
+ unsigned NumWords = Read(naclbitc::BlockSizeWidth);
+ if (NumWordsP) *NumWordsP = NumWords;
+
+ // Validate that this block is sane.
+ if (BlockScope.back().getCodeAbbrev().NumBits == 0 || AtEndOfStream())
+ return true;
+
+ return false;
+}
+
+void NaClBitstreamCursor::skipAbbreviatedField(const NaClBitCodeAbbrevOp &Op) {
+ // Decode the value as we are commanded.
+ switch (Op.getEncoding()) {
+ case NaClBitCodeAbbrevOp::Literal:
+ // No read necessary for literal.
+ break;
+ case NaClBitCodeAbbrevOp::Fixed:
+ (void)Read((unsigned)Op.getValue());
+ break;
+ case NaClBitCodeAbbrevOp::VBR:
+ (void)ReadVBR64((unsigned)Op.getValue());
+ break;
+ case NaClBitCodeAbbrevOp::Array:
+ // This can't happen because the abbreviation must be valid.
+ llvm_unreachable("Bad array abbreviation encoding!");
+ break;
+ case NaClBitCodeAbbrevOp::Char6:
+ (void)Read(6);
+ break;
+ }
+}
+
+/// skipRecord - Read the current record and discard it.
+void NaClBitstreamCursor::skipRecord(unsigned AbbrevID) {
+ // Skip unabbreviated records by reading past their entries.
+ if (AbbrevID == naclbitc::UNABBREV_RECORD) {
+ unsigned Code = ReadVBR(6);
+ (void)Code;
+ unsigned NumElts = ReadVBR(6);
+ for (unsigned i = 0; i != NumElts; ++i)
+ (void)ReadVBR64(6);
+ SkipToByteBoundaryIfAligned();
+ return;
+ }
+
+ const NaClBitCodeAbbrev *Abbv = getAbbrev(AbbrevID);
+
+ for (unsigned i = 0, e = Abbv->getNumOperandInfos(); i != e; ++i) {
+ const NaClBitCodeAbbrevOp &Op = Abbv->getOperandInfo(i);
+ switch (Op.getEncoding()) {
+ default:
+ skipAbbreviatedField(Op);
+ break;
+ case NaClBitCodeAbbrevOp::Literal:
+ break;
+ case NaClBitCodeAbbrevOp::Array: {
+ // Array case. Read the number of elements as a vbr6.
+ unsigned NumElts = ReadVBR(6);
+
+ // Get the element encoding.
+ const NaClBitCodeAbbrevOp &EltEnc = Abbv->getOperandInfo(++i);
+
+ // Read all the elements.
+ for (; NumElts; --NumElts)
+ skipAbbreviatedField(EltEnc);
+ break;
+ }
+ }
+ }
+ SkipToByteBoundaryIfAligned();
+}
+
+bool NaClBitstreamCursor::readRecordAbbrevField(
+ const NaClBitCodeAbbrevOp &Op, uint64_t &Value) {
+ switch (Op.getEncoding()) {
+ case NaClBitCodeAbbrevOp::Literal:
+ Value = Op.getValue();
+ break;
+ case NaClBitCodeAbbrevOp::Array:
+ // Returns number of elements in the array.
+ Value = ReadVBR(6);
+ return true;
+ case NaClBitCodeAbbrevOp::Fixed:
+ Value = Read((unsigned)Op.getValue());
+ break;
+ case NaClBitCodeAbbrevOp::VBR:
+ Value = ReadVBR64((unsigned)Op.getValue());
+ break;
+ case NaClBitCodeAbbrevOp::Char6:
+ Value = NaClBitCodeAbbrevOp::DecodeChar6(Read(6));
+ break;
+ }
+ return false;
+}
+
+uint64_t NaClBitstreamCursor::readArrayAbbreviatedField(
+ const NaClBitCodeAbbrevOp &Op) {
+ // Decode the value as we are commanded.
+ switch (Op.getEncoding()) {
+ case NaClBitCodeAbbrevOp::Literal:
+ return Op.getValue();
+ case NaClBitCodeAbbrevOp::Fixed:
+ return Read((unsigned)Op.getValue());
+ case NaClBitCodeAbbrevOp::VBR:
+ return ReadVBR64((unsigned)Op.getValue());
+ case NaClBitCodeAbbrevOp::Array:
+ // This can't happen because the abbreviation must be valid.
+ llvm_unreachable("Bad array abbreviation encoding!");
+ break;
+ case NaClBitCodeAbbrevOp::Char6:
+ return NaClBitCodeAbbrevOp::DecodeChar6(Read(6));
+ }
+}
+
+void NaClBitstreamCursor::readArrayAbbrev(
+ const NaClBitCodeAbbrevOp &Op, unsigned NumArrayElements,
+ SmallVectorImpl<uint64_t> &Vals) {
+ for (; NumArrayElements; --NumArrayElements) {
+ Vals.push_back(readArrayAbbreviatedField(Op));
+ }
+}
+
+unsigned NaClBitstreamCursor::readRecord(unsigned AbbrevID,
+ SmallVectorImpl<uint64_t> &Vals) {
+ if (AbbrevID == naclbitc::UNABBREV_RECORD) {
+ unsigned Code = ReadVBR(6);
+ unsigned NumElts = ReadVBR(6);
+ for (unsigned i = 0; i != NumElts; ++i)
+ Vals.push_back(ReadVBR64(6));
+ SkipToByteBoundaryIfAligned();
+ return Code;
+ }
+
+ // Read code.
+ const NaClBitCodeAbbrev *Abbv = getAbbrev(AbbrevID);
+ uint64_t Value;
+ unsigned Code;
+ if (readRecordAbbrevField(Abbv->getOperandInfo(0), Value)) {
+ // Array found, use to read all elements.
+ if (Value == 0)
+ ErrHandler->Fatal("No code found for record!");
+ const NaClBitCodeAbbrevOp &Op = Abbv->getOperandInfo(1);
+ Code = readArrayAbbreviatedField(Op);
+ readArrayAbbrev(Op, Value - 1, Vals);
+ SkipToByteBoundaryIfAligned();
+ return Code;
+ }
+ Code = Value;
+
+ // Read arguments.
+ unsigned NumOperands = Abbv->getNumOperandInfos();
+ for (unsigned i = 1; i != NumOperands; ++i) {
+ if (readRecordAbbrevField(Abbv->getOperandInfo(i), Value)) {
+ ++i;
+ readArrayAbbrev(Abbv->getOperandInfo(i), Value, Vals);
+ SkipToByteBoundaryIfAligned();
+ return Code;
+ }
+ Vals.push_back(Value);
+ }
+ SkipToByteBoundaryIfAligned();
+ return Code;
+}
+
+
+NaClBitCodeAbbrevOp::Encoding NaClBitstreamCursor::
+getEncoding(uint64_t Value) {
+ if (!NaClBitCodeAbbrevOp::isValidEncoding(Value)) {
+ std::string Buffer;
+ raw_string_ostream StrBuf(Buffer);
+ StrBuf << "Invalid abbreviation encoding specified in bitcode file: "
+ << Value;
+ ErrHandler->Fatal(StrBuf.str());
+ }
+ return NaClBitCodeAbbrevOp::Encoding(Value);
+}
+
+void NaClBitstreamCursor::ReadAbbrevRecord(bool IsLocal,
+ NaClAbbrevListener *Listener) {
+ NaClBitCodeAbbrev *Abbv = BlockScope.back().appendLocalCreate();
+ unsigned NumOpInfo = ReadVBR(5);
+ if (Listener) Listener->Values.push_back(NumOpInfo);
+ for (unsigned i = 0; i != NumOpInfo; ++i) {
+ bool IsLiteral = Read(1) ? true : false;
+ if (Listener) Listener->Values.push_back(IsLiteral);
+ if (IsLiteral) {
+ uint64_t Value = ReadVBR64(8);
+ if (Listener) Listener->Values.push_back(Value);
+ Abbv->Add(NaClBitCodeAbbrevOp(Value));
+ continue;
+ }
+ NaClBitCodeAbbrevOp::Encoding E = getEncoding(Read(3));
+ if (Listener) Listener->Values.push_back(E);
+ if (NaClBitCodeAbbrevOp::hasValue(E)) {
+ unsigned Data = ReadVBR64(5);
+ if (Listener) Listener->Values.push_back(Data);
+
+ // As a special case, handle fixed(0) (i.e., a fixed field with zero bits)
+ // and vbr(0) as a literal zero. This is decoded the same way, and avoids
+ // a slow path in Read() to have to handle reading zero bits.
+ if ((E == NaClBitCodeAbbrevOp::Fixed || E == NaClBitCodeAbbrevOp::VBR) &&
+ Data == 0) {
+ if (Listener) Listener->Values.push_back(0);
+ Abbv->Add(NaClBitCodeAbbrevOp(0));
+ continue;
+ }
+ if (!NaClBitCodeAbbrevOp::isValid(E, Data)) {
+ std::string Buffer;
+ raw_string_ostream StrBuf(Buffer);
+ StrBuf << "Invalid abbreviation encoding ("
+ << NaClBitCodeAbbrevOp::getEncodingName(E)
+ << ", " << Data << ")";
+ ErrHandler->Fatal(StrBuf.str());
+ }
+ Abbv->Add(NaClBitCodeAbbrevOp(E, Data));
+ } else {
+ if (!NaClBitCodeAbbrevOp::isValid(E)) {
+ std::string Buffer;
+ raw_string_ostream StrBuf(Buffer);
+ StrBuf << "Invalid abbreviation encoding ("
+ << NaClBitCodeAbbrevOp::getEncodingName(E) << ")";
+ ErrHandler->Fatal(StrBuf.str());
+ }
+ Abbv->Add(NaClBitCodeAbbrevOp(E));
+ }
+ }
+ SkipToByteBoundaryIfAligned();
+ if (!Abbv->isValid())
+ ErrHandler->Fatal("Invalid abbreviation specified in bitcode file");
+ if (Listener) {
+ Listener->ProcessAbbreviation(Abbv, IsLocal);
+ // Reset record information of the listener.
+ Listener->Values.clear();
+ Listener->StartBit = GetCurrentBitNo();
+ }
+}
+
+void NaClBitstreamCursor::SkipAbbrevRecord() {
+ unsigned NumOpInfo = ReadVBR(5);
+ for (unsigned i = 0; i != NumOpInfo; ++i) {
+ bool IsLiteral = Read(1) ? true : false;
+ if (IsLiteral) {
+ ReadVBR64(8);
+ continue;
+ }
+ NaClBitCodeAbbrevOp::Encoding E = getEncoding(Read(3));
+ if (NaClBitCodeAbbrevOp::hasValue(E)) {
+ ReadVBR64(5);
+ }
+ }
+ SkipToByteBoundaryIfAligned();
+}
+
+namespace {
+
+unsigned ValidBlockIDs[] = {
+ naclbitc::BLOCKINFO_BLOCK_ID,
+ naclbitc::CONSTANTS_BLOCK_ID,
+ naclbitc::FUNCTION_BLOCK_ID,
+ naclbitc::GLOBALVAR_BLOCK_ID,
+ naclbitc::MODULE_BLOCK_ID,
+ naclbitc::TOP_LEVEL_BLOCKID,
+ naclbitc::TYPE_BLOCK_ID_NEW,
+ naclbitc::VALUE_SYMTAB_BLOCK_ID
+};
+
+} // end of anonymous namespace
+
+NaClBitstreamReader::BlockInfoRecordsMap::
+BlockInfoRecordsMap() : IsFrozen(false) {
+ for (size_t BlockID : ValidBlockIDs) {
+ std::unique_ptr<BlockInfo> Info(new BlockInfo(BlockID));
+ KnownInfos.emplace(BlockID, std::move(Info));
+ }
+}
+
+NaClBitstreamReader::BlockInfo * NaClBitstreamReader::BlockInfoRecordsMap::
+getOrCreateUnknownBlockInfo(unsigned BlockID) {
+ std::unique_lock<std::mutex> Lock(UnknownBlockInfoLock);
+ while (true) {
+ auto Pos = UnknownInfos.find(BlockID);
+ if (Pos != UnknownInfos.end())
+ return Pos->second.get();
+ // Install, then let next iteration find.
+ std::unique_ptr<BlockInfo> Info(new BlockInfo(BlockID));
+ UnknownInfos.emplace(BlockID, std::move(Info));
+ }
+}
+
+NaClBitstreamReader::BlockInfoRecordsMap::UpdateLock::
+UpdateLock(BlockInfoRecordsMap &BlockInfoRecords)
+ : BlockInfoRecords(BlockInfoRecords),
+ Lock(BlockInfoRecords.UpdateRecordsLock) {}
+
+NaClBitstreamReader::BlockInfoRecordsMap::UpdateLock::
+~UpdateLock() {
+ if (BlockInfoRecords.freeze())
+ report_fatal_error("Global abbreviations block frozen while building.");
+}
+
+bool NaClBitstreamCursor::ReadBlockInfoBlock(NaClAbbrevListener *Listener) {
+ // If this is the second read of the block info block, skip it.
+ if (BitStream->BlockInfoRecords->isFrozen())
+ return SkipBlock();
+
+ NaClBitstreamReader::BlockInfoRecordsMap::UpdateLock
+ Lock(*BitStream->BlockInfoRecords);
+ unsigned NumWords;
+ if (EnterSubBlock(naclbitc::BLOCKINFO_BLOCK_ID, &NumWords)) return true;
+
+ if (Listener) Listener->BeginBlockInfoBlock(NumWords);
+
+ NaClBitcodeRecordVector Record;
+ Block &CurBlock = BlockScope.back();
+ NaClBitstreamReader::AbbrevList *UpdateAbbrevs =
+ &CurBlock.GlobalAbbrevs->getAbbrevs();
+ bool FoundSetBID = false;
+
+ // Read records of the BlockInfo block.
+ while (1) {
+ if (Listener) Listener->StartBit = GetCurrentBitNo();
+ NaClBitstreamEntry Entry = advance(AF_DontAutoprocessAbbrevs, Listener);
+
+ switch (Entry.Kind) {
+ case llvm::NaClBitstreamEntry::SubBlock: // PNaCl doesn't allow!
+ case llvm::NaClBitstreamEntry::Error:
+ return true;
+ case llvm::NaClBitstreamEntry::EndBlock:
+ if (Listener) Listener->EndBlockInfoBlock();
+ return false;
+ case llvm::NaClBitstreamEntry::Record:
+ // The interesting case.
+ break;
+ }
+
+ // Read abbrev records, associate them with CurBID.
+ if (Entry.ID == naclbitc::DEFINE_ABBREV) {
+ ReadAbbrevRecord(false, Listener);
+
+ // ReadAbbrevRecord installs a local abbreviation. Move it to the
+ // appropriate BlockInfo if the corresponding SetBID record has been
+ // found.
+ if (FoundSetBID)
+ CurBlock.moveLocalAbbrevToAbbrevList(UpdateAbbrevs);
+ continue;
+ }
+
+ // Read a record.
+ Record.clear();
+ switch (readRecord(Entry.ID, Record)) {
+ default:
+ // No other records should be found!
+ return true;
+ case naclbitc::BLOCKINFO_CODE_SETBID:
+ if (Record.size() < 1) return true;
+ FoundSetBID = true;
+ UpdateAbbrevs =
+ &BitStream->getBlockInfo((unsigned)Record[0])->getAbbrevs();
+ if (Listener) {
+ Listener->Values = Record;
+ Listener->SetBID();
+ }
+ break;
+ }
+ }
+}
diff --git a/pnacl-llvm/README.txt b/pnacl-llvm/README.txt
new file mode 100644
index 0000000..34c421c
--- /dev/null
+++ b/pnacl-llvm/README.txt
@@ -0,0 +1,9 @@
+The files in this directory are copied verbatim from the PNaCl repository. They
+are ultimately needed by PNaClTranslator.cpp.
+
+Individual files are copied from:
+
+https://chromium.googlesource.com/native_client/pnacl-llvm/+/master/include/llvm/Bitcode/NaCl/
+https://chromium.googlesource.com/native_client/pnacl-llvm/+/master/lib/Bitcode/NaCl/Reader/
+
+Only the files needed for compiling and linking pnacl-sz are copied.
diff --git a/pnacl-llvm/include/llvm/Bitcode/NaCl/NaClBitCodes.h b/pnacl-llvm/include/llvm/Bitcode/NaCl/NaClBitCodes.h
new file mode 100644
index 0000000..44069a5
--- /dev/null
+++ b/pnacl-llvm/include/llvm/Bitcode/NaCl/NaClBitCodes.h
@@ -0,0 +1,412 @@
+//===- NaClBitCodes.h - Enum values for the bitcode format ------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This header Bitcode enum values.
+//
+// The enum values defined in this file should be considered permanent. If
+// new features are added, they should have values added at the end of the
+// respective lists.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_BITCODE_NACL_NACLBITCODES_H
+#define LLVM_BITCODE_NACL_NACLBITCODES_H
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MathExtras.h"
+#include <climits>
+
+namespace llvm {
+class raw_ostream;
+
+namespace naclbitc {
+enum StandardWidths {
+ BlockIDWidth = 8, // We use VBR-8 for block IDs.
+ CodeLenWidth = 4, // Codelen are VBR-4.
+ BlockSizeWidth = 32, // BlockSize up to 2^32 32-bit words = 16GB per block.
+ MaxAbbrevWidth = 32, // Maximum value allowed for Fixed and VBR.
+ BitstreamWordSize = sizeof(uint32_t), // Number of bytes in bitstream word.
+ MinRecordBitSize = 2 // Minimum number of bits needed to represent a record.
+};
+
+ // The standard abbrev namespace always has a way to exit a block, enter a
+ // nested block, define abbrevs, and define an unabbreviated record.
+ enum FixedAbbrevIDs {
+ END_BLOCK = 0, // Must be zero to guarantee termination for broken bitcode.
+ ENTER_SUBBLOCK = 1,
+
+ /// DEFINE_ABBREV - Defines an abbrev for the current block. It consists
+ /// of a vbr5 for # operand infos. Each operand info is emitted with a
+ /// single bit to indicate if it is a literal encoding. If so, the value is
+ /// emitted with a vbr8. If not, the encoding is emitted as 3 bits followed
+ /// by the info value as a vbr5 if needed.
+ DEFINE_ABBREV = 2,
+
+ // UNABBREV_RECORDs are emitted with a vbr6 for the record code, followed by
+ // a vbr6 for the # operands, followed by vbr6's for each operand.
+ UNABBREV_RECORD = 3,
+
+ // This is not a code, this is a marker for the first abbrev assignment.
+ // In addition, we assume up to two additional enumerated constants are
+ // added for each extension. These constants are:
+ //
+ // PREFIX_MAX_FIXED_ABBREV
+ // PREFIX_MAX_ABBREV
+ //
+ // PREFIX_MAX_ABBREV defines the maximal enumeration value used for
+ // the code selector of a block. If Both PREFIX_MAX_FIXED_ABBREV
+ // and PREFIX_MAX_ABBREV is defined, then PREFIX_MAX_FIXED_ABBREV
+ // defines the last code selector of the block that must be read using
+ // a single read (i.e. a FIXED read, or the first chunk of a VBR read.
+ FIRST_APPLICATION_ABBREV = 4,
+ // Defines default values for code length, if no additional selectors
+ // are added.
+ DEFAULT_MAX_ABBREV = FIRST_APPLICATION_ABBREV-1
+ };
+
+ /// StandardBlockIDs - All bitcode files can optionally include a BLOCKINFO
+ /// block, which contains metadata about other blocks in the file.
+ enum StandardBlockIDs {
+ /// BLOCKINFO_BLOCK is used to define metadata about blocks, for example,
+ /// standard abbrevs that should be available to all blocks of a specified
+ /// ID.
+ BLOCKINFO_BLOCK_ID = 0,
+ // Block IDs 1-6 are reserved for future expansion.
+ // Dummy block added around all records in a bitcode file. Allows the code
+ // to treat top-level records like all other records (i.e. all records
+ // appear in a block).
+ TOP_LEVEL_BLOCKID = 7,
+ FIRST_APPLICATION_BLOCKID = 8
+ };
+
+ /// BlockInfoCodes - The blockinfo block contains metadata about user-defined
+ /// blocks.
+ enum BlockInfoCodes {
+ // DEFINE_ABBREV has magic semantics here, applying to the current SETBID'd
+ // block, instead of the BlockInfo block.
+
+ BLOCKINFO_CODE_SETBID = 1, // SETBID: [blockid#]
+ // The following two codes were removed
+ // because the PNaCl reader could read
+ // them, but couldn't be generated by
+ // the writer.
+ BLOCKINFO_CODE_BLOCKNAME = 2, // Not used in PNaCl.
+ BLOCKINFO_CODE_SETRECORDNAME = 3 // Not used in PNaCl.
+ };
+
+} // End naclbitc namespace
+
+/// NaClBitCodeAbbrevOp - This describes one or more operands in an abbreviation.
+/// This is actually a union of two different things:
+/// 1. It could be a literal integer value ("the operand is always 17").
+/// 2. It could be an encoding specification ("this operand encoded like so").
+///
+class NaClBitCodeAbbrevOp {
+public:
+ enum Encoding {
+ Literal = 0, // Value is literal value.
+ Fixed = 1, // A fixed width field, Val specifies number of bits.
+ VBR = 2, // A VBR field where Val specifies the width of each chunk.
+ Array = 3, // A sequence of fields, next field species elt encoding.
+ Char6 = 4, // A 6-bit fixed field which maps to [a-zA-Z0-9._].
+ Encoding_MAX = Char6
+ };
+
+ explicit NaClBitCodeAbbrevOp(uint64_t V) : Enc(Literal), Val(V) {}
+ explicit NaClBitCodeAbbrevOp(Encoding E, uint64_t Data = 0);
+
+ Encoding getEncoding() const { return Enc; }
+
+ static bool isValidEncoding(uint64_t Enc) { return Enc <= Encoding_MAX; }
+
+ uint64_t getValue() const { return Val; }
+
+ bool hasValue() const {
+ return hasValue(Enc);
+ }
+ static bool hasValue(Encoding E) {
+ return E <= Encoding_MAX && HasValueArray[E];
+ }
+
+ bool isValid() const { return isValid(Enc, Val); }
+ static bool isValid(Encoding E, uint64_t Val);
+ static bool isValid(Encoding E) { return isValid(E, 0); }
+
+ bool isLiteral() const { return Enc == Literal; }
+
+ bool isArrayOp() const { return Enc == Array; }
+
+ /// Returns the number of arguments expected by this abbrevation operator.
+ unsigned NumArguments() const {
+ if (isArrayOp())
+ return 1;
+ else
+ return 0;
+ }
+
+ // Returns the name of the encoding
+ static const char *getEncodingName(Encoding E) {
+ if (E > Encoding_MAX)
+ return "???";
+ return EncodingNameArray[E];
+ }
+
+ /// Prints out the abbreviation operator to the given stream.
+ void Print(raw_ostream &Stream) const;
+
+ /// isChar6 - Return true if this character is legal in the Char6 encoding.
+ static bool isChar6(char C) {
+ if (C >= 'a' && C <= 'z') return true;
+ if (C >= 'A' && C <= 'Z') return true;
+ if (C >= '0' && C <= '9') return true;
+ if (C == '.' || C == '_') return true;
+ return false;
+ }
+ static unsigned EncodeChar6(char C) {
+ if (C >= 'a' && C <= 'z') return C-'a';
+ if (C >= 'A' && C <= 'Z') return C-'A'+26;
+ if (C >= '0' && C <= '9') return C-'0'+26+26;
+ if (C == '.') return 62;
+ if (C == '_') return 63;
+ llvm_unreachable("Not a value Char6 character!");
+ }
+
+ static char DecodeChar6(unsigned V) {
+ assert((V & ~63) == 0 && "Not a Char6 encoded character!");
+ if (V < 26) return V+'a';
+ if (V < 26+26) return V-26+'A';
+ if (V < 26+26+10) return V-26-26+'0';
+ if (V == 62) return '.';
+ if (V == 63) return '_';
+ llvm_unreachable("Not a value Char6 character!");
+ }
+
+ /// \brief Compares this to Op. Returns <0 if this is less than Op,
+ /// Returns 0 if they are equal, and >0 if this is greater than Op.
+ int Compare(const NaClBitCodeAbbrevOp &Op) const {
+ // Compare encoding values.
+ int EncodingDiff = static_cast<int>(Enc) - static_cast<int>(Op.Enc);
+ if (EncodingDiff != 0) return EncodingDiff;
+
+ // Encodings don't differ, so now base on data associated with the
+ // encoding.
+ return ValCompare(Op);
+ }
+
+private:
+ Encoding Enc; // The encoding to use.
+ uint64_t Val; // Data associated with encoding (if any).
+
+ int ValCompare(const NaClBitCodeAbbrevOp &Op) const {
+ if (Val < Op.Val)
+ return -1;
+ else if (Val > Op.Val)
+ return 1;
+ else
+ return 0;
+ }
+ static const bool HasValueArray[];
+ static const char *EncodingNameArray[];
+};
+
+template <> struct isPodLike<NaClBitCodeAbbrevOp> {
+ static const bool value=true;
+};
+
+static inline bool operator<(const NaClBitCodeAbbrevOp &Op1,
+ const NaClBitCodeAbbrevOp &Op2) {
+ return Op1.Compare(Op2) < 0;
+}
+
+static inline bool operator<=(const NaClBitCodeAbbrevOp &Op1,
+ const NaClBitCodeAbbrevOp &Op2) {
+ return Op1.Compare(Op2) <= 0;
+}
+
+static inline bool operator==(const NaClBitCodeAbbrevOp &Op1,
+ const NaClBitCodeAbbrevOp &Op2) {
+ return Op1.Compare(Op2) == 0;
+}
+
+static inline bool operator!=(const NaClBitCodeAbbrevOp &Op1,
+ const NaClBitCodeAbbrevOp &Op2) {
+ return Op1.Compare(Op2) != 0;
+}
+
+static inline bool operator>=(const NaClBitCodeAbbrevOp &Op1,
+ const NaClBitCodeAbbrevOp &Op2) {
+ return Op1.Compare(Op2) >= 0;
+}
+
+static inline bool operator>(const NaClBitCodeAbbrevOp &Op1,
+ const NaClBitCodeAbbrevOp &Op2) {
+ return Op1.Compare(Op2) > 0;
+}
+
+/// NaClBitCodeAbbrev - This class represents an abbreviation record. An
+/// abbreviation allows a complex record that has redundancy to be stored in a
+/// specialized format instead of the fully-general, fully-vbr, format.
+class NaClBitCodeAbbrev {
+ SmallVector<NaClBitCodeAbbrevOp, 8> OperandList;
+ unsigned char RefCount; // Number of things using this.
+ ~NaClBitCodeAbbrev() {}
+public:
+ NaClBitCodeAbbrev() : RefCount(1) {}
+
+ void addRef() { ++RefCount; }
+ void dropRef() { if (--RefCount == 0) delete this; }
+
+ unsigned getNumOperandInfos() const {
+ return static_cast<unsigned>(OperandList.size());
+ }
+ const NaClBitCodeAbbrevOp &getOperandInfo(unsigned N) const {
+ return OperandList[N];
+ }
+
+ void Add(const NaClBitCodeAbbrevOp &OpInfo) {
+ OperandList.push_back(OpInfo);
+ }
+
+ // Returns a simplified version of the abbreviation. Used
+ // to recognize equivalent abbrevations.
+ NaClBitCodeAbbrev *Simplify() const;
+
+ // Returns true if the abbreviation is valid wrt to the bitcode reader.
+ bool isValid() const;
+
+ int Compare(const NaClBitCodeAbbrev &Abbrev) const {
+ // First order based on number of operands.
+ size_t OperandListSize = OperandList.size();
+ size_t AbbrevOperandListSize = Abbrev.OperandList.size();
+ if (OperandListSize < AbbrevOperandListSize)
+ return -1;
+ else if (OperandListSize > AbbrevOperandListSize)
+ return 1;
+
+ // Same number of operands, so compare element by element.
+ for (size_t I = 0; I < OperandListSize; ++I) {
+ if (int Diff = OperandList[I].Compare(Abbrev.OperandList[I]))
+ return Diff;
+ }
+ return 0;
+ }
+
+ // Returns true if all records matching the abbreviation must be
+ // of fixed length.
+ bool IsFixedSize() const {
+ unsigned Size = getNumOperandInfos();
+ if (Size < 2) return true;
+ return !OperandList[Size-2].isArrayOp();
+ }
+
+ // Returns the smallest record size that will match this
+ // abbreviation.
+ size_t GetMinRecordSize() const {
+ size_t Min = getNumOperandInfos();
+ if (!IsFixedSize()) Min -= 2;
+ return Min;
+ }
+
+ void Print(raw_ostream &Stream, bool AddNewline=true) const;
+
+ NaClBitCodeAbbrev *Copy() const {
+ NaClBitCodeAbbrev *AbbrevCopy = new NaClBitCodeAbbrev();
+ for (unsigned I = 0, IEnd = getNumOperandInfos();
+ I != IEnd; ++I) {
+ AbbrevCopy->Add(NaClBitCodeAbbrevOp(getOperandInfo(I)));
+ }
+ return AbbrevCopy;
+ }
+};
+
+static inline bool operator<(const NaClBitCodeAbbrev &A1,
+ const NaClBitCodeAbbrev &A2) {
+ return A1.Compare(A2) < 0;
+}
+
+static inline bool operator<=(const NaClBitCodeAbbrev &A1,
+ const NaClBitCodeAbbrev &A2) {
+ return A1.Compare(A2) <= 0;
+}
+static inline bool operator==(const NaClBitCodeAbbrev &A1,
+ const NaClBitCodeAbbrev &A2) {
+ return A1.Compare(A2) == 0;
+}
+
+static inline bool operator!=(const NaClBitCodeAbbrev &A1,
+ const NaClBitCodeAbbrev &A2) {
+ return A1.Compare(A2) != 0;
+}
+static inline bool operator>=(const NaClBitCodeAbbrev &A1,
+ const NaClBitCodeAbbrev &A2) {
+ return A1.Compare(A2) >= 0;
+}
+
+static inline bool operator>(const NaClBitCodeAbbrev &A1,
+ const NaClBitCodeAbbrev &A2) {
+ return A1.Compare(A2) > 0;
+}
+
+/// \brief Returns number of bits needed to encode
+/// value for dense FIXED encoding.
+inline unsigned NaClBitsNeededForValue(unsigned Value) {
+ // Note: Need to handle case where Value=0xFFFFFFFF as special case,
+ // since we can't add 1 to it.
+ if (Value >= 0x80000000) return 32;
+ return Log2_32_Ceil(Value+1);
+}
+
+/// \brief Encode a signed value by moving the sign to the LSB for dense
+/// VBR encoding.
+inline uint64_t NaClEncodeSignRotatedValue(int64_t V) {
+ return (V >= 0) ? (V << 1) : ((-V << 1) | 1);
+}
+
+/// \brief Decode a signed value stored with the sign bit in
+/// the LSB for dense VBR encoding.
+inline uint64_t NaClDecodeSignRotatedValue(uint64_t V) {
+ if ((V & 1) == 0)
+ return V >> 1;
+ if (V != 1)
+ return -(V >> 1);
+ // There is no such thing as -0 with integers. "-0" really means MININT.
+ return 1ULL << 63;
+}
+
+/// \brief This class determines whether a FIXED or VBR
+/// abbreviation should be used for the selector, and the number of bits
+/// needed to capture such selectors.
+class NaClBitcodeSelectorAbbrev {
+
+public:
+ // If true, use a FIXED abbreviation. Otherwise, use a VBR abbreviation.
+ bool IsFixed;
+ // Number of bits needed for selector.
+ unsigned NumBits;
+
+ // Creates a selector range for the given values.
+ NaClBitcodeSelectorAbbrev(bool IF, unsigned NB)
+ : IsFixed(IF), NumBits(NB) {}
+
+ // Creates a selector range when no abbreviations are defined.
+ NaClBitcodeSelectorAbbrev()
+ : IsFixed(true),
+ NumBits(NaClBitsNeededForValue(naclbitc::DEFAULT_MAX_ABBREV)) {}
+
+ // Creates a selector range to handle fixed abbrevations up to
+ // the specified value.
+ explicit NaClBitcodeSelectorAbbrev(unsigned MaxAbbrev)
+ : IsFixed(true),
+ NumBits(NaClBitsNeededForValue(MaxAbbrev)) {}
+};
+} // End llvm namespace
+
+#endif
diff --git a/pnacl-llvm/include/llvm/Bitcode/NaCl/NaClBitcodeDecoders.h b/pnacl-llvm/include/llvm/Bitcode/NaCl/NaClBitcodeDecoders.h
new file mode 100644
index 0000000..a3250e0
--- /dev/null
+++ b/pnacl-llvm/include/llvm/Bitcode/NaCl/NaClBitcodeDecoders.h
@@ -0,0 +1,74 @@
+//===- NaClBitcodeDecoders.h -------------------------------------*- C++ -*-===//
+// Functions used to decode values in PNaCl bitcode files.
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This header file provides a public API for value decoders defined in
+// the PNaCl bitcode reader.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_BITCODE_NACL_NACLBITCODEDECODERS_H
+#define LLVM_BITCODE_NACL_NACLBITCODEDECODERS_H
+
+#include "llvm/IR/CallingConv.h"
+#include "llvm/IR/GlobalValue.h"
+#include "llvm/IR/InstrTypes.h"
+#include "llvm/IR/Instruction.h"
+#include "llvm/Bitcode/NaCl/NaClLLVMBitCodes.h"
+
+namespace llvm {
+namespace naclbitc {
+
+/// Converts the NaCl (bitcode file) cast opcode to the corresponding
+/// LLVM cast opcode. Returns true if the conversion
+/// succeeds. Otherwise sets LLVMOpcode to Instruction::BitCast and
+/// returns false.
+bool DecodeCastOpcode(uint64_t NaClOpcode,
+ Instruction::CastOps &LLVMOpcode);
+
+/// Converts the NaCl (bitcode file) linkage type to the corresponding
+/// LLVM linkage type. Returns true if the conversion
+/// succeeds. Otherwise sets LLVMLinkage to
+/// GlobalValue::InternalLinkage and returns false.
+bool DecodeLinkage(uint64_t NaClLinkage,
+ GlobalValue::LinkageTypes &LLVMLinkage);
+
+/// Converts the NaCl (bitcode file) binary opcode to the
+/// corresponding LLVM binary opcode, assuming that the operator
+/// operates on OpType. Returns true if the conversion
+/// succeeds. Otherwise sets LLVMOpcode to Instruction::Add and
+/// returns false.
+bool DecodeBinaryOpcode(uint64_t NaClOpcode, Type *OpType,
+ Instruction::BinaryOps &LLVMOpcode);
+
+/// Converts the NaCl (bitcode file) calling convention value to the
+/// corresponding LLVM calling conventions. Returns true if the
+/// conversion succeeds. Otherwise sets LLVMCallingConv to
+/// CallingConv::C and returns false.
+bool DecodeCallingConv(uint64_t NaClCallingConv,
+ CallingConv::ID &LLVMCallingConv);
+
+/// Converts the NaCl (bitcode file) float comparison predicate to the
+/// corresponding LLVM float comparison predicate. Returns true if the
+/// conversion succeeds. Otherwise sets LLVMPredicate to
+/// CmpInst::FCMP_FALSE and returns false.
+bool DecodeFcmpPredicate(uint64_t NaClPredicate,
+ CmpInst::Predicate &LLVMPredicate);
+
+/// Converts the NaCl (bitcode file) integer comparison predicate to
+/// the corresponding LLVM integer comparison predicate. Returns true
+/// if the conversion succeeds. Otherwise sets LLVMPredicate to
+/// CmpInst::ICMP_EQ and returns false.
+bool DecodeIcmpPredicate(uint64_t NaClPredicate,
+ CmpInst::Predicate &LLVMPredicate);
+
+}
+}
+
+#endif
diff --git a/pnacl-llvm/include/llvm/Bitcode/NaCl/NaClBitcodeDefs.h b/pnacl-llvm/include/llvm/Bitcode/NaCl/NaClBitcodeDefs.h
new file mode 100644
index 0000000..bb1792f
--- /dev/null
+++ b/pnacl-llvm/include/llvm/Bitcode/NaCl/NaClBitcodeDefs.h
@@ -0,0 +1,53 @@
+//===- NaClBitcodeDefs.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines some common types/constants used by bitcode readers and
+// writers. It is intended to make clear assumptions made in
+// representing bitcode files.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_BITCODE_NACL_NACLBITCODEDEFS_H
+#define LLVM_BITCODE_NACL_NACLBITCODEDEFS_H
+
+namespace llvm {
+
+namespace naclbitc {
+
+// Special record codes used to model codes for predefined records.
+// They are very large so that they do not conflict with existing
+// record codes for user-defined blocks.
+enum SpecialBlockCodes {
+ BLK_CODE_ENTER = 65535,
+ BLK_CODE_EXIT = 65534,
+ BLK_CODE_DEFINE_ABBREV = 65533,
+ BLK_CODE_HEADER = 65532
+};
+
+} // end of namespace naclbitc
+
+/// Defines type for value indicies in bitcode. Like a size_t, but
+/// fixed across platforms.
+typedef uint32_t NaClBcIndexSize_t;
+
+/// Signed version of NaClBcIndexSize_t. Used to define relative indices.
+typedef int32_t NaClRelBcIndexSize_t;
+
+/// Defines maximum allowed bitcode index in bitcode files.
+static const size_t NaClBcIndexSize_t_Max =
+ std::numeric_limits<NaClBcIndexSize_t>::max();
+
+/// Defines the maximum number of initializers allowed, based on ILP32.
+static const size_t MaxNaClGlobalVarInits =
+ std::numeric_limits<uint32_t>::max();
+
+} // end of namespace llvm
+
+
+#endif // LLVM_BITCODE_NACL_NACLBITCODEDEFS_H
diff --git a/pnacl-llvm/include/llvm/Bitcode/NaCl/NaClBitcodeHeader.h b/pnacl-llvm/include/llvm/Bitcode/NaCl/NaClBitcodeHeader.h
new file mode 100644
index 0000000..50ca5aa
--- /dev/null
+++ b/pnacl-llvm/include/llvm/Bitcode/NaCl/NaClBitcodeHeader.h
@@ -0,0 +1,263 @@
+//===-- llvm/Bitcode/NaCl/NaClBitcodeHeader.h - ----------------*- C++ -*-===//
+// NaCl Bitcode header reader.
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This header defines interfaces to read and write NaCl bitcode wire format
+// file headers.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_BITCODE_NACL_NACLBITCODEHEADER_H
+#define LLVM_BITCODE_NACL_NACLBITCODEHEADER_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/DataTypes.h"
+#include <string>
+#include <vector>
+
+namespace llvm {
+class MemoryObject;
+
+// Class representing a variable-size metadata field in the bitcode header.
+// Also contains the list of known (typed) Tag IDs.
+//
+// The serialized format has 2 fixed subfields (ID:type and data length) and the
+// variable-length data subfield
+class NaClBitcodeHeaderField {
+ NaClBitcodeHeaderField(const NaClBitcodeHeaderField &) = delete;
+ void operator=(const NaClBitcodeHeaderField &) = delete;
+
+public:
+ // Defines the ID associated with the value. Valid values are in
+ // {0x0, ..., 0xFFF}
+ typedef enum {
+ kInvalid = 0, // KUnknownType.
+ kPNaClVersion = 1, // kUint32Type.
+ kAlignBitcodeRecords = 2, // kFlagType.
+ kTag_MAX = kAlignBitcodeRecords
+ } Tag;
+ // Defines the type of value.
+ typedef enum {
+ kBufferType, // Buffer of form uint8_t[len].
+ kUInt32Type,
+ kFlagType,
+ kUnknownType,
+ kFieldType_MAX = kUnknownType
+ } FieldType;
+ // Defines the number of bytes in a (32-bit) word.
+ static const int WordSize = 4;
+
+ // Defines the encoding of the fixed fields {i.e. ID:type and data length).
+ typedef uint16_t FixedSubfield;
+
+ // Create an invalid header field.
+ NaClBitcodeHeaderField();
+
+ // Creates a header field where MyID is a flag.
+ NaClBitcodeHeaderField(Tag MyID);
+
+ // Create a header field with an uint32_t value.
+ NaClBitcodeHeaderField(Tag MyID, uint32_t value);
+
+ // Create a header field for the given data.
+ NaClBitcodeHeaderField(Tag MyID, size_t MyLen, uint8_t *MyData);
+
+ virtual ~NaClBitcodeHeaderField() {
+ if (Data)
+ delete[] Data;
+ }
+
+ /// \brief Number of bytes used to represent header field.
+ size_t GetTotalSize() const {
+ // Round up to 4 byte alignment
+ return (kTagLenSize + Len + (WordSize - 1)) & ~(WordSize - 1);
+ }
+
+ /// \brief Write field into Buf[BufLen].
+ bool Write(uint8_t *Buf, size_t BufLen) const;
+
+ /// \brief Read field from Buf[BufLen].
+ bool Read(const uint8_t *Buf, size_t BufLen);
+
+ /// \brief Returns string describing ID of field.
+ static const char *IDName(Tag ID);
+ const char *IDName() const {
+ return IDName(ID);
+ }
+
+ /// \brief Returns string describing type of field.
+ static const char *TypeName(FieldType FType);
+ const char *TypeName() const {
+ return TypeName(FType);
+ }
+
+ /// \brief Returns string describing field.
+ std::string Contents() const;
+
+ /// \brief Get the data size from a serialized field to allow allocation.
+ static size_t GetDataSizeFromSerialized(const uint8_t *Buf) {
+ FixedSubfield Length;
+ ReadFixedSubfield(&Length, Buf + sizeof(FixedSubfield));
+ return Length;
+ }
+
+ /// \brief Return the ID of the field.
+ Tag GetID() const { return ID; }
+
+ FieldType GetType() const { return FType; }
+
+ /// \brief Return the length of the data (in bytes).
+ size_t GetLen() const { return Len; }
+
+ /// \brief Return the data. Data is array getData()[getLen()].
+ const uint8_t *GetData() const { return Data; }
+
+ /// \brief Returns the uint32_t value stored. Requires that
+ /// getType() == kUint32Type
+ uint32_t GetUInt32Value() const;
+
+private:
+ // Convert ID:Type into a fixed subfield
+ FixedSubfield EncodeTypedID() const { return (ID << 4) | FType; }
+ // Extract out ID and Type from a fixed subfield.
+ void DecodeTypedID(FixedSubfield Subfield, Tag &ID, FieldType &FType) {
+ FixedSubfield PossibleID = Subfield >> 4;
+ ID = (PossibleID > kTag_MAX ? kInvalid : static_cast<Tag>(PossibleID));
+ FixedSubfield PossibleFType = Subfield & 0xF;
+ FType = (PossibleFType > kFieldType_MAX
+ ? kUnknownType : static_cast<FieldType>(PossibleFType));
+ }
+ // Combined size of the fixed subfields
+ const static size_t kTagLenSize = 2 * sizeof(FixedSubfield);
+ static void WriteFixedSubfield(FixedSubfield Value, uint8_t *Buf) {
+ Buf[0] = Value & 0xFF;
+ Buf[1] = (Value >> 8) & 0xFF;
+ }
+ static void ReadFixedSubfield(FixedSubfield *Value, const uint8_t *Buf) {
+ *Value = Buf[0] | Buf[1] << 8;
+ }
+ Tag ID;
+ FieldType FType;
+ size_t Len;
+ uint8_t *Data;
+};
+
+/// \brief Class holding parsed header fields in PNaCl bitcode file.
+class NaClBitcodeHeader {
+ NaClBitcodeHeader(const NaClBitcodeHeader &) = delete;
+ void operator=(const NaClBitcodeHeader &) = delete;
+
+ // The set of parsed header fields. The header takes ownership of
+ // all fields in this vector.
+ std::vector<NaClBitcodeHeaderField *> Fields;
+ // The number of bytes in the PNaCl header.
+ size_t HeaderSize;
+ // String defining why it is unsupported (if unsupported).
+ std::string UnsupportedMessage;
+ // Flag defining if header is supported.
+ bool IsSupportedFlag;
+ // Flag defining if the corresponding bitcode file is readable.
+ bool IsReadableFlag;
+ // Defines the PNaCl version defined by the header file.
+ uint32_t PNaClVersion;
+ // Byte align bitcode records when nonzero.
+ bool AlignBitcodeRecords = false;
+
+public:
+ static const int WordSize = NaClBitcodeHeaderField::WordSize;
+
+ NaClBitcodeHeader();
+ ~NaClBitcodeHeader();
+
+ /// \brief Installs the fields of the header, defining if the header
+ /// is readable and supported. Sets UnsupportedMessage on failure.
+ void InstallFields();
+
+ /// \brief Adds a field to the list of fields in a header. Takes ownership
+ /// of fields added.
+ void push_back(NaClBitcodeHeaderField *Field) {
+ Fields.push_back(Field);
+ }
+
+ /// \brief Read the PNaCl bitcode header, The format of the header is:
+ ///
+ /// 1) 'PEXE' - The four character sequence defining the magic number.
+ /// 2) uint_16 num_fields - The number of NaClBitcodeHeaderField's.
+ /// 3) uint_16 num_bytes - The number of bytes to hold fields in
+ /// the header.
+ /// 4) NaClBitcodeHeaderField f1 - The first bitcode header field.
+ /// ...
+ /// 2 + num_fields) NaClBitcodeHeaderField fn - The last bitcode header
+ /// field.
+ ///
+ /// Returns false if able to read (all of) the bitcode header.
+ bool Read(const unsigned char *BufPtr, const unsigned char *BufEnd);
+
+ // \brief Read the PNaCl bitcode header, recording the fields found
+ // in the header. Returns false if able to read (all of) the bitcode header.
+ bool Read(MemoryObject *Bytes);
+
+ // \brief Returns the number of bytes read to consume the header.
+ size_t getHeaderSize() { return HeaderSize; }
+
+ /// \brief Returns string describing why the header describes
+ /// an unsupported PNaCl Bitcode file.
+ const std::string &Unsupported() const { return UnsupportedMessage; }
+
+ /// \brief Returns true if supported. That is, it can be run in the
+ /// browser.
+ bool IsSupported() const { return IsSupportedFlag; }
+
+ /// \brief Returns true if the bitcode file should be readable. Note
+ /// that just because it is readable, it doesn't necessarily mean that
+ /// it is supported.
+ bool IsReadable() const { return IsReadableFlag; }
+
+ /// \brief Returns number of fields defined.
+ size_t NumberFields() const { return Fields.size(); }
+
+ /// \brief Returns a pointer to the field with the given ID
+ /// (0 if no such field).
+ NaClBitcodeHeaderField *GetTaggedField(NaClBitcodeHeaderField::Tag ID) const;
+
+ /// \brief Returns a pointer to the Nth field in the header
+ /// (0 if no such field).
+ NaClBitcodeHeaderField *GetField(size_t index) const;
+
+ /// \brief Returns the PNaClVersion, as defined by the header.
+ uint32_t GetPNaClVersion() const { return PNaClVersion; }
+
+ /// \brief Returns if one should byte align bitcode records.
+ bool getAlignBitcodeRecords() const { return AlignBitcodeRecords; }
+
+private:
+ // Reads and verifies the first 8 bytes of the header, consisting
+ // of the magic number 'PEXE', and the value defining the number
+ // of fields and number of bytes used to hold fields.
+ // Returns false if successful, sets UnsupportedMessage otherwise.
+ bool ReadPrefix(const unsigned char *BufPtr, const unsigned char *BufEnd,
+ unsigned &NumFields, unsigned &NumBytes);
+
+ // Reads and verifies the fields in the header.
+ // Returns false if successful, sets UnsupportedMessage otherwise.
+ bool ReadFields(const unsigned char *BufPtr, const unsigned char *BufEnd,
+ unsigned NumFields, unsigned NumBytes);
+
+ // Sets the Unsupported error message and returns true.
+ bool UnsupportedError(StringRef Message) {
+ UnsupportedMessage = Message.str();
+ return true;
+ }
+
+};
+
+} // namespace llvm
+
+#endif
diff --git a/pnacl-llvm/include/llvm/Bitcode/NaCl/NaClBitcodeParser.h b/pnacl-llvm/include/llvm/Bitcode/NaCl/NaClBitcodeParser.h
new file mode 100644
index 0000000..e48aebd
--- /dev/null
+++ b/pnacl-llvm/include/llvm/Bitcode/NaCl/NaClBitcodeParser.h
@@ -0,0 +1,663 @@
+//===- NaClBitcodeParser.h -----------------------------------*- C++ -*-===//
+// Low-level bitcode driver to parse PNaCl bitcode files.
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Parses and processes low-level PNaCl bitcode files. Defines class
+// NaClBitcodeParser.
+//
+// The concepts of PNaCl bitcode files are basically the same as for
+// LLVM bitcode files (see http://llvm.org/docs/BitCodeFormat.html for
+// details).
+//
+// The bitstream format is an abstract encoding of structured data,
+// very similar to XML in some ways. Like XML, bitstream files contain
+// tags, and nested structures, and you can parse the file without
+// having to understand the tags. Unlike XML, the bitstream format is
+// a binary encoding, and provides a mechanism for the file to
+// self-describe "abbreviations". Abbreviations are effectively size
+// optimizations for the content.
+//
+// The bitcode file is conceptually a sequence of "blocks", defining
+// the content. Blocks contain a sequence of records and
+// blocks. Nested content is defined using nested blocks. A (data)
+// "record" is a tag, and a vector of (unsigned integer) values.
+//
+// Blocks are identified using Block IDs. Each kind of block has a
+// unique block "ID". Records have two elements:
+//
+// a) A "code" identifying what type of record it is.
+// b) A vector of "values" defining the contents of the record.
+//
+// The bitstream "reader" (defined in NaClBitstreamReader.h) defines
+// the implementation that converts the low-level bit file into
+// records and blocks. The bit stream is processed by moving a
+// "cursor" over the sequence of bits.
+//
+// The bitstream reader assumes that each block/record is read in by
+// first reading the "entry". The entry defines whether it corresponds
+// to one of the following:
+//
+// a) At the beginning of a (possibly nested) block
+// b) At the end of the current block.
+// c) The input defines an abberviation.
+// d) The input defines a record.
+//
+// An entry contains two values, a "kind" and an "ID". The kind
+// defines which of the four cases above occurs. The ID provides
+// identifying information on how to further process the input. For
+// case (a), the ID is the identifier associated with the the block
+// being processed. For case (b) and (c) the ID is ignored. For case
+// (d) the ID identifies the abbreviation that should be used to parse
+// the values.
+//
+// The class NaClBitcodeParser defines a bitcode parser that extracts
+// the blocks and records, which are then processed using virtual
+// callbacks. In general, you will want to implement derived classes
+// for each type of block, so that the corresponding data is processed
+// appropriately.
+//
+// The class NaClBitcodeParser parses a bitcode block, and defines a
+// set of callbacks for that block, including:
+//
+// a) EnterBlock: What to do once we have entered the block.
+// b) ProcessRecord: What to do with each parsed record.
+// c) ParseBlock: Parse the (nested) block with the given ID.
+// d) ExitBlock: What to do once we have finished processing the block.
+//
+// Note that a separate instance of NaClBitcodeParser (or a
+// corresponding derived class) is created for each nested block. Each
+// instance is responsible for only parsing a single block. Method
+// ParseBlock creates new instances to parse nested blocks. Method
+// GetEnclosingParser() can be used to refer to the parser associated
+// with the enclosing block.
+//
+// Currently, the default processing of abbreviations is handled by
+// the PNaCl bitstream reader, rather than by the parser.
+//
+// If you need to process abbreviations processed by the PNaCl
+// bitstream reader, you must explicitly define a
+// NaClBitcodeParserListener to listen (within the bitstream reader),
+// and make appropriate call backs to the NaClBitcodeParser.
+// The listener is glued to parsers using method SetListener.
+//
+// TODO(kschimpf): Define an intermediate derived class of
+// NaClBitcodeParser that defines callbacks based on the actual
+// structure of PNaCl bitcode files. That is, it has callbacks for
+// each of the types of blocks (i.e. module, types, global variables,
+// function, symbol tables etc). This derivied class can then be used
+// as the base class for the bitcode reader.
+// ===----------------------------------------------------------------------===//
+
+#ifndef LLVM_BITCODE_NACL_NACLBITCODEPARSER_H
+#define LLVM_BITCODE_NACL_NACLBITCODEPARSER_H
+
+#include "llvm/Bitcode/NaCl/NaClBitstreamReader.h"
+#include "llvm/Bitcode/NaCl/NaClBitcodeDefs.h"
+#include "llvm/Support/raw_ostream.h"
+#include <vector>
+
+namespace llvm {
+
+class NaClBitcodeRecord;
+class NaClBitcodeParser;
+class NaClBitcodeParserListener;
+
+// Defines the base class for data extracted from the input bitstream
+// (i.e blocks and records).
+class NaClBitcodeData {
+ void operator=(const NaClBitcodeData&) = delete;
+
+public:
+ /// Create data element to be read from input cursor.
+ explicit NaClBitcodeData(NaClBitstreamCursor &Cursor)
+ : Cursor(Cursor), StartBit(Cursor.GetCurrentBitNo())
+ {}
+
+ /// Create copy of the given data element.
+ explicit NaClBitcodeData(const NaClBitcodeData &Data)
+ : Cursor(Data.Cursor), StartBit(Data.StartBit)
+ {}
+
+ /// Returns the bitstream reader being used.
+ NaClBitstreamReader &GetReader() const {
+ return *Cursor.getBitStreamReader();
+ }
+
+ /// Returns the cursor position within the bitstream.
+ NaClBitstreamCursor &GetCursor() const {
+ return Cursor;
+ }
+
+ /// Returns the number of bits defined by the data.
+ uint64_t GetNumBits() const {
+ return GetCursor().GetCurrentBitNo() - StartBit;
+ }
+
+ /// Returns the first bit of the stream data.
+ uint64_t GetStartBit() const {
+ return StartBit;
+ }
+
+protected:
+ /// Change the start bit for the data to the new value.
+ void SetStartBit(uint64_t NewValue) {
+ StartBit = NewValue;
+ }
+
+private:
+ // The bitstream cursor defining location within the bitcode file.
+ NaClBitstreamCursor &Cursor;
+
+ // Start bit for the record.
+ uint64_t StartBit;
+};
+
+/// Models the block defined by a (begin) block record, through the
+/// (end) block record.
+class NaClBitcodeBlock : public NaClBitcodeData {
+ NaClBitcodeBlock(const NaClBitcodeBlock &) = delete;
+ void operator=(const NaClBitcodeBlock &) = delete;
+
+public:
+ /// Given the found (begin) block record for block BlockID, create
+ /// the corresponding data associated with that block.
+ NaClBitcodeBlock(unsigned BlockID, const NaClBitcodeRecord &Record);
+
+ /// Create block data for block BlockID, using the input cursor.
+ NaClBitcodeBlock(unsigned BlockID, NaClBitstreamCursor &Cursor)
+ : NaClBitcodeData(Cursor),
+ BlockID(BlockID),
+ EnclosingBlock(0)
+ {
+ LocalStartBit = GetStartBit();
+ }
+
+ /// Print the contents out to the given stream.
+ void Print(raw_ostream& os) const;
+
+ /// Returns pointer to the enclosing block.
+ const NaClBitcodeBlock *GetEnclosingBlock() const {
+ return EnclosingBlock;
+ }
+
+ /// Returns the block ID of the block.
+ unsigned GetBlockID() const {
+ return BlockID;
+ }
+
+ /// Returns the number of bits in the block associated with the
+ /// bitcode parser parsing this block, excluding nested blocks.
+ unsigned GetLocalNumBits() const {
+ return GetCursor().GetCurrentBitNo() - LocalStartBit;
+ }
+
+protected:
+ // The block ID associated with this record.
+ unsigned BlockID;
+ // The enclosing block, if defined.
+ const NaClBitcodeBlock *EnclosingBlock;
+ // Start bit for the block, updated to skip nested blocks.
+ uint64_t LocalStartBit;
+
+ // Note: We friend class NaClBitcodeParser, so that it can
+ // update field LocalStartBit.
+ friend class NaClBitcodeParser;
+};
+
+typedef NaClBitcodeRecordVector NaClRecordVector;
+
+class NaClBitcodeRecordData {
+ NaClBitcodeRecordData &operator=(const NaClBitcodeRecordData &) = delete;
+public:
+ NaClBitcodeRecordData(unsigned Code, const NaClRecordVector &Values)
+ : Code(Code), Values(Values) {}
+ explicit NaClBitcodeRecordData(const NaClBitcodeRecordData &Record)
+ : Code(Record.Code), Values(Record.Values) {}
+ NaClBitcodeRecordData() : Code(0) {}
+ // The selector code associated with the record.
+ unsigned Code;
+ // The sequence of values defining the parsed record.
+ NaClRecordVector Values;
+
+ void Print(raw_ostream &strm) const;
+};
+
+inline raw_ostream &operator<<(raw_ostream &Strm,
+ const NaClBitcodeRecordData &Data) {
+ Data.Print(Strm);
+ return Strm;
+}
+
+/// Simple container class to convert the values of the corresponding
+/// read record to a simpler form, only containing values.
+struct NaClBitcodeValues {
+public:
+ NaClBitcodeValues(const NaClBitcodeRecordData &Record)
+ : Record(Record) {}
+
+ size_t size() const {
+ return Record.Values.size()+1;
+ }
+
+ uint64_t operator[](size_t index) const {
+ return index == 0 ? Record.Code : Record.Values[index-1];
+ }
+
+private:
+ const NaClBitcodeRecordData &Record;
+};
+
+/// Defines the data associated with reading a block record in the
+/// PNaCl bitcode stream.
+class NaClBitcodeRecord : public NaClBitcodeData {
+public:
+ /// Type for vector of values representing a record.
+ typedef NaClRecordVector RecordVector;
+
+ /// Creates a bitcode record, starting at the position defined
+ /// by cursor.
+ explicit NaClBitcodeRecord(const NaClBitcodeBlock &Block)
+ : NaClBitcodeData(Block.GetCursor()),
+ Block(Block)
+ {}
+
+ /// Print the contents out to the given stream.
+ void Print(raw_ostream& os) const;
+
+ /// The block the record appears in.
+ const NaClBitcodeBlock &GetBlock() const {
+ return Block;
+ }
+
+ /// Returns the block ID associated with the record.
+ unsigned GetBlockID() const {
+ return Block.GetBlockID();
+ }
+
+ /// Returns the kind of entry read from the input stream.
+ unsigned GetEntryKind() const {
+ return Entry.Kind;
+ }
+
+ /// Returns the code value (i.e. selector) associated with the
+ /// record.
+ unsigned GetCode() const {
+ return Data.Code;
+ }
+
+ /// Returns the EntryID (e.g. abbreviation if !=
+ /// naclbitc::UNABBREV_RECORD) associated with the record. Note:
+ /// for block-enter, block-exit, and define-abbreviation, EntryID is
+ /// not the corresponding abbreviation.
+ unsigned GetEntryID() const {
+ return Entry.ID;
+ }
+
+ /// Returns the (value) record associated with the read record.
+ const RecordVector &GetValues() const {
+ return Data.Values;
+ }
+
+ /// Allows lower level access to data representing record.
+ const NaClBitcodeRecordData &GetRecordData() const {
+ return Data;
+ }
+
+ /// Returns true if the record was read using an abbreviation.
+ bool UsedAnAbbreviation() const {
+ return GetEntryKind() == NaClBitstreamEntry::Record &&
+ GetEntryID() != naclbitc::UNABBREV_RECORD;
+ }
+
+ /// Returns the abbrevation index used to read the record.
+ /// Returns naclbitc::UNABBREV_RECORD if not applicable.
+ unsigned GetAbbreviationIndex() const {
+ return UsedAnAbbreviation()
+ ? GetEntryID() : static_cast<unsigned>(naclbitc::UNABBREV_RECORD);
+ }
+
+ /// Destructively change the abbreviation ID to the given value.
+ void SetAbbreviationIndex(unsigned Index) {
+ Entry.ID = Index;
+ }
+
+protected:
+ // The block associated with the record.
+ const NaClBitcodeBlock &Block;
+ // The data of the record.
+ NaClBitcodeRecordData Data;
+ // The entry (i.e. value(s) preceding the record that define what
+ // value comes next).
+ NaClBitstreamEntry Entry;
+
+private:
+ // Allows class NaClBitcodeParser to read values into the
+ // record, thereby hiding the details of how to read values.
+ friend class NaClBitcodeParser;
+ friend class NaClBitcodeParserListener;
+
+ /// Read bitstream entry. Defines what construct appears next in the
+ /// bitstream.
+ void ReadEntry() {
+ SetStartBit(GetCursor().GetCurrentBitNo());
+ Entry = GetCursor().
+ advance(NaClBitstreamCursor::AF_DontAutoprocessAbbrevs, 0);
+ }
+
+ /// Reads in a record's values, if the entry defines a record (Must
+ /// be called after ReadEntry).
+ void ReadValues() {
+ Data.Values.clear();
+ Data.Code = GetCursor().readRecord(Entry.ID, Data.Values);
+ }
+
+ NaClBitcodeRecord(const NaClBitcodeRecord &Rcd) = delete;
+ void operator=(const NaClBitcodeRecord &Rcd) = delete;
+};
+
+inline raw_ostream &operator<<(raw_ostream &Strm,
+ const NaClBitcodeRecord &Record) {
+ Record.Print(Strm);
+ return Strm;
+}
+
+/// Defines a listener to handle abbreviations within a bitcode file.
+/// In particular, abbreviations and the BlockInfo block are made more
+/// explicit, and then sent to the parser through virtuals
+/// ProcessAbbreviation and SetBID.
+class NaClBitcodeParserListener : public NaClAbbrevListener {
+ friend class NaClBitcodeParser;
+public:
+ // Constructs a listener for the given parser. Note: All nested
+ // parsers automatically inherit this listener.
+ NaClBitcodeParserListener(NaClBitcodeParser *Parser)
+ : Parser(Parser), GlobalBlockID(naclbitc::BLOCKINFO_BLOCK_ID) {
+ }
+
+ virtual ~NaClBitcodeParserListener() {}
+
+private:
+ virtual void BeginBlockInfoBlock(unsigned NumWords);
+
+ virtual void SetBID();
+
+ virtual void EndBlockInfoBlock();
+
+ virtual void ProcessAbbreviation(NaClBitCodeAbbrev *Abbrev,
+ bool IsLocal);
+
+ /// The block parser currently being listened to.
+ NaClBitcodeParser *Parser;
+
+ /// The block ID to use if a global abbreviation. Note: This field is
+ /// updated by calls to method SetBID.
+ unsigned GlobalBlockID;
+};
+
+/// Parses a block in the PNaCl bitcode stream.
+class NaClBitcodeParser {
+ // Allow listener privledges, so that it can update/call the parser
+ // using a clean API.
+ friend class NaClBitcodeParserListener;
+
+ // Implements an error handler for errors in the bitstream reader.
+ // Redirects bitstream reader errors to corresponding parrser error
+ // reporting function.
+ class ErrorHandler : public NaClBitstreamCursor::ErrorHandler {
+ NaClBitcodeParser *Parser;
+ public:
+ ErrorHandler(NaClBitcodeParser *Parser,
+ NaClBitstreamCursor &Cursor):
+ NaClBitstreamCursor::ErrorHandler(Cursor), Parser(Parser) {}
+ LLVM_ATTRIBUTE_NORETURN
+ void Fatal(const std::string &ErrorMessage) const final {
+ Parser->FatalAt(getCurrentBitNo(), ErrorMessage);
+ llvm_unreachable("GCC treats noreturn virtual functions as returning");
+ }
+ ~ErrorHandler() override {}
+ };
+
+public:
+ // Creates a parser to parse the the block at the given cursor in
+ // the PNaCl bitcode stream. This instance is a "dummy" instance
+ // that starts the parser.
+ explicit NaClBitcodeParser(NaClBitstreamCursor &Cursor)
+ : EnclosingParser(0),
+ Block(ILLEGAL_BLOCK_ID, Cursor),
+ Record(Block),
+ Listener(0),
+ ErrStream(&errs()) {
+ std::unique_ptr<NaClBitstreamCursor::ErrorHandler>
+ ErrHandler(new ErrorHandler(this, Cursor));
+ Cursor.setErrorHandler(ErrHandler);
+ }
+
+ virtual ~NaClBitcodeParser();
+
+ /// Reads the (top-level) block associated with the given block
+ /// record at the stream cursor. Returns true if unable to parse.
+ /// Can be called multiple times to parse multiple blocks.
+ bool Parse();
+
+ // Called once the bitstream reader has entered the corresponding
+ // subblock. Argument NumWords is set to the number of words in the
+ // corresponding subblock.
+ virtual void EnterBlock(unsigned /*NumWords*/) {}
+
+ // Called when the corresponding EndBlock of the block being parsed
+ // is found.
+ virtual void ExitBlock() {}
+
+ // Called after each record (within the block) is read (into field Record).
+ virtual void ProcessRecord() {}
+
+ // Called if a SetBID record is encountered in the BlockInfo block,
+ // and the parser has a listener.
+ virtual void SetBID() {}
+
+ // Called to process an abbreviation if the parser has a listener.
+ virtual void ProcessAbbreviation(unsigned /*BlockID*/,
+ NaClBitCodeAbbrev * /*Abbrev*/,
+ bool /*IsLocal*/) {}
+
+ // Creates an instance of the NaClBitcodeParser to use to parse the
+ // block with the given block ID, and then call's method
+ // ParseThisBlock() to parse the corresponding block. Note:
+ // Each derived class should define it's own version of this
+ // method, following the pattern below.
+ virtual bool ParseBlock(unsigned BlockID) {
+ // Default implementation just builds a parser that does nothing.
+ NaClBitcodeParser Parser(BlockID, this);
+ return Parser.ParseThisBlock();
+ }
+
+ // Changes the stream to print errors to, and returns the old error stream.
+ // There are two use cases:
+ // 1) To change (from the default errs()) inside the constructor of the
+ // derived class. In this context, it will be used for all error
+ // messages for the derived class.
+ // 2) Temporarily modify it for a single error message.
+ raw_ostream &setErrStream(raw_ostream &Stream) {
+ raw_ostream &OldErrStream = *ErrStream;
+ ErrStream = &Stream;
+ return OldErrStream;
+ }
+
+ // Called when an error occurs. BitPosition is the bit position the
+ // error was found, and Message is the error to report. Always
+ // returns true (the error return value of Parse). Level is
+ // the severity of the error.
+ virtual bool ErrorAt(naclbitc::ErrorLevel Level, uint64_t BitPosition,
+ const std::string &Message);
+
+ bool ErrorAt(uint64_t BitPosition, const std::string &Message) {
+ return ErrorAt(naclbitc::Error, BitPosition, Message);
+ }
+
+ // Called when an error occurs. Message is the error to
+ // report. Always returns true (the error return value of Parse).
+ bool Error(const std::string &Message) {
+ return ErrorAt(Record.GetStartBit(), Message);
+ }
+
+ // Called when a fatal error occurs. BitPosition is the bit position
+ // the error was found, and Message is the error to report. Does not
+ // return.
+ LLVM_ATTRIBUTE_NORETURN
+ void FatalAt(uint64_t BitPosition, const std::string &Message) {
+ ErrorAt(naclbitc::Fatal, BitPosition, Message);
+ llvm_unreachable("Fatal errors should not return");
+ }
+
+ // Called when a fatal error occurs. Message is the error to
+ // report. Does not return.
+ LLVM_ATTRIBUTE_NORETURN
+ void Fatal(const std::string &Message) {
+ FatalAt(Record.GetStartBit(), Message);
+ llvm_unreachable("GCC treats noreturn virtual functions as returning");
+ }
+
+ // Generates fatal generic error message.
+ LLVM_ATTRIBUTE_NORETURN
+ void Fatal() {
+ Fatal("Fatal error occurred!");
+ }
+
+ // Returns the number of bits in this block, including nested blocks.
+ unsigned GetBlockNumBits() const {
+ return Block.GetNumBits();
+ }
+
+ // Returns the number of bits in this block, excluding nested blocks.
+ unsigned GetBlockLocalNumBits() const {
+ return Block.GetLocalNumBits();
+ }
+
+ /// Returns the block ID associated with the Parser.
+ unsigned GetBlockID() const {
+ return Block.GetBlockID();
+ }
+
+ NaClBitcodeBlock &GetBlock() {
+ return Block;
+ }
+
+ /// Returns the enclosing parser of this block.
+ NaClBitcodeParser *GetEnclosingParser() const {
+ // Note: The top-level parser instance is a dummy instance
+ // and is not considered an enclosing parser.
+ return EnclosingParser->EnclosingParser ? EnclosingParser : 0;
+ }
+
+ // Parses the block using the parser defined by
+ // ParseBlock(unsigned). Returns true if unable to parse the
+ // block. Note: Should only be called by virtual ParseBlock(unsigned).
+ bool ParseThisBlock() {
+ bool Results;
+ if (Listener) {
+ NaClBitcodeParser *CallingParser = Listener->Parser;
+ Listener->Parser = this;
+ Results = ParseThisBlockInternal();
+ Listener->Parser = CallingParser;
+ } else {
+ Results = ParseThisBlockInternal();
+ }
+ return Results;
+ }
+
+ /// Skips the current block, assuming the parser is at the beginning
+ /// of the block. That is, Record.GetEntryKind() equals
+ /// NaClBitstreamEntry::SubBlock. Returns false if
+ /// successful. Otherwise returns 1.
+ bool SkipBlock() {
+ if (Record.GetEntryKind() != NaClBitstreamEntry::SubBlock)
+ return Error("SkipBlock on non-block record");
+ return Record.GetCursor().SkipBlock();
+ }
+
+protected:
+ // The containing parser.
+ NaClBitcodeParser *EnclosingParser;
+
+ // The block the parser is associated with.
+ NaClBitcodeBlock Block;
+
+ // The current record (within the block) being processed.
+ NaClBitcodeRecord Record;
+
+ // The listener (if any) to use.
+ NaClBitcodeParserListener *Listener;
+
+ // The error stream to use if non-null (uses errs() if null).
+ raw_ostream *ErrStream;
+
+ // Creates a block parser to parse the block associated with the bitcode entry
+ // that defines the beginning of a block. This instance actually parses the
+ // corresponding block. Inherits the bitstream cursor from the
+ // EnclosingParser.
+ NaClBitcodeParser(unsigned BlockID, NaClBitcodeParser *EnclosingParser)
+ : EnclosingParser(EnclosingParser),
+ Block(BlockID, EnclosingParser->Record),
+ Record(Block),
+ Listener(EnclosingParser->Listener),
+ ErrStream(EnclosingParser->ErrStream)
+ {}
+
+ // Same as above, but use the supplied bitstream cursor (instead of
+ // inheriting from the enclosing parser). This constructor allows
+ // parallel parsing of subblocks, by allowing the caller to generate
+ // a different Cursor for each block to be parsed in parallel.
+ NaClBitcodeParser(unsigned BlockID, NaClBitcodeParser *EnclosingParser,
+ NaClBitstreamCursor &Cursor)
+ : EnclosingParser(EnclosingParser),
+ Block(BlockID, Cursor),
+ Record(Block),
+ Listener(EnclosingParser->Listener),
+ ErrStream(EnclosingParser->ErrStream)
+ {}
+
+ /// Defines the listener for this block, and all enclosing blocks,
+ /// to be the given listener. Should be set in the constructor.
+ void SetListener(NaClBitcodeParserListener* UseListener) {
+ Listener = UseListener;
+ }
+
+private:
+ // Special constant identifying the top-level instance.
+ static const unsigned ILLEGAL_BLOCK_ID = UINT_MAX;
+
+ // Parses the block. Returns true if unable to parse the
+ // block. Note: Should only be called by virtual ParseThisBlock.
+ bool ParseThisBlockInternal() {
+ bool Results;
+ if (GetBlockID() == naclbitc::BLOCKINFO_BLOCK_ID) {
+ Results = ParseBlockInfoInternal();
+ } else {
+ Results = ParseBlockInternal();
+ ExitBlock();
+ }
+ return Results;
+ }
+
+ // Parses a BlockInfo block, where processing is handled through
+ // a listener in the bitstream reader.
+ bool ParseBlockInfoInternal();
+
+ // Parses the non-BlockInfo block. Returns true if unable to parse the
+ // block.
+ bool ParseBlockInternal();
+
+ void operator=(const NaClBitcodeParser &Parser) = delete;
+ NaClBitcodeParser(const NaClBitcodeParser &Parser) = delete;
+
+};
+
+} // namespace llvm
+
+#endif
diff --git a/pnacl-llvm/include/llvm/Bitcode/NaCl/NaClBitstreamReader.h b/pnacl-llvm/include/llvm/Bitcode/NaCl/NaClBitstreamReader.h
new file mode 100644
index 0000000..6e4da3c
--- /dev/null
+++ b/pnacl-llvm/include/llvm/Bitcode/NaCl/NaClBitstreamReader.h
@@ -0,0 +1,911 @@
+//===- NaClBitstreamReader.h -----------------------------------*- C++ -*-===//
+// Low-level bitstream reader interface
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This header defines the BitstreamReader class. This class can be used to
+// read an arbitrary bitstream, regardless of its contents.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_BITCODE_NACL_NACLBITSTREAMREADER_H
+#define LLVM_BITCODE_NACL_NACLBITSTREAMREADER_H
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Bitcode/NaCl/NaClBitcodeHeader.h"
+#include "llvm/Bitcode/NaCl/NaClLLVMBitCodes.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/StreamingMemoryObject.h"
+#include <atomic>
+#include <climits>
+#include <mutex>
+#include <unordered_map>
+#include <vector>
+
+namespace llvm {
+
+class Deserializer;
+class NaClBitstreamCursor;
+
+namespace naclbitc {
+
+/// Returns the Bit as a Byte:BitInByte string.
+std::string getBitAddress(uint64_t Bit);
+
+/// Severity levels for reporting errors.
+enum ErrorLevel {
+ Warning,
+ Error,
+ Fatal
+};
+
+// Basic printing routine to generate the beginning of an error
+// message. BitPosition is the bit position the error was found.
+// Level is the severity of the error.
+raw_ostream &ErrorAt(raw_ostream &Out, ErrorLevel Level,
+ uint64_t BitPosition);
+
+} // End namespace naclbitc.
+
+/// This class is used to read from a NaCl bitcode wire format stream,
+/// maintaining information that is global to decoding the entire file.
+/// While a file is being read, multiple cursors can be independently
+/// advanced or skipped around within the file. These are represented by
+/// the NaClBitstreamCursor class.
+class NaClBitstreamReader {
+public:
+ // Models a raw list of abbreviations.
+ static const size_t DefaultAbbrevListSize = 12;
+ using AbbrevListVector = SmallVector<NaClBitCodeAbbrev *,
+ DefaultAbbrevListSize>;
+
+ // Models and maintains a list of abbreviations. In particular, it maintains
+ // updating reference counts of abbreviation operators within the abbreviation
+ // list.
+ class AbbrevList {
+ public:
+ AbbrevList() = default;
+ explicit AbbrevList(const AbbrevList &NewAbbrevs) {
+ appendList(NewAbbrevs);
+ }
+ AbbrevList &operator=(const AbbrevList &Rhs) {
+ clear();
+ appendList(Rhs);
+ return *this;
+ }
+ // Creates a new (empty) abbreviation, appends it to this, and then returns
+ // the new abbreviation.
+ NaClBitCodeAbbrev *appendCreate() {
+ NaClBitCodeAbbrev *Abbv = new NaClBitCodeAbbrev();
+ Abbrevs.push_back(Abbv);
+ return Abbv;
+ }
+ // Appends the given abbreviation to this.
+ void append(NaClBitCodeAbbrev *Abbrv) {
+ Abbrv->addRef();
+ Abbrevs.push_back(Abbrv);
+ }
+ // Appends the contents of NewAbbrevs to this.
+ void appendList(const AbbrevList &NewAbbrevs) {
+ for (NaClBitCodeAbbrev *Abbrv : NewAbbrevs.Abbrevs)
+ append(Abbrv);
+ }
+ // Returns last abbreviation on list.
+ NaClBitCodeAbbrev *last() { return Abbrevs.back(); }
+ // Removes the last element of the list.
+ void popLast() {
+ Abbrevs.back()->dropRef();
+ Abbrevs.pop_back();
+ }
+ // Empties abbreviation list.
+ void clear() {
+ while(!Abbrevs.empty())
+ popLast();
+ }
+ // Allow read access to vector defining list.
+ const AbbrevListVector &getVector() const { return Abbrevs; }
+ ~AbbrevList() { clear(); }
+ private:
+ AbbrevListVector Abbrevs;
+ };
+
+ /// This contains information about abbreviations in blocks defined in the
+ /// BLOCKINFO_BLOCK block. These describe global abbreviations that apply to
+ /// all succeeding blocks of the specified ID.
+ class BlockInfo {
+ BlockInfo &operator=(const BlockInfo&) = delete;
+ public:
+ BlockInfo() = default;
+ explicit BlockInfo(unsigned BlockID)
+ : BlockID(BlockID), Abbrevs() {}
+ BlockInfo(const BlockInfo&) = default;
+ unsigned getBlockID() const { return BlockID; }
+ void setBlockID(unsigned ID) { BlockID = ID; }
+ AbbrevList &getAbbrevs() { return Abbrevs; }
+ ~BlockInfo() {}
+ private:
+ unsigned BlockID;
+ AbbrevList Abbrevs;
+ };
+
+ class BlockInfoRecordsMap;
+ using SharedBlockInfoMap = std::shared_ptr<BlockInfoRecordsMap>;
+
+ // Holds the global abbreviations in the BlockInfo block of the bitcode file.
+ // Sharing is used to allow parallel parses. Share by using std::share_ptr's
+ // and std::shared_from_this().
+ //
+ // Note: The BlockInfo block must be parsed before sharing of the
+ // BlockInfoRecordsMap. Therefore, before changing to a parallel parse, the
+ // BlockInfoRecordsMap must be frozen. Failure to do so, can lead to
+ // unexpected behaviour.
+ //
+ // In practice, this means that only function blocks can be parsed in
+ // parallel.
+ class BlockInfoRecordsMap :
+ public std::enable_shared_from_this<BlockInfoRecordsMap> {
+ friend class NaClBitstreamReader;
+ BlockInfoRecordsMap(const BlockInfoRecordsMap&) = delete;
+ BlockInfoRecordsMap &operator=(const BlockInfoRecordsMap&) = delete;
+ public:
+ using InfosMap = std::unordered_map<unsigned, std::unique_ptr<BlockInfo>>;
+
+ static SharedBlockInfoMap create() {
+ return SharedBlockInfoMap(new BlockInfoRecordsMap());
+ }
+ ~BlockInfoRecordsMap() = default;
+
+ bool isFrozen() const {
+ return IsFrozen.load();
+ }
+
+ // Returns true if already frozen.
+ bool freeze() {
+ return IsFrozen.exchange(true);
+ }
+
+ BlockInfo *getBlockInfo(unsigned BlockID) {
+ auto Pos = KnownInfos.find(BlockID);
+ if (Pos != KnownInfos.end())
+ return Pos->second.get();
+ return getOrCreateUnknownBlockInfo(BlockID);
+ }
+
+ // Locks the BlockInfoRecordsMap for the lifetime of the UpdateLock. Used
+ // to allow the parsing of a BlockInfo block, and install global
+ // abbreviations.
+ //
+ // Verifies that the BlockInfoRecordsMap didn't get frozen during the
+ // instance's lifetime as a safety precaution. That is, it checks that no
+ // bitstream reader was created to share the global abbreviations before the
+ // global abbreviations are defined.
+ class UpdateLock {
+ UpdateLock() = delete;
+ UpdateLock(const UpdateLock&) = delete;
+ UpdateLock &operator=(const UpdateLock&) = delete;
+ public:
+ explicit UpdateLock(BlockInfoRecordsMap &BlockInfoRecords);
+ ~UpdateLock();
+ private:
+ // The BlockInfoRecordsMap to update.
+ BlockInfoRecordsMap &BlockInfoRecords;
+ // The locked mutex from BlockInfoRecordsMap;
+ std::unique_lock<std::mutex> Lock;
+ };
+
+ private:
+ // The set of known BlockInfo's. This map is prepopulated so that fast
+ // lookup can be performed thread safe (i.e. without using a lock).
+ InfosMap KnownInfos;
+ // The set of unknown BlockInfo's. This map is to handle unknown (and hence,
+ // invalid) PNaCl bitcode files. This map is updated incrementally, and uses
+ // UnknownBlockInfoLock to make it thread safe.
+ InfosMap UnknownInfos;
+ // True if the known BlockInfo blocks are frozen (i.e. the bitstream reader
+ // will ignore the BlockInfo block).
+ std::atomic_bool IsFrozen;
+ // Lock to use to update this data structure.
+ std::mutex UpdateRecordsLock;
+ // Lock to get/create an unknonw block info.
+ std::mutex UnknownBlockInfoLock;
+
+ BlockInfoRecordsMap();
+
+ BlockInfo *getOrCreateUnknownBlockInfo(unsigned BlockID);
+ };
+
+private:
+ friend class NaClBitstreamCursor;
+
+ std::unique_ptr<MemoryObject> BitcodeBytes;
+
+ SharedBlockInfoMap BlockInfoRecords;
+
+ /// \brief Holds the offset of the first byte after the header.
+ size_t InitialAddress;
+
+ // Holds the number of bytes to add to the bitcode position, when reporting
+ // errors. Useful when using parallel parses of function blocks.
+ size_t ErrorOffset = 0;
+
+ // True if filler should be added to byte align records.
+ bool AlignBitcodeRecords = false;
+ NaClBitstreamReader(const NaClBitstreamReader&) = delete;
+ void operator=(const NaClBitstreamReader&) = delete;
+
+
+ void initFromHeader(NaClBitcodeHeader &Header) {
+ InitialAddress = Header.getHeaderSize();
+ AlignBitcodeRecords = Header.getAlignBitcodeRecords();
+ }
+
+public:
+ /// Read stream from sequence of bytes [Start .. End) after parsing
+ /// the given bitcode header.
+ NaClBitstreamReader(const unsigned char *Start, const unsigned char *End,
+ NaClBitcodeHeader &Header)
+ : BitcodeBytes(getNonStreamedMemoryObject(Start, End)),
+ BlockInfoRecords(BlockInfoRecordsMap::create()) {
+ initFromHeader(Header);
+ }
+
+ /// Read stream from Bytes, after parsing the given bitcode header.
+ NaClBitstreamReader(MemoryObject *Bytes, NaClBitcodeHeader &Header)
+ : BitcodeBytes(Bytes), BlockInfoRecords(BlockInfoRecordsMap::create())
+ { initFromHeader(Header); }
+
+ /// Read stream from bytes, starting at the given initial address.
+ /// Provides simple API for unit testing.
+ NaClBitstreamReader(MemoryObject *Bytes, size_t InitialAddress)
+ : BitcodeBytes(Bytes), BlockInfoRecords(BlockInfoRecordsMap::create()),
+ InitialAddress(InitialAddress) {}
+
+ /// Read stream from sequence of bytes [Start .. End), using the global
+ /// abbreviations of the given bitstream reader. Assumes that [Start .. End)
+ /// is copied from Reader's memory object.
+ NaClBitstreamReader(size_t StartAddress, const unsigned char *Start,
+ const unsigned char *End, NaClBitstreamReader *Reader)
+ : BitcodeBytes(getNonStreamedMemoryObject(Start, End)),
+ BlockInfoRecords(Reader->BlockInfoRecords), InitialAddress(0),
+ ErrorOffset(StartAddress) { BlockInfoRecords->freeze(); }
+
+ // Returns the memory object that is being read.
+ MemoryObject &getBitcodeBytes() { return *BitcodeBytes; }
+
+ ~NaClBitstreamReader() {}
+
+ /// \brief Returns the initial address (after the header) of the input stream.
+ size_t getInitialAddress() const {
+ return InitialAddress;
+ }
+
+ /// Returns the byte address of the first byte in the bitstream. Used
+ /// for error reporting.
+ size_t getErrorOffset() const { return ErrorOffset; }
+
+ //===--------------------------------------------------------------------===//
+ // Block Manipulation
+ //===--------------------------------------------------------------------===//
+
+ BlockInfo *getBlockInfo(unsigned BlockID) {
+ return BlockInfoRecords->getBlockInfo(BlockID);
+ }
+};
+
+/// When advancing through a bitstream cursor, each advance can discover a few
+/// different kinds of entries:
+struct NaClBitstreamEntry {
+ enum {
+ Error, // Malformed bitcode was found.
+ EndBlock, // We've reached the end of the current block, (or the end of the
+ // file, which is treated like a series of EndBlock records.
+ SubBlock, // This is the start of a new subblock of a specific ID.
+ Record // This is a record with a specific AbbrevID.
+ } Kind;
+
+ unsigned ID;
+
+ static NaClBitstreamEntry getError() {
+ NaClBitstreamEntry E; E.Kind = Error; return E;
+ }
+ static NaClBitstreamEntry getEndBlock() {
+ NaClBitstreamEntry E; E.Kind = EndBlock; return E;
+ }
+ static NaClBitstreamEntry getSubBlock(unsigned ID) {
+ NaClBitstreamEntry E; E.Kind = SubBlock; E.ID = ID; return E;
+ }
+ static NaClBitstreamEntry getRecord(unsigned AbbrevID) {
+ NaClBitstreamEntry E; E.Kind = Record; E.ID = AbbrevID; return E;
+ }
+};
+
+/// Models default view of a bitcode record.
+typedef SmallVector<uint64_t, 8> NaClBitcodeRecordVector;
+
+/// Class NaClAbbrevListener is used to allow instances of class
+/// NaClBitcodeParser to listen to record details when processing
+/// abbreviations. The major reason for using a listener is that the
+/// NaCl bitcode reader would require a major rewrite (including the
+/// introduction of more overhead) if we were to lift abbreviations up
+/// to the bitcode reader. That is, not only would we have to lift the
+/// block processing up into the readers (i.e. many blocks in
+/// NaClBitcodeReader and NaClBitcodeParser), but add many new API's
+/// to allow the readers to update internals of the bit stream reader
+/// appropriately.
+class NaClAbbrevListener {
+ NaClAbbrevListener(const NaClAbbrevListener&) = delete;
+ void operator=(const NaClAbbrevListener&) = delete;
+public:
+ NaClAbbrevListener() {}
+ virtual ~NaClAbbrevListener() {}
+
+ /// Called to process the read abbreviation.
+ virtual void ProcessAbbreviation(NaClBitCodeAbbrev *Abbrv,
+ bool IsLocal) = 0;
+
+ /// Called after entering block. NumWords is the number of words
+ /// in the block.
+ virtual void BeginBlockInfoBlock(unsigned NumWords) = 0;
+
+ /// Called if a naclbitc::BLOCKINFO_CODE_SETBID record is found in
+ /// NaClBitstreamCursor::ReadBlockInfoBlock.
+ virtual void SetBID() = 0;
+
+ /// Called just before an EndBlock record is processed by
+ /// NaClBitstreamCursor::ReadBlockInfoBlock
+ virtual void EndBlockInfoBlock() = 0;
+
+ /// The values of the bitcode record associated with the called
+ /// virtual function.
+ NaClBitcodeRecordVector Values;
+
+ /// Start bit for current record being processed in
+ /// NaClBitstreamCursor::ReadBlockInfoBlock.
+ uint64_t StartBit;
+};
+
+/// This represents a position within a bitcode file. There may be multiple
+/// independent cursors reading within one bitstream, each maintaining their
+/// own local state.
+///
+/// Unlike iterators, NaClBitstreamCursors are heavy-weight objects
+/// that should not be passed by value.
+class NaClBitstreamCursor {
+public:
+ /// This class handles errors in the bitstream reader. Redirects
+ /// fatal error messages to virtual method Fatal.
+ class ErrorHandler {
+ ErrorHandler(const ErrorHandler &) = delete;
+ ErrorHandler &operator=(const ErrorHandler &) = delete;
+ public:
+ explicit ErrorHandler(NaClBitstreamCursor &Cursor) : Cursor(Cursor) {}
+ LLVM_ATTRIBUTE_NORETURN
+ virtual void Fatal(const std::string &ErrorMessage) const;
+ virtual ~ErrorHandler() {}
+ uint64_t getCurrentBitNo() const {
+ return Cursor.GetCurrentBitNo();
+ }
+ private:
+ NaClBitstreamCursor &Cursor;
+ };
+
+private:
+ friend class Deserializer;
+ NaClBitstreamReader *BitStream;
+ size_t NextChar;
+ // The current error handler for the bitstream reader.
+ std::unique_ptr<ErrorHandler> ErrHandler;
+
+ // The size of the bitcode. 0 if we don't know it yet.
+ size_t Size;
+
+ /// This is the current data we have pulled from the stream but have not
+ /// returned to the client. This is specifically and intentionally defined to
+ /// follow the word size of the host machine for efficiency. We use word_t in
+ /// places that are aware of this to make it perfectly explicit what is going
+ /// on.
+ typedef size_t word_t;
+ word_t CurWord;
+
+ /// This is the number of bits in CurWord that are valid. This
+ /// is always from [0...bits_of(word_t)-1] inclusive.
+ unsigned BitsInCurWord;
+
+ // Data specific to a block being scanned.
+ class Block {
+ public:
+ Block() = delete;
+ Block &operator=(const Block &Rhs) {
+ GlobalAbbrevs = Rhs.GlobalAbbrevs;
+ NumGlobalAbbrevs = Rhs.NumGlobalAbbrevs;
+ LocalAbbrevs = Rhs.LocalAbbrevs;
+ CodeAbbrev = Rhs.CodeAbbrev;
+ return *this;
+ }
+ Block(NaClBitstreamReader::BlockInfo *GlobalAbbrevs,
+ NaClBitcodeSelectorAbbrev& CodeAbbrev)
+ : GlobalAbbrevs(GlobalAbbrevs),
+ NumGlobalAbbrevs(GlobalAbbrevs->getAbbrevs().getVector().size()),
+ LocalAbbrevs(), CodeAbbrev(CodeAbbrev) {}
+ Block(NaClBitstreamReader::BlockInfo *GlobalAbbrevs)
+ : GlobalAbbrevs(GlobalAbbrevs),
+ NumGlobalAbbrevs(GlobalAbbrevs->getAbbrevs().getVector().size()),
+ LocalAbbrevs(), CodeAbbrev() {}
+ ~Block() = default;
+ const NaClBitstreamReader::AbbrevList &getGlobalAbbrevs() const {
+ return GlobalAbbrevs->getAbbrevs();
+ }
+ unsigned getNumGlobalAbbrevs() const { return NumGlobalAbbrevs; }
+ const NaClBitstreamReader::AbbrevList &getLocalAbbrevs() const {
+ return LocalAbbrevs;
+ }
+ const NaClBitcodeSelectorAbbrev &getCodeAbbrev() const {
+ return CodeAbbrev;
+ }
+ void setCodeAbbrev(NaClBitcodeSelectorAbbrev &Abbrev) {
+ CodeAbbrev = Abbrev;
+ }
+ NaClBitCodeAbbrev *appendLocalCreate() {
+ return LocalAbbrevs.appendCreate();
+ }
+ void moveLocalAbbrevToAbbrevList(NaClBitstreamReader::AbbrevList *List) {
+ if (List != &LocalAbbrevs) {
+ NaClBitCodeAbbrev *Abbv = LocalAbbrevs.last();
+ List->append(Abbv);
+ LocalAbbrevs.popLast();
+ }
+ }
+ private:
+ friend class NaClBitstreamCursor;
+ // The global abbreviations associated with this scope.
+ NaClBitstreamReader::BlockInfo *GlobalAbbrevs;
+ // Number of abbreviations when block was entered. Used to limit scope of
+ // CurBlockInfo, since any abbreviation added inside a BlockInfo block
+ // (within this block) must not effect global abbreviations.
+ unsigned NumGlobalAbbrevs;
+ NaClBitstreamReader::AbbrevList LocalAbbrevs;
+ // This is the declared size of code values used for the current block, in
+ // bits.
+ NaClBitcodeSelectorAbbrev CodeAbbrev;
+ };
+
+ /// This tracks the Block-specific information for each nested block.
+ SmallVector<Block, 8> BlockScope;
+
+ NaClBitstreamCursor(const NaClBitstreamCursor &) = delete;
+ NaClBitstreamCursor &operator=(const NaClBitstreamCursor &) = delete;
+
+public:
+ NaClBitstreamCursor() : ErrHandler(new ErrorHandler(*this)) {
+ init(nullptr);
+ }
+
+ explicit NaClBitstreamCursor(NaClBitstreamReader &R)
+ : ErrHandler(new ErrorHandler(*this)) { init(&R); }
+
+ void init(NaClBitstreamReader *R) {
+ freeState();
+ BitStream = R;
+ NextChar = (BitStream == nullptr) ? 0 : BitStream->getInitialAddress();
+ Size = 0;
+ BitsInCurWord = 0;
+ if (BitStream) {
+ BlockScope.push_back(
+ Block(BitStream->getBlockInfo(naclbitc::TOP_LEVEL_BLOCKID)));
+ }
+ }
+
+ ~NaClBitstreamCursor() {
+ freeState();
+ }
+
+ void freeState() {
+ while (!BlockScope.empty())
+ BlockScope.pop_back();
+ }
+
+ // Replaces the current bitstream error handler with the new
+ // handler. Takes ownership of the new handler and deletes it when
+ // it is no longer needed.
+ void setErrorHandler(std::unique_ptr<ErrorHandler> &NewHandler) {
+ ErrHandler = std::move(NewHandler);
+ }
+
+ bool canSkipToPos(size_t pos) const {
+ // pos can be skipped to if it is a valid address or one byte past the end.
+ return pos == 0 || BitStream->getBitcodeBytes().isValidAddress(
+ static_cast<uint64_t>(pos - 1));
+ }
+
+ bool AtEndOfStream() {
+ if (BitsInCurWord != 0)
+ return false;
+ if (Size != 0)
+ return Size == NextChar;
+ fillCurWord();
+ return BitsInCurWord == 0;
+ }
+
+ /// Return the number of bits used to encode an abbrev #.
+ unsigned getAbbrevIDWidth() const {
+ return BlockScope.back().getCodeAbbrev().NumBits;
+ }
+
+ /// Return the bit # of the bit we are reading.
+ uint64_t GetCurrentBitNo() const {
+ return NextChar*CHAR_BIT - BitsInCurWord;
+ }
+
+ /// Converts the given position into the corresponding Error position.
+ uint64_t getErrorBitNo(uint64_t Position) const {
+ return BitStream->getErrorOffset() * CHAR_BIT + Position;
+ }
+
+ /// Returns the current bit address for reporting errors.
+ uint64_t getErrorBitNo() const {
+ return getErrorBitNo(GetCurrentBitNo());
+ }
+
+ NaClBitstreamReader *getBitStreamReader() {
+ return BitStream;
+ }
+ const NaClBitstreamReader *getBitStreamReader() const {
+ return BitStream;
+ }
+
+ /// Returns the current bit address (string) of the bit cursor.
+ std::string getCurrentBitAddress() const {
+ return naclbitc::getBitAddress(GetCurrentBitNo());
+ }
+
+ /// Flags that modify the behavior of advance().
+ enum {
+ /// If this flag is used, the advance() method does not automatically pop
+ /// the block scope when the end of a block is reached.
+ AF_DontPopBlockAtEnd = 1,
+
+ /// If this flag is used, abbrev entries are returned just like normal
+ /// records.
+ AF_DontAutoprocessAbbrevs = 2
+ };
+
+ /// Advance the current bitstream, returning the next entry in the stream.
+ /// Use the given abbreviation listener (if provided).
+ NaClBitstreamEntry advance(unsigned Flags, NaClAbbrevListener *Listener) {
+ while (1) {
+ unsigned Code = ReadCode();
+ if (Code == naclbitc::END_BLOCK) {
+ // Pop the end of the block unless Flags tells us not to.
+ if (!(Flags & AF_DontPopBlockAtEnd) && ReadBlockEnd())
+ return NaClBitstreamEntry::getError();
+ return NaClBitstreamEntry::getEndBlock();
+ }
+
+ if (Code == naclbitc::ENTER_SUBBLOCK)
+ return NaClBitstreamEntry::getSubBlock(ReadSubBlockID());
+
+ if (Code == naclbitc::DEFINE_ABBREV &&
+ !(Flags & AF_DontAutoprocessAbbrevs)) {
+ // We read and accumulate abbrev's, the client can't do anything with
+ // them anyway.
+ ReadAbbrevRecord(true, Listener);
+ continue;
+ }
+
+ return NaClBitstreamEntry::getRecord(Code);
+ }
+ }
+
+ /// This is a convenience function for clients that don't expect any
+ /// subblocks. This just skips over them automatically.
+ NaClBitstreamEntry advanceSkippingSubblocks(unsigned Flags = 0) {
+ while (1) {
+ // If we found a normal entry, return it.
+ NaClBitstreamEntry Entry = advance(Flags, 0);
+ if (Entry.Kind != NaClBitstreamEntry::SubBlock)
+ return Entry;
+
+ // If we found a sub-block, just skip over it and check the next entry.
+ if (SkipBlock())
+ return NaClBitstreamEntry::getError();
+ }
+ }
+
+ /// Returns the starting byte of the word containing BitNo.
+ uintptr_t getStartWordByteForBit(uint64_t BitNo) const {
+ return uintptr_t(BitNo/CHAR_BIT) & ~(sizeof(word_t)-1);
+ }
+
+ /// Returns the index of BitNo within the word it appears in.
+ unsigned getWordBitNo(uint64_t BitNo) const {
+ return unsigned(BitNo & (sizeof(word_t)*CHAR_BIT-1));
+ }
+
+ /// Returns the ending byte of the word containing BitNo.
+ uintptr_t getEndWordByteForBit(uint64_t BitNo) const {
+ return getStartWordByteForBit(BitNo) +
+ (getWordBitNo(BitNo)
+ ? sizeof(word_t)
+ : 0);
+ }
+
+ /// Fills Buffer[Size] using bytes at Address (in the memory object being
+ /// read). Returns number of bytes filled (less than Size if at end of memory
+ /// object).
+ uint64_t fillBuffer(uint8_t *Buffer, size_t Size, size_t Address) const {
+ return BitStream->getBitcodeBytes().readBytes(Buffer, Size, Address);
+ }
+
+ /// Reset the stream to the specified bit number.
+ void JumpToBit(uint64_t BitNo) {
+ const uintptr_t ByteNo = getStartWordByteForBit(BitNo);
+ const unsigned WordBitNo = getWordBitNo(BitNo);
+ if (!canSkipToPos(ByteNo))
+ reportInvalidJumpToBit(BitNo);
+
+ // Move the cursor to the right word.
+ NextChar = ByteNo;
+ BitsInCurWord = 0;
+
+ // Skip over any bits that are already consumed.
+ if (WordBitNo)
+ Read(WordBitNo);
+ }
+
+ void fillCurWord() {
+ assert(Size == 0 || NextChar < (unsigned)Size);
+
+ // Read the next word from the stream.
+ uint8_t Array[sizeof(word_t)] = {0};
+
+ uint64_t BytesRead = fillBuffer(Array, sizeof(Array), NextChar);
+
+ // If we run out of data, stop at the end of the stream.
+ if (BytesRead == 0) {
+ Size = NextChar;
+ return;
+ }
+
+ CurWord =
+ support::endian::read<word_t, support::little, support::unaligned>(
+ Array);
+ NextChar += BytesRead;
+ BitsInCurWord = BytesRead * CHAR_BIT;
+ }
+
+ word_t Read(unsigned NumBits) {
+ static const unsigned BitsInWord = sizeof(word_t) * CHAR_BIT;
+
+ assert(NumBits && NumBits <= BitsInWord &&
+ "Cannot return zero or more than BitsInWord bits!");
+
+ static const unsigned Mask = sizeof(word_t) > 4 ? 0x3f : 0x1f;
+
+ // If the field is fully contained by CurWord, return it quickly.
+ if (BitsInCurWord >= NumBits) {
+ word_t R = CurWord & (~word_t(0) >> (BitsInWord - NumBits));
+
+ // Use a mask to avoid undefined behavior.
+ CurWord >>= (NumBits & Mask);
+
+ BitsInCurWord -= NumBits;
+ return R;
+ }
+
+ word_t R = BitsInCurWord ? CurWord : 0;
+ unsigned BitsLeft = NumBits - BitsInCurWord;
+
+ fillCurWord();
+
+ // If we run out of data, stop at the end of the stream.
+ if (BitsLeft > BitsInCurWord)
+ return 0;
+
+ word_t R2 = CurWord & (~word_t(0) >> (BitsInWord - BitsLeft));
+
+ // Use a mask to avoid undefined behavior.
+ CurWord >>= (BitsLeft & Mask);
+
+ BitsInCurWord -= BitsLeft;
+
+ R |= R2 << (NumBits - BitsLeft);
+
+ return R;
+ }
+
+ uint32_t ReadVBR(unsigned NumBits) {
+ uint32_t Piece = Read(NumBits);
+ if ((Piece & (1U << (NumBits-1))) == 0)
+ return Piece;
+
+ uint32_t Result = 0;
+ unsigned NextBit = 0;
+ while (1) {
+ Result |= (Piece & ((1U << (NumBits-1))-1)) << NextBit;
+
+ if ((Piece & (1U << (NumBits-1))) == 0)
+ return Result;
+
+ NextBit += NumBits-1;
+ Piece = Read(NumBits);
+ }
+ }
+
+ // Read a VBR that may have a value up to 64-bits in size. The chunk size of
+ // the VBR must still be <= 32 bits though.
+ uint64_t ReadVBR64(unsigned NumBits) {
+ uint32_t Piece = Read(NumBits);
+ if ((Piece & (1U << (NumBits-1))) == 0)
+ return uint64_t(Piece);
+
+ uint64_t Result = 0;
+ unsigned NextBit = 0;
+ while (1) {
+ Result |= uint64_t(Piece & ((1U << (NumBits-1))-1)) << NextBit;
+
+ if ((Piece & (1U << (NumBits-1))) == 0)
+ return Result;
+
+ NextBit += NumBits-1;
+ Piece = Read(NumBits);
+ }
+ }
+
+private:
+ void SkipToByteBoundary() {
+ unsigned BitsToSkip = BitsInCurWord % CHAR_BIT;
+ if (BitsToSkip) {
+ CurWord >>= BitsToSkip;
+ BitsInCurWord -= BitsToSkip;
+ }
+ }
+
+ void SkipToByteBoundaryIfAligned() {
+ if (BitStream->AlignBitcodeRecords)
+ SkipToByteBoundary();
+ }
+
+ void SkipToFourByteBoundary() {
+ // If word_t is 64-bits and if we've read less than 32 bits, just dump
+ // the bits we have up to the next 32-bit boundary.
+ if (sizeof(word_t) > 4 &&
+ BitsInCurWord >= 32) {
+ CurWord >>= BitsInCurWord-32;
+ BitsInCurWord = 32;
+ return;
+ }
+
+ BitsInCurWord = 0;
+ }
+public:
+
+ unsigned ReadCode() {
+ const NaClBitcodeSelectorAbbrev &CodeAbbrev =
+ BlockScope.back().getCodeAbbrev();
+ return CodeAbbrev.IsFixed
+ ? Read(CodeAbbrev.NumBits)
+ : ReadVBR(CodeAbbrev.NumBits);
+ }
+
+ // Block header:
+ // [ENTER_SUBBLOCK, blockid, newcodelen, <align4bytes>, blocklen]
+
+ /// Having read the ENTER_SUBBLOCK code, read the BlockID for the block.
+ unsigned ReadSubBlockID() {
+ return ReadVBR(naclbitc::BlockIDWidth);
+ }
+
+ /// Having read the ENTER_SUBBLOCK abbrevid and a BlockID, skip over the body
+ /// of this block. If the block record is malformed, return true.
+ bool SkipBlock() {
+ // Read and ignore the codelen value. Since we are skipping this block, we
+ // don't care what code widths are used inside of it.
+ ReadVBR(naclbitc::CodeLenWidth);
+ SkipToFourByteBoundary();
+ unsigned NumFourBytes = Read(naclbitc::BlockSizeWidth);
+
+ // Check that the block wasn't partially defined, and that the offset isn't
+ // bogus.
+ size_t SkipTo = GetCurrentBitNo() + NumFourBytes*4*CHAR_BIT;
+ if (AtEndOfStream() || !canSkipToPos(SkipTo/CHAR_BIT))
+ return true;
+
+ JumpToBit(SkipTo);
+ return false;
+ }
+
+ /// Having read the ENTER_SUBBLOCK abbrevid, enter the block, and return true
+ /// if the block has an error.
+ bool EnterSubBlock(unsigned BlockID, unsigned *NumWordsP = nullptr);
+
+ bool ReadBlockEnd() {
+ if (BlockScope.empty()) return true;
+
+ // Block tail:
+ // [END_BLOCK, <align4bytes>]
+ SkipToFourByteBoundary();
+
+ BlockScope.pop_back();
+ return false;
+ }
+
+private:
+
+ //===--------------------------------------------------------------------===//
+ // Record Processing
+ //===--------------------------------------------------------------------===//
+
+private:
+ // Returns abbreviation encoding associated with Value.
+ NaClBitCodeAbbrevOp::Encoding getEncoding(uint64_t Value);
+
+ void skipAbbreviatedField(const NaClBitCodeAbbrevOp &Op);
+
+ // Reads the next Value using the abbreviation Op. Returns true only
+ // if Op is an array (and sets Value to the number of elements in the
+ // array).
+ inline bool readRecordAbbrevField(const NaClBitCodeAbbrevOp &Op,
+ uint64_t &Value);
+
+ // Reads and returns the next value using the abbreviation Op,
+ // assuming Op appears after an array abbreviation.
+ inline uint64_t readArrayAbbreviatedField(const NaClBitCodeAbbrevOp &Op);
+
+ // Reads the array abbreviation Op, NumArrayElements times, putting
+ // the read values in Vals.
+ inline void readArrayAbbrev(const NaClBitCodeAbbrevOp &Op,
+ unsigned NumArrayElements,
+ SmallVectorImpl<uint64_t> &Vals);
+
+ // Reports that that abbreviation Index is not valid.
+ void reportInvalidAbbrevNumber(unsigned Index) const;
+
+ // Reports that jumping to Bit is not valid.
+ void reportInvalidJumpToBit(uint64_t Bit) const;
+
+public:
+
+ /// Return the abbreviation for the specified AbbrevId.
+ const NaClBitCodeAbbrev *getAbbrev(unsigned AbbrevID) const {
+ unsigned AbbrevNo = AbbrevID-naclbitc::FIRST_APPLICATION_ABBREV;
+ const Block &CurBlock = BlockScope.back();
+ const unsigned NumGlobalAbbrevs = CurBlock.getNumGlobalAbbrevs();
+ if (AbbrevNo < NumGlobalAbbrevs)
+ return CurBlock.getGlobalAbbrevs().getVector()[AbbrevNo];
+ unsigned LocalAbbrevNo = AbbrevNo - NumGlobalAbbrevs;
+ NaClBitstreamReader::AbbrevListVector
+ LocalAbbrevs = CurBlock.getLocalAbbrevs().getVector();
+ if (LocalAbbrevNo >= LocalAbbrevs.size())
+ reportInvalidAbbrevNumber(AbbrevID);
+ return LocalAbbrevs[LocalAbbrevNo];
+ }
+
+ /// Read the current record and discard it.
+ void skipRecord(unsigned AbbrevID);
+
+ unsigned readRecord(unsigned AbbrevID, SmallVectorImpl<uint64_t> &Vals);
+
+ //===--------------------------------------------------------------------===//
+ // Abbrev Processing
+ //===--------------------------------------------------------------------===//
+ // IsLocal indicates where the abbreviation occurs. If it is in the
+ // BlockInfo block, IsLocal is false. In all other cases, IsLocal is
+ // true.
+ void ReadAbbrevRecord(bool IsLocal,
+ NaClAbbrevListener *Listener);
+
+ // Skips over an abbreviation record. Duplicates code of ReadAbbrevRecord,
+ // except that no abbreviation is built.
+ void SkipAbbrevRecord();
+
+ bool ReadBlockInfoBlock(NaClAbbrevListener *Listener);
+};
+
+} // End llvm namespace
+
+#endif
diff --git a/pnacl-llvm/include/llvm/Bitcode/NaCl/NaClLLVMBitCodes.h b/pnacl-llvm/include/llvm/Bitcode/NaCl/NaClLLVMBitCodes.h
new file mode 100644
index 0000000..adc554c
--- /dev/null
+++ b/pnacl-llvm/include/llvm/Bitcode/NaCl/NaClLLVMBitCodes.h
@@ -0,0 +1,374 @@
+//===- NaClLLVMBitCodes.h ---------------------------------------*- C++ -*-===//
+// Enum values for the NaCl bitcode wire format
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This header defines Bitcode enum values for NaCl bitcode wire format.
+//
+// The enum values defined in this file should be considered permanent. If
+// new features are added, they should have values added at the end of the
+// respective lists.
+//
+// Note: PNaCl version 1 is no longer supported, and has been removed from
+// comments.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_BITCODE_NACL_NACLLLVMBITCODES_H
+#define LLVM_BITCODE_NACL_NACLLLVMBITCODES_H
+
+#include "llvm/Bitcode/NaCl/NaClBitCodes.h"
+
+namespace llvm {
+namespace naclbitc {
+ // The only top-level block type defined is for a module.
+ enum NaClBlockIDs {
+ // Blocks
+ MODULE_BLOCK_ID = FIRST_APPLICATION_BLOCKID,
+
+ // Module sub-block id's.
+ PARAMATTR_BLOCK_ID, // Not used in PNaCl.
+ PARAMATTR_GROUP_BLOCK_ID, // Not used in PNaCl.
+
+ CONSTANTS_BLOCK_ID,
+ FUNCTION_BLOCK_ID,
+
+ UNUSED_ID1,
+
+ VALUE_SYMTAB_BLOCK_ID,
+ METADATA_BLOCK_ID, // Not used in PNaCl.
+ METADATA_ATTACHMENT_ID, // Not used in PNaCl.
+
+ TYPE_BLOCK_ID_NEW,
+
+ USELIST_BLOCK_ID, // Not used in PNaCl.
+ GLOBALVAR_BLOCK_ID
+ };
+
+
+ /// MODULE blocks have a number of optional fields and subblocks.
+ enum NaClModuleCodes {
+ MODULE_CODE_VERSION = 1, // VERSION: [version#]
+ MODULE_CODE_TRIPLE = 2, // Not used in PNaCl
+ MODULE_CODE_DATALAYOUT = 3, // Not used in PNaCl
+ MODULE_CODE_ASM = 4, // Not used in PNaCl
+ MODULE_CODE_SECTIONNAME = 5, // Not used in PNaCl
+ MODULE_CODE_DEPLIB = 6, // Not used in PNaCl
+ MODULE_CODE_GLOBALVAR = 7, // Not used in PNaCl
+ // FUNCTION: [type, callingconv, isproto, linkage]
+ MODULE_CODE_FUNCTION = 8,
+ MODULE_CODE_ALIAS = 9, // Not used in PNaCl
+ MODULE_CODE_PURGEVALS = 10, // Not used in PNaCl
+ MODULE_CODE_GCNAME = 11 // Not used in PNaCl
+ };
+
+ /// PARAMATTR blocks have code for defining a parameter attribute set.
+ enum NaClAttributeCodes {
+ // FIXME: Remove `PARAMATTR_CODE_ENTRY_OLD' in 4.0
+ PARAMATTR_CODE_ENTRY_OLD = 1, // ENTRY: [paramidx0, attr0,
+ // paramidx1, attr1...]
+ PARAMATTR_CODE_ENTRY = 2, // ENTRY: [paramidx0, attrgrp0,
+ // paramidx1, attrgrp1, ...]
+ PARAMATTR_GRP_CODE_ENTRY = 3 // ENTRY: [id, attr0, att1, ...]
+ };
+
+ /// TYPE blocks have codes for each type primitive they use.
+ enum NaClTypeCodes {
+ TYPE_CODE_NUMENTRY = 1, // NUMENTRY: [numentries]
+
+ // Type Codes
+ TYPE_CODE_VOID = 2, // VOID
+ TYPE_CODE_FLOAT = 3, // FLOAT
+ TYPE_CODE_DOUBLE = 4, // DOUBLE
+ // TODO(mseaborn): Remove LABEL when we drop support for v1 of the
+ // PNaCl bitcode format. The writer no longer generates it.
+ TYPE_CODE_LABEL = 5, // LABEL
+ TYPE_CODE_OPAQUE = 6, // Not used in PNaCl.
+ TYPE_CODE_INTEGER = 7, // INTEGER: [width]
+ TYPE_CODE_POINTER = 8, // POINTER: [pointee type]
+
+ TYPE_CODE_FUNCTION_OLD = 9, // Not used in PNaCl.
+
+ TYPE_CODE_HALF = 10, // Not used in PNaCl.
+
+ TYPE_CODE_ARRAY = 11, // Not used in PNaCl.
+ TYPE_CODE_VECTOR = 12, // VECTOR: [numelts, eltty]
+
+ // These are not with the other floating point types because they're
+ // a late addition, and putting them in the right place breaks
+ // binary compatibility.
+ TYPE_CODE_X86_FP80 = 13, // Not used in PNaCl.
+ TYPE_CODE_FP128 = 14, // Not used in PNaCl.
+ TYPE_CODE_PPC_FP128= 15, // Not used in PNaCl.
+
+ TYPE_CODE_METADATA = 16, // Not used in PNaCl.
+
+ TYPE_CODE_X86_MMX = 17, // Not used in PNaCl.
+
+ TYPE_CODE_STRUCT_ANON = 18, // Not used in PNaCl.
+ TYPE_CODE_STRUCT_NAME = 19, // Not used in PNaCl.
+ TYPE_CODE_STRUCT_NAMED = 20,// Not used in PNaCl.
+
+ TYPE_CODE_FUNCTION = 21 // FUNCTION: [vararg, retty, paramty x N]
+ };
+
+ // The type symbol table only has one code (TST_ENTRY_CODE).
+ enum NaClTypeSymtabCodes {
+ TST_CODE_ENTRY = 1 // TST_ENTRY: [typeid, namechar x N]
+ };
+
+ // The value symbol table only has one code (VST_ENTRY_CODE).
+ enum NaClValueSymtabCodes {
+ VST_CODE_ENTRY = 1, // VST_ENTRY: [valid, namechar x N]
+ VST_CODE_BBENTRY = 2 // VST_BBENTRY: [bbid, namechar x N]
+ };
+
+ // Not used in PNaCl.
+ enum NaClMetadataCodes {
+ METADATA_STRING = 1, // MDSTRING: [values]
+ // 2 is unused.
+ // 3 is unused.
+ METADATA_NAME = 4, // STRING: [values]
+ // 5 is unused.
+ METADATA_KIND = 6, // [n x [id, name]]
+ // 7 is unused.
+ METADATA_NODE = 8, // NODE: [n x (type num, value num)]
+ METADATA_FN_NODE = 9, // FN_NODE: [n x (type num, value num)]
+ METADATA_NAMED_NODE = 10, // NAMED_NODE: [n x mdnodes]
+ METADATA_ATTACHMENT = 11 // [m x [value, [n x [id, mdnode]]]
+ };
+
+ // The constants block (CONSTANTS_BLOCK_ID) describes emission for each
+ // constant and maintains an implicit current type value.
+ enum NaClConstantsCodes {
+ CST_CODE_SETTYPE = 1, // SETTYPE: [typeid]
+ CST_CODE_NULL = 2, // Not used in PNaCl.
+ CST_CODE_UNDEF = 3, // UNDEF
+ CST_CODE_INTEGER = 4, // INTEGER: [intval]
+ CST_CODE_WIDE_INTEGER = 5, // Not used in PNaCl.
+ CST_CODE_FLOAT = 6, // FLOAT: [fpval]
+ CST_CODE_AGGREGATE = 7, // Not used in PNaCl.
+ CST_CODE_STRING = 8, // Not used in PNaCl.
+ CST_CODE_CSTRING = 9, // Not used in PNaCl.
+ CST_CODE_CE_BINOP = 10, // Not used in PNaCl.
+ CST_CODE_CE_CAST = 11, // Not used in PNaCl.
+ CST_CODE_CE_GEP = 12, // Not used in PNaCl.
+ CST_CODE_CE_SELECT = 13, // Not used in PNaCl.
+ CST_CODE_CE_EXTRACTELT = 14, // Not used in PNaCl.
+ CST_CODE_CE_INSERTELT = 15, // Not used in PNaCl.
+ CST_CODE_CE_SHUFFLEVEC = 16, // Not used in PNaCl.
+ CST_CODE_CE_CMP = 17, // Not used in PNaCl.
+ CST_CODE_INLINEASM_OLD = 18, // No longer used.
+ CST_CODE_CE_SHUFVEC_EX = 19, // Not used in PNaCl.
+ CST_CODE_CE_INBOUNDS_GEP = 20,// Not used in PNaCl.
+ CST_CODE_BLOCKADDRESS = 21, // Not used in PNaCl.
+ CST_CODE_DATA = 22, // Not used in PNaCl.
+ CST_CODE_INLINEASM = 23 // Not used in PNaCl.
+ };
+
+ /// GlobalVarOpcodes - These are values used in the bitcode files to
+ /// encode records defining global variables.
+ ///
+ /// The structure of global variables can be summarized as follows:
+ ///
+ /// The global variable block begins with a GLOBALVAR_COUNT, defining
+ /// the number of global variables in the bitcode file. After that,
+ /// each global variable is defined.
+ ///
+ /// Global variables are defined by a GLOBALVAR_VAR record, followed
+ /// by 1 or more records defining its initial value. Simple
+ /// variables have a single initializer. Structured variables are
+ /// defined by an initial GLOBALVAR_COMPOUND record defining the
+ /// number of fields in the structure, followed by an initializer
+ /// for each of its fields. In this context, a field is either data,
+ /// or a relocation. A data field is defined by a
+ /// GLOBALVAR_ZEROFILL or GLOBALVAR_DATA record. A relocation field
+ /// is defined by a GLOBALVAR_RELOC record.
+ enum NaClGlobalVarOpcodes {
+ GLOBALVAR_VAR = 0, // VAR: [align, isconst]
+ GLOBALVAR_COMPOUND = 1, // COMPOUND: [size]
+ GLOBALVAR_ZEROFILL = 2, // ZEROFILL: [size]
+ GLOBALVAR_DATA = 3, // DATA: [b0, b1, ...]
+ GLOBALVAR_RELOC = 4, // RELOC: [val, [addend]]
+ GLOBALVAR_COUNT = 5 // COUNT: [n]
+ };
+
+ /// CastOpcodes - These are values used in the bitcode files to encode which
+ /// cast a CST_CODE_CE_CAST or a XXX refers to. The values of these enums
+ /// have no fixed relation to the LLVM IR enum values. Changing these will
+ /// break compatibility with old files.
+ enum NaClCastOpcodes {
+ CAST_TRUNC = 0,
+ CAST_ZEXT = 1,
+ CAST_SEXT = 2,
+ CAST_FPTOUI = 3,
+ CAST_FPTOSI = 4,
+ CAST_UITOFP = 5,
+ CAST_SITOFP = 6,
+ CAST_FPTRUNC = 7,
+ CAST_FPEXT = 8,
+ // 9 was CAST_PTRTOINT; not used in PNaCl.
+ // 10 was CAST_INTTOPTR; not used in PNaCl.
+ CAST_BITCAST = 11
+ };
+
+ /// BinaryOpcodes - These are values used in the bitcode files to encode which
+ /// binop a CST_CODE_CE_BINOP or a XXX refers to. The values of these enums
+ /// have no fixed relation to the LLVM IR enum values. Changing these will
+ /// break compatibility with old files.
+ enum NaClBinaryOpcodes {
+ BINOP_ADD = 0,
+ BINOP_SUB = 1,
+ BINOP_MUL = 2,
+ BINOP_UDIV = 3,
+ BINOP_SDIV = 4, // overloaded for FP
+ BINOP_UREM = 5,
+ BINOP_SREM = 6, // overloaded for FP
+ BINOP_SHL = 7,
+ BINOP_LSHR = 8,
+ BINOP_ASHR = 9,
+ BINOP_AND = 10,
+ BINOP_OR = 11,
+ BINOP_XOR = 12
+ };
+
+ /// OverflowingBinaryOperatorOptionalFlags - Flags for serializing
+ /// OverflowingBinaryOperator's SubclassOptionalData contents.
+ /// Note: This enum is no longer used in PNaCl, because these
+ /// flags can't exist in files that meet the PNaCl ABI.
+ enum NaClOverflowingBinaryOperatorOptionalFlags {
+ OBO_NO_UNSIGNED_WRAP = 0,
+ OBO_NO_SIGNED_WRAP = 1
+ };
+
+ /// PossiblyExactOperatorOptionalFlags - Flags for serializing
+ /// PossiblyExactOperator's SubclassOptionalData contents.
+ /// Note: This enum is no longer used in PNaCl, because these
+ /// flags can't exist in files that meet the PNaCl ABI.
+ enum NaClPossiblyExactOperatorOptionalFlags {
+ PEO_EXACT = 0
+ };
+
+ /// \brief Flags for serializing floating point binary operators's
+ /// SubclassOptionalData contents.
+ /// Note: This enum is no longer used in PNaCl, because these
+ /// flags shouldn't exist in files that meet the PNaCl ABI, unless
+ /// they are old. In the latter case, they are ignored by the reader.
+ enum NaClFloatingPointBinaryOperatorOptionalFlags {
+ FPO_UNSAFE_ALGEBRA = 0,
+ FPO_NO_NANS = 1,
+ FPO_NO_INFS = 2,
+ FPO_NO_SIGNED_ZEROS = 3,
+ FPO_ALLOW_RECIPROCAL = 4
+ };
+
+ /// Encoded function calling conventions.
+ enum NaClCallingConventions {
+ C_CallingConv = 0
+ };
+
+ /// Encoded comparison predicates.
+ enum NaClComparisonPredicates {
+ // Opcode U L G E Intuitive operation
+ FCMP_FALSE = 0, ///< 0 0 0 0 Always false (always folded)
+ FCMP_OEQ = 1, ///< 0 0 0 1 True if ordered and equal
+ FCMP_OGT = 2, ///< 0 0 1 0 True if ordered and greater than
+ FCMP_OGE = 3, ///< 0 0 1 1 True if ordered and greater than or equal
+ FCMP_OLT = 4, ///< 0 1 0 0 True if ordered and less than
+ FCMP_OLE = 5, ///< 0 1 0 1 True if ordered and less than or equal
+ FCMP_ONE = 6, ///< 0 1 1 0 True if ordered and operands are unequal
+ FCMP_ORD = 7, ///< 0 1 1 1 True if ordered (no nans)
+ FCMP_UNO = 8, ///< 1 0 0 0 True if unordered: isnan(X) | isnan(Y)
+ FCMP_UEQ = 9, ///< 1 0 0 1 True if unordered or equal
+ FCMP_UGT = 10, ///< 1 0 1 0 True if unordered or greater than
+ FCMP_UGE = 11, ///< 1 0 1 1 True if unordered, greater than, or equal
+ FCMP_ULT = 12, ///< 1 1 0 0 True if unordered or less than
+ FCMP_ULE = 13, ///< 1 1 0 1 True if unordered, less than, or equal
+ FCMP_UNE = 14, ///< 1 1 1 0 True if unordered or not equal
+ FCMP_TRUE = 15, ///< 1 1 1 1 Always true (always folded)
+ ICMP_EQ = 32, ///< equal
+ ICMP_NE = 33, ///< not equal
+ ICMP_UGT = 34, ///< unsigned greater than
+ ICMP_UGE = 35, ///< unsigned greater or equal
+ ICMP_ULT = 36, ///< unsigned less than
+ ICMP_ULE = 37, ///< unsigned less or equal
+ ICMP_SGT = 38, ///< signed greater than
+ ICMP_SGE = 39, ///< signed greater or equal
+ ICMP_SLT = 40, ///< signed less than
+ ICMP_SLE = 41 ///< signed less or equal
+ };
+
+ enum NaClLinkageTypes {
+ LINKAGE_EXTERNAL = 0,
+ LINKAGE_INTERNAL = 3
+ };
+
+ // The function body block (FUNCTION_BLOCK_ID) describes function bodies. It
+ // can contain a constant block (CONSTANTS_BLOCK_ID).
+ enum NaClFunctionCodes {
+ FUNC_CODE_DECLAREBLOCKS = 1, // DECLAREBLOCKS: [n]
+
+ FUNC_CODE_INST_BINOP = 2, // BINOP: [opval, opval, opcode]
+ // Note: because old PNaCl bitcode files
+ // may contain flags (which we now ignore),
+ // the reader must also support:
+ // BINOP: [opval, opval, opcode, flags]
+ FUNC_CODE_INST_CAST = 3, // CAST: [opval, destty, castopc]
+ FUNC_CODE_INST_GEP = 4, // Not used in PNaCl.
+ FUNC_CODE_INST_SELECT = 5, // Not used in PNaCl. Replaced by VSELECT.
+ FUNC_CODE_INST_EXTRACTELT = 6, // EXTRACTELT: [opval, opval]
+ FUNC_CODE_INST_INSERTELT = 7, // INSERTELT: [opval, opval, opval]
+ FUNC_CODE_INST_SHUFFLEVEC = 8, // Not used in PNaCl.
+ FUNC_CODE_INST_CMP = 9, // Not used in PNaCl. Replaced by CMP2.
+ FUNC_CODE_INST_RET = 10, // RET: [opval<optional>]
+ FUNC_CODE_INST_BR = 11, // BR: [bb#, bb#, cond] or [bb#]
+ FUNC_CODE_INST_SWITCH = 12, // SWITCH: [opty, op0, op1, ...]
+ FUNC_CODE_INST_INVOKE = 13, // Not used in PNaCl.
+ // 14 is unused.
+ FUNC_CODE_INST_UNREACHABLE = 15, // UNREACHABLE
+
+ FUNC_CODE_INST_PHI = 16, // PHI: [ty, val0,bb0, ...]
+ // 17 is unused.
+ // 18 is unused.
+ FUNC_CODE_INST_ALLOCA = 19, // ALLOCA: [op, align]
+ FUNC_CODE_INST_LOAD = 20, // LOAD: [op, align, ty]
+ // 21 is unused.
+ // 22 is unused.
+ FUNC_CODE_INST_VAARG = 23, // Not used in PNaCl.
+ FUNC_CODE_INST_STORE = 24, // STORE: [ptr, val, align]
+ // 25 is unused.
+ FUNC_CODE_INST_EXTRACTVAL = 26, // Not used in PNaCl.
+ FUNC_CODE_INST_INSERTVAL = 27, // Not used in PNaCl.
+ // fcmp/icmp returning Int1TY or vector of Int1Ty. Same as CMP, exists to
+ // support legacy vicmp/vfcmp instructions.
+ FUNC_CODE_INST_CMP2 = 28, // CMP2: [opval, opval, pred]
+ // new select on i1 or [N x i1]
+ FUNC_CODE_INST_VSELECT = 29, // VSELECT: [opval, opval, pred]
+ FUNC_CODE_INST_INBOUNDS_GEP= 30, // Not used in PNaCl.
+ FUNC_CODE_INST_INDIRECTBR = 31, // Not used in PNaCl.
+ // 32 is unused.
+ FUNC_CODE_DEBUG_LOC_AGAIN = 33, // Not used in PNaCl.
+
+ FUNC_CODE_INST_CALL = 34, // CALL: [cc, fnid, args...]
+ // See FUNC_CODE_INST_CALL_INDIRECT below.
+ FUNC_CODE_DEBUG_LOC = 35, // Not used in PNaCl.
+ FUNC_CODE_INST_FENCE = 36, // Not used in PNaCl.
+ FUNC_CODE_INST_CMPXCHG = 37, // Not used in PNaCl.
+ FUNC_CODE_INST_ATOMICRMW = 38, // Not used in PNaCl.
+ FUNC_CODE_INST_RESUME = 39, // Not used in PNaCl.
+ FUNC_CODE_INST_LANDINGPAD = 40, // Not used in PNaCl.
+ FUNC_CODE_INST_LOADATOMIC = 41, // Not used in PNaCl.
+ FUNC_CODE_INST_STOREATOMIC = 42, // Not used in PNaCl.
+ FUNC_CODE_INST_FORWARDTYPEREF = 43, // TYPE: [opval, ty]
+ // CALL_INDIRECT: [cc, fnid, returnty, args...]
+ FUNC_CODE_INST_CALL_INDIRECT = 44
+ };
+} // End naclbitc namespace
+} // End llvm namespace
+
+#endif
diff --git a/pnacl-llvm/include/llvm/Bitcode/NaCl/NaClReaderWriter.h b/pnacl-llvm/include/llvm/Bitcode/NaCl/NaClReaderWriter.h
new file mode 100644
index 0000000..762e51b
--- /dev/null
+++ b/pnacl-llvm/include/llvm/Bitcode/NaCl/NaClReaderWriter.h
@@ -0,0 +1,143 @@
+//===-- llvm/Bitcode/NaCl/NaClReaderWriter.h - ------------------*- C++ -*-===//
+// NaCl Bitcode reader/writer.
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This header defines interfaces to read and write NaCl bitcode wire format
+// files.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_BITCODE_NACL_NACLREADERWRITER_H
+#define LLVM_BITCODE_NACL_NACLREADERWRITER_H
+
+#include "llvm/IR/DiagnosticInfo.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+#include <string>
+
+namespace llvm {
+ class LLVMContext;
+ class Module;
+ class NaClBitcodeHeader;
+ class NaClBitstreamWriter;
+ class StreamingMemoryObject;
+ class raw_ostream;
+
+ /// Defines the data layout used for PNaCl bitcode files. We set the
+ /// data layout of the module in the bitcode readers rather than in
+ /// pnacl-llc so that 'opt' will also use the correct data layout if
+ /// it is run on a pexe.
+ extern const char *PNaClDataLayout;
+
+ /// Allows (function) local symbol tables (unsupported) in PNaCl bitcode
+ /// files.
+ extern cl::opt<bool> PNaClAllowLocalSymbolTables;
+
+ /// \brief Defines the integer bit size used to model pointers in PNaCl.
+ static const unsigned PNaClIntPtrTypeBitSize = 32;
+
+ /// Diagnostic handler that redirects error diagnostics to the given stream.
+ DiagnosticHandlerFunction redirectNaClDiagnosticToStream(raw_ostream &Out);
+
+ /// Read the header of the specified bitcode buffer and prepare for lazy
+ /// deserialization of function bodies. If successful, this takes ownership
+ /// of 'Buffer' (extending its lifetime). On error, this returns an error
+ /// code and deletes Buffer.
+ ///
+ /// The AcceptSupportedOnly argument is used to decide which PNaCl versions
+ /// of the PNaCl bitcode to accept. There are three forms:
+ /// 1) Readable and supported.
+ /// 2) Readable and unsupported. Allows testing of code before becoming
+ /// supported, as well as running experiments on the bitcode format.
+ /// 3) Unreadable.
+ /// When AcceptSupportedOnly is true, only form 1 is allowed. When
+ /// AcceptSupportedOnly is false, forms 1 and 2 are allowed.
+ ErrorOr<Module *> getNaClLazyBitcodeModule(
+ std::unique_ptr<MemoryBuffer> &&Buffer, LLVMContext &Context,
+ DiagnosticHandlerFunction DiagnosticHandler = nullptr,
+ bool AcceptSupportedOnly = true);
+
+ /// Read the header of the specified stream and prepare for lazy
+ /// deserialization and streaming of function bodies. On error,
+ /// this returns null, and fills in *ErrMsg with an error description
+ /// if ErrMsg is non-null.
+ ///
+ /// See getNaClLazyBitcodeModule for an explanation of argument
+ /// AcceptSupportedOnly.
+ /// TODO(kschimpf): Refactor this and getStreamedBitcodeModule to use
+ /// ErrorOr<Module *> API so that all methods have the same interface.
+ Module *getNaClStreamedBitcodeModule(
+ const std::string &name, StreamingMemoryObject *streamer,
+ LLVMContext &Context,
+ DiagnosticHandlerFunction DiagnosticHandler = nullptr,
+ std::string *ErrMsg = nullptr, bool AcceptSupportedOnly = true);
+
+ /// Read the bitcode file from a buffer, returning the module.
+ ///
+ /// See getNaClLazyBitcodeModule for an explanation of argument
+ /// AcceptSupportedOnly.
+ ErrorOr<Module *>
+ NaClParseBitcodeFile(MemoryBufferRef Buffer, LLVMContext &Context,
+ DiagnosticHandlerFunction DiagnosticHandler = nullptr,
+ bool AcceptSupportedOnly = true);
+
+ /// Read the textual bitcode records in Filename, returning the module.
+ /// Note: If Filename is "-", stdin will be read.
+ ///
+ /// TODO(kschimpf) Replace Verbose argument with a DiagnosticHandlerFunction.
+ ErrorOr<Module *> parseNaClBitcodeText(const std::string &Filename,
+ LLVMContext &Context,
+ raw_ostream *Verbose = nullptr);
+
+ /// Write the specified module to the specified raw output stream, using
+ /// PNaCl wire format. For streams where it matters, the given stream
+ /// should be in "binary" mode.
+ ///
+ /// The AcceptSupportedOnly argument is used to decide which PNaCl versions
+ /// of the PNaCl bitcode to generate. There are two forms:
+ /// 1) Writable and supported.
+ /// 2) Writable and unsupported. Allows testing of code before becoming
+ /// supported, as well as running experiments on the bitcode format.
+ /// When AcceptSupportedOnly is true, only form 1 is allowed. When
+ /// AcceptSupportedOnly is false, forms 1 and 2 are allowed.
+ void NaClWriteBitcodeToFile(const Module *M, raw_ostream &Out,
+ bool AcceptSupportedOnly = true);
+
+ /// isNaClBitcode - Return true if the given bytes are the magic bytes for
+ /// PNaCl bitcode wire format.
+ ///
+ inline bool isNaClBitcode(const unsigned char *BufPtr,
+ const unsigned char *BufEnd) {
+ return BufPtr+4 <= BufEnd &&
+ BufPtr[0] == 'P' &&
+ BufPtr[1] == 'E' &&
+ BufPtr[2] == 'X' &&
+ BufPtr[3] == 'E';
+ }
+
+ /// NaClWriteHeader - Generate a default header (using the version
+ /// number defined by kPNaClVersion) and write to the corresponding
+ /// bitcode stream.
+ void NaClWriteHeader(NaClBitstreamWriter &Stream, bool AcceptSupportedOnly);
+
+ // NaClWriteHeader - Write the contents of the bitcode header to the
+ // corresponding bitcode stream.
+ void NaClWriteHeader(const NaClBitcodeHeader &Header,
+ NaClBitstreamWriter &Stream);
+
+ /// NaClObjDump - Read PNaCl bitcode file from input, and print a
+ /// textual representation of its contents. NoRecords and NoAssembly
+ /// define what should not be included in the dump.
+ bool NaClObjDump(MemoryBufferRef Input, raw_ostream &output,
+ bool NoRecords, bool NoAssembly);
+
+} // end llvm namespace
+#endif
diff --git a/src/IceBitVector.h b/src/IceBitVector.h
index 3a5f8e6..8b5330a 100644
--- a/src/IceBitVector.h
+++ b/src/IceBitVector.h
@@ -263,7 +263,7 @@
uint64_t alignTo(uint64_t Value, uint64_t Align) {
#ifdef PNACL_LLVM
return llvm::RoundUpToAlignment(Value, Align);
-#else // !PNACL_LLVM
+#else // !PNACL_LLVM
return llvm::alignTo(Value, Align);
#endif // !PNACL_LLVM
}
diff --git a/src/IceCompileServer.cpp b/src/IceCompileServer.cpp
index 15a86c3..adb4102 100644
--- a/src/IceCompileServer.cpp
+++ b/src/IceCompileServer.cpp
@@ -24,7 +24,9 @@
#pragma clang diagnostic ignored "-Wunused-parameter"
#endif // __clang__
+#ifdef PNACL_LLVM
#include "llvm/Bitcode/NaCl/NaClBitcodeMungeUtils.h"
+#endif // PNACL_LLVM
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/raw_os_ostream.h"
#include "llvm/Support/Signals.h"
@@ -52,11 +54,10 @@
~TextDataStreamer() final = default;
#ifdef PNACL_LLVM
using CreateType = TextDataStreamer *;
-#else // !PNACL_LLVM
+#else // !PNACL_LLVM
using CreateType = std::unique_ptr<TextDataStreamer>;
#endif // !PNACL_LLVM
- static CreateType create(const std::string &Filename,
- std::string *Err);
+ static CreateType create(const std::string &Filename, std::string *Err);
size_t GetBytes(unsigned char *Buf, size_t Len) final;
private:
@@ -64,8 +65,8 @@
size_t Cursor = 0;
};
-TextDataStreamer::CreateType TextDataStreamer::create(const std::string &Filename,
- std::string *Err) {
+TextDataStreamer::CreateType
+TextDataStreamer::create(const std::string &Filename, std::string *Err) {
#ifdef PNACL_LLVM
TextDataStreamer *Streamer = new TextDataStreamer();
llvm::raw_string_ostream ErrStrm(*Err);
@@ -78,7 +79,7 @@
}
ErrStrm.flush();
return Streamer;
-#else // !PNACL_LLVM
+#else // !PNACL_LLVM
return CreateType();
#endif // !PNACL_LLVM
}
diff --git a/src/IceCompiler.cpp b/src/IceCompiler.cpp
index 08e1a14..d605610 100644
--- a/src/IceCompiler.cpp
+++ b/src/IceCompiler.cpp
@@ -87,9 +87,11 @@
if (BuildOnRead) {
std::unique_ptr<PNaClTranslator> PTranslator(new PNaClTranslator(&Ctx));
#ifdef PNACL_LLVM
- std::unique_ptr<llvm::StreamingMemoryObject> MemObj(new llvm::StreamingMemoryObjectImpl(InputStream.release()));
-#else // !PNACL_LLVM
- std::unique_ptr<llvm::StreamingMemoryObject> MemObj(new llvm::StreamingMemoryObject(std::move(InputStream)));
+ std::unique_ptr<llvm::StreamingMemoryObject> MemObj(
+ new llvm::StreamingMemoryObjectImpl(InputStream.release()));
+#else // !PNACL_LLVM
+ std::unique_ptr<llvm::StreamingMemoryObject> MemObj(
+ new llvm::StreamingMemoryObject(std::move(InputStream)));
#endif // !PNACL_LLVM
PTranslator->translate(IRFilename, std::move(MemObj));
Translator.reset(PTranslator.release());
@@ -131,11 +133,10 @@
std::unique_ptr<llvm::Module> Mod =
NaClParseIRFile(IRFilename, Flags.getInputFileFormat(), Err,
llvm::getGlobalContext(), DiagnosticHandler);
-#else // !PNACL_LLVM
+#else // !PNACL_LLVM
llvm::DiagnosticHandlerFunction DiagnosticHandler = nullptr;
llvm::LLVMContext Context;
- std::unique_ptr<llvm::Module> Mod =
- parseIRFile(IRFilename, Err, Context);
+ std::unique_ptr<llvm::Module> Mod = parseIRFile(IRFilename, Err, Context);
#endif // !PNACL_LLVM
if (!Mod) {
Err.print(Flags.getAppName().c_str(), llvm::errs());
diff --git a/src/IceInst.h b/src/IceInst.h
index 769d405..36b8810 100644
--- a/src/IceInst.h
+++ b/src/IceInst.h
@@ -1136,14 +1136,12 @@
inline InstList::iterator instToIterator(Inst *Instr) {
#ifdef PNACL_LLVM
return Instr;
-#else // !PNACL_LLVM
+#else // !PNACL_LLVM
return Instr->getIterator();
#endif // !PNACL_LLVM
}
-inline Inst *iteratorToInst(InstList::iterator Iter) {
- return &*Iter;
-}
+inline Inst *iteratorToInst(InstList::iterator Iter) { return &*Iter; }
inline const Inst *iteratorToInst(InstList::const_iterator Iter) {
return &*Iter;