diff options
Diffstat (limited to 'lib/Bitcode')
-rw-r--r-- | lib/Bitcode/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib/Bitcode/LLVMBuild.txt | 2 | ||||
-rw-r--r-- | lib/Bitcode/Makefile | 2 | ||||
-rw-r--r-- | lib/Bitcode/NaCl/CMakeLists.txt | 2 | ||||
-rw-r--r-- | lib/Bitcode/NaCl/LLVMBuild.txt | 24 | ||||
-rw-r--r-- | lib/Bitcode/NaCl/Makefile | 14 | ||||
-rw-r--r-- | lib/Bitcode/NaCl/Reader/CMakeLists.txt | 7 | ||||
-rw-r--r-- | lib/Bitcode/NaCl/Reader/LLVMBuild.txt | 22 | ||||
-rw-r--r-- | lib/Bitcode/NaCl/Reader/Makefile | 15 | ||||
-rw-r--r-- | lib/Bitcode/NaCl/Reader/NaClBitcodeHeader.cpp | 261 | ||||
-rw-r--r-- | lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp | 2644 | ||||
-rw-r--r-- | lib/Bitcode/NaCl/Reader/NaClBitcodeReader.h | 297 | ||||
-rw-r--r-- | lib/Bitcode/NaCl/Reader/NaClBitstreamReader.cpp | 374 | ||||
-rw-r--r-- | lib/Bitcode/NaCl/Writer/CMakeLists.txt | 5 | ||||
-rw-r--r-- | lib/Bitcode/NaCl/Writer/LLVMBuild.txt | 22 | ||||
-rw-r--r-- | lib/Bitcode/NaCl/Writer/Makefile | 15 | ||||
-rw-r--r-- | lib/Bitcode/NaCl/Writer/NaClBitcodeWriter.cpp | 1790 | ||||
-rw-r--r-- | lib/Bitcode/NaCl/Writer/NaClValueEnumerator.cpp | 443 | ||||
-rw-r--r-- | lib/Bitcode/NaCl/Writer/NaClValueEnumerator.h | 157 | ||||
-rw-r--r-- | lib/Bitcode/Reader/BitcodeReader.cpp | 21 |
20 files changed, 6116 insertions, 2 deletions
diff --git a/lib/Bitcode/CMakeLists.txt b/lib/Bitcode/CMakeLists.txt index ff7e290cad..8969ec83f5 100644 --- a/lib/Bitcode/CMakeLists.txt +++ b/lib/Bitcode/CMakeLists.txt @@ -1,2 +1,3 @@ add_subdirectory(Reader) add_subdirectory(Writer) +add_subdirectory(NaCl) diff --git a/lib/Bitcode/LLVMBuild.txt b/lib/Bitcode/LLVMBuild.txt index af9936bbe8..415a33dfdf 100644 --- a/lib/Bitcode/LLVMBuild.txt +++ b/lib/Bitcode/LLVMBuild.txt @@ -16,7 +16,7 @@ ;===------------------------------------------------------------------------===; [common] -subdirectories = Reader Writer +subdirectories = Reader Writer NaCl [component_0] type = Group diff --git a/lib/Bitcode/Makefile b/lib/Bitcode/Makefile index 2d6b5ad1fe..cbaab3578c 100644 --- a/lib/Bitcode/Makefile +++ b/lib/Bitcode/Makefile @@ -8,7 +8,7 @@ ##===----------------------------------------------------------------------===## LEVEL = ../.. -PARALLEL_DIRS = Reader Writer +PARALLEL_DIRS = Reader Writer NaCl include $(LEVEL)/Makefile.common diff --git a/lib/Bitcode/NaCl/CMakeLists.txt b/lib/Bitcode/NaCl/CMakeLists.txt new file mode 100644 index 0000000000..5a8b272bef --- /dev/null +++ b/lib/Bitcode/NaCl/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(Writer) +add_subdirectory(Reader) diff --git a/lib/Bitcode/NaCl/LLVMBuild.txt b/lib/Bitcode/NaCl/LLVMBuild.txt new file mode 100644 index 0000000000..a29928d2a0 --- /dev/null +++ b/lib/Bitcode/NaCl/LLVMBuild.txt @@ -0,0 +1,24 @@ +;===- ./lib/Bitcode/NaCl/LLVMBuild.txt ------------------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[common] +subdirectories = Writer Reader + +[component_0] +type = Group +name = NaClBitcode +parent = Bitcode diff --git a/lib/Bitcode/NaCl/Makefile b/lib/Bitcode/NaCl/Makefile new file mode 100644 index 0000000000..5bbbc351a1 --- /dev/null +++ b/lib/Bitcode/NaCl/Makefile @@ -0,0 +1,14 @@ +##===- lib/Bitcode/NaCl/Makefile ---------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../.. +PARALLEL_DIRS = Writer Reader + +include $(LEVEL)/Makefile.common + diff --git a/lib/Bitcode/NaCl/Reader/CMakeLists.txt b/lib/Bitcode/NaCl/Reader/CMakeLists.txt new file mode 100644 index 0000000000..9e4de723c1 --- /dev/null +++ b/lib/Bitcode/NaCl/Reader/CMakeLists.txt @@ -0,0 +1,7 @@ +add_llvm_library(LLVMNaClBitReader + NaClBitcodeHeader.cpp + NaClBitcodeReader.cpp + NaClBitstreamReader.cpp + ) + +add_dependencies(LLVMNaClBitReader intrinsics_gen) diff --git a/lib/Bitcode/NaCl/Reader/LLVMBuild.txt b/lib/Bitcode/NaCl/Reader/LLVMBuild.txt new file mode 100644 index 0000000000..acf354f5b5 --- /dev/null +++ b/lib/Bitcode/NaCl/Reader/LLVMBuild.txt @@ -0,0 +1,22 @@ +;===- ./lib/Bitcode/NaClReader/LLVMBuild.txt -------------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Library +name = NaClBitReader +parent = NaClBitcode +required_libraries = Core Support diff --git a/lib/Bitcode/NaCl/Reader/Makefile b/lib/Bitcode/NaCl/Reader/Makefile new file mode 100644 index 0000000000..92c75c29a4 --- /dev/null +++ b/lib/Bitcode/NaCl/Reader/Makefile @@ -0,0 +1,15 @@ +##===- lib/Bitcode/NaCl/Reader/Makefile --------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../../.. +LIBRARYNAME = LLVMNaClBitReader +BUILD_ARCHIVE = 1 + +include $(LEVEL)/Makefile.common + diff --git a/lib/Bitcode/NaCl/Reader/NaClBitcodeHeader.cpp b/lib/Bitcode/NaCl/Reader/NaClBitcodeHeader.cpp new file mode 100644 index 0000000000..aa73b9cffa --- /dev/null +++ b/lib/Bitcode/NaCl/Reader/NaClBitcodeHeader.cpp @@ -0,0 +1,261 @@ +//===- 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/Bitcode/NaCl/NaClReaderWriter.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/StreamableMemoryObject.h" + +#include <limits> +#include <cstring> +#include <iomanip> + +using namespace llvm; + +NaClBitcodeHeaderField::NaClBitcodeHeaderField() + : ID(kInvalid), FType(kBufferType), Len(0), Data(0) {} + +NaClBitcodeHeaderField::NaClBitcodeHeaderField(Tag MyID, uint32_t MyValue) + : ID(MyID), FType(kUInt32Type), Len(4), Data(new uint8_t[4]) { + 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]) { + 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); + switch (ID) { + case kPNaClVersion: + ss << "PNaCl Version"; + break; + case kInvalid: + ss << "Invalid"; + break; + default: + report_fatal_error("PNaCl bitcode file contains unknown field tag"); + } + ss << ": "; + switch (FType) { + 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; + default: + report_fatal_error("PNaCL bitcode file contains unknown field type"); + } + 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)) + return true; + BufPtr += WordSize; + + // Read #Fields and number of bytes needed for the header. + if (BufPtr + WordSize > BufEnd) + return true; + 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 true; + 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; + BufPtr += 2 * WordSize; + + if (ReadFields(BufPtr, BufEnd, NumFields, NumBytes)) + return true; + BufPtr += NumBytes; + InstallFields(); + return false; +} + +bool NaClBitcodeHeader::Read(StreamableMemoryObject *Bytes) { + unsigned NumFields; + unsigned NumBytes; + { + unsigned char Buffer[2 * WordSize]; + if (Bytes->readBytes(0, sizeof(Buffer), Buffer, NULL) || + ReadPrefix(Buffer, Buffer + sizeof(Buffer), NumFields, NumBytes)) + return true; + } + uint8_t *Header = new uint8_t[NumBytes]; + bool failed = + Bytes->readBytes(2 * WordSize, NumBytes, Header, NULL) || + ReadFields(Header, Header + NumBytes, NumFields, NumBytes); + delete[] Header; + if (failed) + return true; + 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() { + // Assume supported until contradicted. + bool UpdatedUnsupportedMessage = false; + IsSupportedFlag = true; + IsReadableFlag = true; + UnsupportedMessage = "Supported"; + PNaClVersion = 0; + if (NaClBitcodeHeaderField *Version = GetPNaClVersionPtr(this)) { + PNaClVersion = Version->GetUInt32Value(); + } + if (PNaClVersion != 1) { + IsSupportedFlag = false; + IsReadableFlag = false; + UnsupportedMessage = "Unsupported Version"; + UpdatedUnsupportedMessage = true; + } + if (Fields.size() != 1) { + IsSupportedFlag = false; + IsReadableFlag = false; + if (!UpdatedUnsupportedMessage) + UnsupportedMessage = "Unknown header field(s) found"; + } +} diff --git a/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp b/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp new file mode 100644 index 0000000000..5f14a639ba --- /dev/null +++ b/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp @@ -0,0 +1,2644 @@ +//===- NaClBitcodeReader.cpp ----------------------------------------------===// +// Internal NaClBitcodeReader implementation +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "NaClBitcodeReader" + +#include "llvm/Bitcode/NaCl/NaClReaderWriter.h" +#include "NaClBitcodeReader.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/AutoUpgrade.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/InlineAsm.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/OperandTraits.h" +#include "llvm/IR/Operator.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/DataStream.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/MemoryBuffer.h" +using namespace llvm; + +enum { + SWITCH_INST_MAGIC = 0x4B5 // May 2012 => 1205 => Hex +}; + +void NaClBitcodeReader::materializeForwardReferencedFunctions() { + while (!BlockAddrFwdRefs.empty()) { + Function *F = BlockAddrFwdRefs.begin()->first; + F->Materialize(); + } +} + +void NaClBitcodeReader::FreeState() { + if (BufferOwned) + delete Buffer; + Buffer = 0; + std::vector<Type*>().swap(TypeList); + ValueList.clear(); + + std::vector<BasicBlock*>().swap(FunctionBBs); + std::vector<Function*>().swap(FunctionsWithBodies); + DeferredFunctionInfo.clear(); + + assert(BlockAddrFwdRefs.empty() && "Unresolved blockaddress fwd references"); +} + +//===----------------------------------------------------------------------===// +// Helper functions to implement forward reference resolution, etc. +//===----------------------------------------------------------------------===// + +/// ConvertToString - Convert a string from a record into an std::string, return +/// true on failure. +template<typename StrTy> +static bool ConvertToString(ArrayRef<uint64_t> Record, unsigned Idx, + StrTy &Result) { + if (Idx > Record.size()) + return true; + + for (unsigned i = Idx, e = Record.size(); i != e; ++i) + Result += (char)Record[i]; + return false; +} + +static GlobalValue::LinkageTypes GetDecodedLinkage(unsigned Val) { + switch (Val) { + default: // Map unknown/new linkages to external + case 0: return GlobalValue::ExternalLinkage; + case 1: return GlobalValue::WeakAnyLinkage; + case 2: return GlobalValue::AppendingLinkage; + case 3: return GlobalValue::InternalLinkage; + case 4: return GlobalValue::LinkOnceAnyLinkage; + case 5: return GlobalValue::DLLImportLinkage; + case 6: return GlobalValue::DLLExportLinkage; + case 7: return GlobalValue::ExternalWeakLinkage; + case 8: return GlobalValue::CommonLinkage; + case 9: return GlobalValue::PrivateLinkage; + case 10: return GlobalValue::WeakODRLinkage; + case 11: return GlobalValue::LinkOnceODRLinkage; + case 12: return GlobalValue::AvailableExternallyLinkage; + case 13: return GlobalValue::LinkerPrivateLinkage; + case 14: return GlobalValue::LinkerPrivateWeakLinkage; + case 15: return GlobalValue::LinkOnceODRAutoHideLinkage; + } +} + +static GlobalValue::VisibilityTypes GetDecodedVisibility(unsigned Val) { + switch (Val) { + default: // Map unknown visibilities to default. + case 0: return GlobalValue::DefaultVisibility; + case 1: return GlobalValue::HiddenVisibility; + case 2: return GlobalValue::ProtectedVisibility; + } +} + +static int GetDecodedCastOpcode(unsigned Val) { + switch (Val) { + default: return -1; + case naclbitc::CAST_TRUNC : return Instruction::Trunc; + case naclbitc::CAST_ZEXT : return Instruction::ZExt; + case naclbitc::CAST_SEXT : return Instruction::SExt; + case naclbitc::CAST_FPTOUI : return Instruction::FPToUI; + case naclbitc::CAST_FPTOSI : return Instruction::FPToSI; + case naclbitc::CAST_UITOFP : return Instruction::UIToFP; + case naclbitc::CAST_SITOFP : return Instruction::SIToFP; + case naclbitc::CAST_FPTRUNC : return Instruction::FPTrunc; + case naclbitc::CAST_FPEXT : return Instruction::FPExt; + case naclbitc::CAST_PTRTOINT: return Instruction::PtrToInt; + case naclbitc::CAST_INTTOPTR: return Instruction::IntToPtr; + case naclbitc::CAST_BITCAST : return Instruction::BitCast; + } +} +static int GetDecodedBinaryOpcode(unsigned Val, Type *Ty) { + switch (Val) { + default: return -1; + case naclbitc::BINOP_ADD: + return Ty->isFPOrFPVectorTy() ? Instruction::FAdd : Instruction::Add; + case naclbitc::BINOP_SUB: + return Ty->isFPOrFPVectorTy() ? Instruction::FSub : Instruction::Sub; + case naclbitc::BINOP_MUL: + return Ty->isFPOrFPVectorTy() ? Instruction::FMul : Instruction::Mul; + case naclbitc::BINOP_UDIV: return Instruction::UDiv; + case naclbitc::BINOP_SDIV: + return Ty->isFPOrFPVectorTy() ? Instruction::FDiv : Instruction::SDiv; + case naclbitc::BINOP_UREM: return Instruction::URem; + case naclbitc::BINOP_SREM: + return Ty->isFPOrFPVectorTy() ? Instruction::FRem : Instruction::SRem; + case naclbitc::BINOP_SHL: return Instruction::Shl; + case naclbitc::BINOP_LSHR: return Instruction::LShr; + case naclbitc::BINOP_ASHR: return Instruction::AShr; + case naclbitc::BINOP_AND: return Instruction::And; + case naclbitc::BINOP_OR: return Instruction::Or; + case naclbitc::BINOP_XOR: return Instruction::Xor; + } +} + +static AtomicRMWInst::BinOp GetDecodedRMWOperation(unsigned Val) { + switch (Val) { + default: return AtomicRMWInst::BAD_BINOP; + case naclbitc::RMW_XCHG: return AtomicRMWInst::Xchg; + case naclbitc::RMW_ADD: return AtomicRMWInst::Add; + case naclbitc::RMW_SUB: return AtomicRMWInst::Sub; + case naclbitc::RMW_AND: return AtomicRMWInst::And; + case naclbitc::RMW_NAND: return AtomicRMWInst::Nand; + case naclbitc::RMW_OR: return AtomicRMWInst::Or; + case naclbitc::RMW_XOR: return AtomicRMWInst::Xor; + case naclbitc::RMW_MAX: return AtomicRMWInst::Max; + case naclbitc::RMW_MIN: return AtomicRMWInst::Min; + case naclbitc::RMW_UMAX: return AtomicRMWInst::UMax; + case naclbitc::RMW_UMIN: return AtomicRMWInst::UMin; + } +} + +static AtomicOrdering GetDecodedOrdering(unsigned Val) { + switch (Val) { + case naclbitc::ORDERING_NOTATOMIC: return NotAtomic; + case naclbitc::ORDERING_UNORDERED: return Unordered; + case naclbitc::ORDERING_MONOTONIC: return Monotonic; + case naclbitc::ORDERING_ACQUIRE: return Acquire; + case naclbitc::ORDERING_RELEASE: return Release; + case naclbitc::ORDERING_ACQREL: return AcquireRelease; + default: // Map unknown orderings to sequentially-consistent. + case naclbitc::ORDERING_SEQCST: return SequentiallyConsistent; + } +} + +static SynchronizationScope GetDecodedSynchScope(unsigned Val) { + switch (Val) { + case naclbitc::SYNCHSCOPE_SINGLETHREAD: return SingleThread; + default: // Map unknown scopes to cross-thread. + case naclbitc::SYNCHSCOPE_CROSSTHREAD: return CrossThread; + } +} + +static CallingConv::ID GetDecodedCallingConv(unsigned Val) { + switch (Val) { + default: + report_fatal_error("PNaCl bitcode contains invalid calling conventions."); + case naclbitc::C_CallingConv: return CallingConv::C; + } +} + +namespace llvm { +namespace { + /// @brief A class for maintaining the slot number definition + /// as a placeholder for the actual definition for forward constants defs. + class ConstantPlaceHolder : public ConstantExpr { + void operator=(const ConstantPlaceHolder &) LLVM_DELETED_FUNCTION; + public: + // allocate space for exactly one operand + void *operator new(size_t s) { + return User::operator new(s, 1); + } + explicit ConstantPlaceHolder(Type *Ty, LLVMContext& Context) + : ConstantExpr(Ty, Instruction::UserOp1, &Op<0>(), 1) { + Op<0>() = UndefValue::get(Type::getInt32Ty(Context)); + } + + /// @brief Methods to support type inquiry through isa, cast, and dyn_cast. + static bool classof(const Value *V) { + return isa<ConstantExpr>(V) && + cast<ConstantExpr>(V)->getOpcode() == Instruction::UserOp1; + } + + + /// Provide fast operand accessors + //DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); + }; +} + +// FIXME: can we inherit this from ConstantExpr? +template <> +struct OperandTraits<ConstantPlaceHolder> : + public FixedNumOperandTraits<ConstantPlaceHolder, 1> { +}; +} + + +void NaClBitcodeReaderValueList::AssignValue(Value *V, unsigned Idx) { + assert(V); + if (Idx == size()) { + push_back(V); + return; + } + + if (Idx >= size()) + resize(Idx+1); + + WeakVH &OldV = ValuePtrs[Idx]; + if (OldV == 0) { + OldV = V; + return; + } + + // Handle constants and non-constants (e.g. instrs) differently for + // efficiency. + if (Constant *PHC = dyn_cast<Constant>(&*OldV)) { + ResolveConstants.push_back(std::make_pair(PHC, Idx)); + OldV = V; + } else { + // If there was a forward reference to this value, replace it. + Value *PrevVal = OldV; + OldV->replaceAllUsesWith(V); + delete PrevVal; + } +} + +void NaClBitcodeReaderValueList::AssignGlobalVar(GlobalVariable *GV, + unsigned Idx) { + assert(GV); + + if (Idx == size()) { + push_back(GV); + return; + } + + if (Idx >= size()) + resize(Idx+1); + + WeakVH &OldV = ValuePtrs[Idx]; + if (OldV == 0) { + OldV = GV; + return; + } + + // If there was a forward reference to this value, replace it. + Value *PrevVal = OldV; + GlobalVariable *Placeholder = cast<GlobalVariable>(PrevVal); + Placeholder->replaceAllUsesWith( + ConstantExpr::getBitCast(GV, Placeholder->getType())); + Placeholder->eraseFromParent(); + ValuePtrs[Idx] = GV; +} + +Constant *NaClBitcodeReaderValueList::getConstantFwdRef(unsigned Idx, + Type *Ty) { + if (Idx >= size()) + resize(Idx + 1); + + if (Value *V = ValuePtrs[Idx]) { + assert(Ty == V->getType() && "Type mismatch in constant table!"); + return cast<Constant>(V); + } + + // Create and return a placeholder, which will later be RAUW'd. + Constant *C = new ConstantPlaceHolder(Ty, Context); + ValuePtrs[Idx] = C; + return C; +} + +Value *NaClBitcodeReaderValueList::getValueFwdRef(unsigned Idx) { + if (Idx >= size()) + return 0; + + if (Value *V = ValuePtrs[Idx]) + return V; + + return 0; +} + +bool NaClBitcodeReaderValueList::createValueFwdRef(unsigned Idx, Type *Ty) { + if (Idx >= size()) + resize(Idx + 1); + + // Return an error if this a duplicate definition of Idx. + if (ValuePtrs[Idx]) + return true; + + // No type specified, must be invalid reference. + if (Ty == 0) + return true; + + // Create a placeholder, which will later be RAUW'd. + ValuePtrs[Idx] = new Argument(Ty); + return false; +} + +Constant *NaClBitcodeReaderValueList::getOrCreateGlobalVarRef( + unsigned Idx, Module *M) { + // First make sure the element for Idx is defined. + if (Idx >= size()) + resize(Idx + 1); + + // Now get its value (if applicable). + if (Value *V = ValuePtrs[Idx]) + return dyn_cast<Constant>(V); + + // Create a placeholder, which will later be RAUW'd. + Type *PlaceholderType = Type::getInt8Ty(Context); + + Constant *C = + new GlobalVariable(*M, PlaceholderType, false, + GlobalValue::ExternalLinkage, 0); + ValuePtrs[Idx] = C; + return C; +} + +/// ResolveConstantForwardRefs - Once all constants are read, this method bulk +/// resolves any forward references. The idea behind this is that we sometimes +/// get constants (such as large arrays) which reference *many* forward ref +/// constants. Replacing each of these causes a lot of thrashing when +/// building/reuniquing the constant. Instead of doing this, we look at all the +/// uses and rewrite all the place holders at once for any constant that uses +/// a placeholder. +void NaClBitcodeReaderValueList::ResolveConstantForwardRefs() { + // Sort the values by-pointer so that they are efficient to look up with a + // binary search. + std::sort(ResolveConstants.begin(), ResolveConstants.end()); + + SmallVector<Constant*, 64> NewOps; + + while (!ResolveConstants.empty()) { + Value *RealVal = operator[](ResolveConstants.back().second); + Constant *Placeholder = ResolveConstants.back().first; + ResolveConstants.pop_back(); + + // Loop over all users of the placeholder, updating them to reference the + // new value. If they reference more than one placeholder, update them all + // at once. + while (!Placeholder->use_empty()) { + Value::use_iterator UI = Placeholder->use_begin(); + User *U = *UI; + + // If the using object isn't uniqued, just update the operands. This + // handles instructions and initializers for global variables. + if (!isa<Constant>(U) || isa<GlobalValue>(U)) { + UI.getUse().set(RealVal); + continue; + } + + // Otherwise, we have a constant that uses the placeholder. Replace that + // constant with a new constant that has *all* placeholder uses updated. + Constant *UserC = cast<Constant>(U); + for (User::op_iterator I = UserC->op_begin(), E = UserC->op_end(); + I != E; ++I) { + Value *NewOp; + if (!isa<ConstantPlaceHolder>(*I)) { + // Not a placeholder reference. + NewOp = *I; + } else if (*I == Placeholder) { + // Common case is that it just references this one placeholder. + NewOp = RealVal; + } else { + // Otherwise, look up the placeholder in ResolveConstants. + ResolveConstantsTy::iterator It = + std::lower_bound(ResolveConstants.begin(), ResolveConstants.end(), + std::pair<Constant*, unsigned>(cast<Constant>(*I), + 0)); + assert(It != ResolveConstants.end() && It->first == *I); + NewOp = operator[](It->second); + } + + NewOps.push_back(cast<Constant>(NewOp)); + } + + // Make the new constant. + Constant *NewC; + if (ConstantArray *UserCA = dyn_cast<ConstantArray>(UserC)) { + NewC = ConstantArray::get(UserCA->getType(), NewOps); + } else if (ConstantStruct *UserCS = dyn_cast<ConstantStruct>(UserC)) { + NewC = ConstantStruct::get(UserCS->getType(), NewOps); + } else if (isa<ConstantVector>(UserC)) { + NewC = ConstantVector::get(NewOps); + } else { + assert(isa<ConstantExpr>(UserC) && "Must be a ConstantExpr."); + NewC = cast<ConstantExpr>(UserC)->getWithOperands(NewOps); + } + + UserC->replaceAllUsesWith(NewC); + UserC->destroyConstant(); + NewOps.clear(); + } + + // Update all ValueHandles, they should be the only users at this point. + Placeholder->replaceAllUsesWith(RealVal); + delete Placeholder; + } +} + +Type *NaClBitcodeReader::getTypeByID(unsigned ID) { + // The type table size is always specified correctly. + if (ID >= TypeList.size()) + return 0; + + if (Type *Ty = TypeList[ID]) + return Ty; + + // If we have a forward reference, the only possible case is when it is to a + // named struct. Just create a placeholder for now. + return TypeList[ID] = StructType::create(Context); +} + + +//===----------------------------------------------------------------------===// +// Functions for parsing blocks from the bitcode file +//===----------------------------------------------------------------------===// + + +bool NaClBitcodeReader::ParseTypeTable() { + DEBUG(dbgs() << "-> ParseTypeTable\n"); + if (Stream.EnterSubBlock(naclbitc::TYPE_BLOCK_ID_NEW)) + return Error("Malformed block record"); + + bool result = ParseTypeTableBody(); + if (!result) + DEBUG(dbgs() << "<- ParseTypeTable\n"); + return result; +} + +bool NaClBitcodeReader::ParseTypeTableBody() { + if (!TypeList.empty()) + return Error("Multiple TYPE_BLOCKs found!"); |