Commit a5b16abf by Jim Stichnoth

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 .
parent f5fdd236
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 @@ else()
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)
......@@ -743,6 +743,7 @@ FORMAT_BLACKLIST += ! -name IceParseTypesTest.cpp
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)`
......
......@@ -44,6 +44,27 @@ minimize the size of the translator by compiling out everything unnecessary.
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``
------------
......
//===- 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;
}
//===- 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;
}
}
}
}
//===- 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;
}
}
}
//===- 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;
}
//===- 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;
}
}
}
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.
//===- 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
//===- 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
//===- 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
//===-- 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
//===- 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
//===- 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
//===- 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
//===-- 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
......@@ -263,7 +263,7 @@ template <template <typename> class AT> class BitVectorTmpl {
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
}
......
......@@ -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 @@ public:
~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 @@ private:
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 @@ TextDataStreamer::CreateType TextDataStreamer::create(const std::string &Filenam
}
ErrStrm.flush();
return Streamer;
#else // !PNACL_LLVM
#else // !PNACL_LLVM
return CreateType();
#endif // !PNACL_LLVM
}
......
......@@ -87,9 +87,11 @@ void Compiler::run(const Ice::ClFlags &Flags, GlobalContext &Ctx,
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 @@ void Compiler::run(const Ice::ClFlags &Flags, GlobalContext &Ctx,
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());
......
......@@ -1136,14 +1136,12 @@ namespace Ice {
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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment