forked from OSchip/llvm-project
Remove files no longer needed. ConstantReader and InstructionReader were
integrated into Reader. Parser.* was just a bad idea. AnalyzerInternals.h is no longer needed. ReaderPrimitives.h was integrated into Reader.h and Reader.cpp. Dumper.cpp was integrated into Analyzer.cpp. ReaderInternals.h became Reader.h. AnalyzerWrappers.cpp was integerated into ReaderWrappers.cpp llvm-svn: 14496
This commit is contained in:
parent
f4ec6383c0
commit
fddebf7ff2
|
@ -1,51 +0,0 @@
|
|||
//===-- ReaderInternals.h - Definitions internal to the reader --*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by the LLVM research group and is distributed under
|
||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This header file defines various stuff that is used by the bytecode reader.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef ANALYZER_INTERNALS_H
|
||||
#define ANALYZER_INTERNALS_H
|
||||
|
||||
#include "Parser.h"
|
||||
#include "llvm/Bytecode/Analyzer.h"
|
||||
#include "llvm/Constants.h"
|
||||
#include "llvm/DerivedTypes.h"
|
||||
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class BytecodeAnalyzer {
|
||||
BytecodeAnalyzer(const BytecodeAnalyzer &); // DO NOT IMPLEMENT
|
||||
void operator=(const BytecodeAnalyzer &); // DO NOT IMPLEMENT
|
||||
public:
|
||||
BytecodeAnalyzer() { }
|
||||
~BytecodeAnalyzer() { }
|
||||
|
||||
void AnalyzeBytecode(
|
||||
const unsigned char *Buf,
|
||||
unsigned Length,
|
||||
BytecodeAnalysis& bca,
|
||||
const std::string &ModuleID
|
||||
);
|
||||
|
||||
void DumpBytecode(
|
||||
const unsigned char *Buf,
|
||||
unsigned Length,
|
||||
BytecodeAnalysis& bca,
|
||||
const std::string &ModuleID
|
||||
);
|
||||
};
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
||||
|
||||
// vim: sw=2
|
|
@ -1,332 +0,0 @@
|
|||
//===- AnalyzerWrappers.cpp - Analyze bytecode from file or buffer -------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by Reid Spencer and is distributed under the
|
||||
// University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements loading and analysis of a bytecode file and analyzing a
|
||||
// bytecode buffer.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Bytecode/Analyzer.h"
|
||||
#include "AnalyzerInternals.h"
|
||||
#include "Support/FileUtilities.h"
|
||||
#include "Support/StringExtras.h"
|
||||
#include "Config/unistd.h"
|
||||
#include <cerrno>
|
||||
#include <iomanip>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// BytecodeFileAnalyzer - Analyze from an mmap'able file descriptor.
|
||||
//
|
||||
|
||||
namespace {
|
||||
/// BytecodeFileAnalyzer - parses a bytecode file from a file
|
||||
class BytecodeFileAnalyzer : public BytecodeAnalyzer {
|
||||
private:
|
||||
unsigned char *Buffer;
|
||||
unsigned Length;
|
||||
|
||||
BytecodeFileAnalyzer(const BytecodeFileAnalyzer&); // Do not implement
|
||||
void operator=(const BytecodeFileAnalyzer &BFR); // Do not implement
|
||||
|
||||
public:
|
||||
BytecodeFileAnalyzer(const std::string &Filename, BytecodeAnalysis& bca);
|
||||
~BytecodeFileAnalyzer();
|
||||
};
|
||||
}
|
||||
|
||||
static std::string ErrnoMessage (int savedErrNum, std::string descr) {
|
||||
return ::strerror(savedErrNum) + std::string(", while trying to ") + descr;
|
||||
}
|
||||
|
||||
BytecodeFileAnalyzer::BytecodeFileAnalyzer(const std::string &Filename,
|
||||
BytecodeAnalysis& bca) {
|
||||
Buffer = (unsigned char*)ReadFileIntoAddressSpace(Filename, Length);
|
||||
if (Buffer == 0)
|
||||
throw "Error reading file '" + Filename + "'.";
|
||||
|
||||
try {
|
||||
// Parse the bytecode we mmapped in
|
||||
if ( bca.dumpBytecode )
|
||||
DumpBytecode(Buffer, Length, bca, Filename);
|
||||
AnalyzeBytecode(Buffer, Length, bca, Filename);
|
||||
} catch (...) {
|
||||
UnmapFileFromAddressSpace(Buffer, Length);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
BytecodeFileAnalyzer::~BytecodeFileAnalyzer() {
|
||||
// Unmmap the bytecode...
|
||||
UnmapFileFromAddressSpace(Buffer, Length);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// BytecodeBufferAnalyzer - Read from a memory buffer
|
||||
//
|
||||
|
||||
namespace {
|
||||
/// BytecodeBufferAnalyzer - parses a bytecode file from a buffer
|
||||
///
|
||||
class BytecodeBufferAnalyzer : public BytecodeAnalyzer {
|
||||
private:
|
||||
const unsigned char *Buffer;
|
||||
bool MustDelete;
|
||||
|
||||
BytecodeBufferAnalyzer(const BytecodeBufferAnalyzer&); // Do not implement
|
||||
void operator=(const BytecodeBufferAnalyzer &BFR); // Do not implement
|
||||
|
||||
public:
|
||||
BytecodeBufferAnalyzer(const unsigned char *Buf, unsigned Length,
|
||||
BytecodeAnalysis& bca, const std::string &ModuleID);
|
||||
~BytecodeBufferAnalyzer();
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
BytecodeBufferAnalyzer::BytecodeBufferAnalyzer(const unsigned char *Buf,
|
||||
unsigned Length,
|
||||
BytecodeAnalysis& bca,
|
||||
const std::string &ModuleID) {
|
||||
// If not aligned, allocate a new buffer to hold the bytecode...
|
||||
const unsigned char *ParseBegin = 0;
|
||||
if ((intptr_t)Buf & 3) {
|
||||
Buffer = new unsigned char[Length+4];
|
||||
unsigned Offset = 4 - ((intptr_t)Buffer & 3); // Make sure it's aligned
|
||||
ParseBegin = Buffer + Offset;
|
||||
memcpy((unsigned char*)ParseBegin, Buf, Length); // Copy it over
|
||||
MustDelete = true;
|
||||
} else {
|
||||
// If we don't need to copy it over, just use the caller's copy
|
||||
ParseBegin = Buffer = Buf;
|
||||
MustDelete = false;
|
||||
}
|
||||
try {
|
||||
if ( bca.dumpBytecode )
|
||||
DumpBytecode(ParseBegin, Length, bca, ModuleID);
|
||||
AnalyzeBytecode(ParseBegin, Length, bca, ModuleID);
|
||||
} catch (...) {
|
||||
if (MustDelete) delete [] Buffer;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
BytecodeBufferAnalyzer::~BytecodeBufferAnalyzer() {
|
||||
if (MustDelete) delete [] Buffer;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// BytecodeStdinAnalyzer - Read bytecode from Standard Input
|
||||
//
|
||||
|
||||
namespace {
|
||||
/// BytecodeStdinAnalyzer - parses a bytecode file from stdin
|
||||
///
|
||||
class BytecodeStdinAnalyzer : public BytecodeAnalyzer {
|
||||
private:
|
||||
std::vector<unsigned char> FileData;
|
||||
unsigned char *FileBuf;
|
||||
|
||||
BytecodeStdinAnalyzer(const BytecodeStdinAnalyzer&); // Do not implement
|
||||
void operator=(const BytecodeStdinAnalyzer &BFR); // Do not implement
|
||||
|
||||
public:
|
||||
BytecodeStdinAnalyzer(BytecodeAnalysis& bca);
|
||||
};
|
||||
}
|
||||
|
||||
BytecodeStdinAnalyzer::BytecodeStdinAnalyzer(BytecodeAnalysis& bca ) {
|
||||
int BlockSize;
|
||||
unsigned char Buffer[4096*4];
|
||||
|
||||
// Read in all of the data from stdin, we cannot mmap stdin...
|
||||
while ((BlockSize = ::read(0 /*stdin*/, Buffer, 4096*4))) {
|
||||
if (BlockSize == -1)
|
||||
throw ErrnoMessage(errno, "read from standard input");
|
||||
|
||||
FileData.insert(FileData.end(), Buffer, Buffer+BlockSize);
|
||||
}
|
||||
|
||||
if (FileData.empty())
|
||||
throw std::string("Standard Input empty!");
|
||||
|
||||
FileBuf = &FileData[0];
|
||||
if (bca.dumpBytecode)
|
||||
DumpBytecode(&FileData[0], FileData.size(), bca, "<stdin>");
|
||||
AnalyzeBytecode(FileBuf, FileData.size(), bca, "<stdin>");
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Wrapper functions
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// AnalyzeBytecodeFile - analyze one file
|
||||
void llvm::AnalyzeBytecodeFile(const std::string &Filename,
|
||||
BytecodeAnalysis& bca,
|
||||
std::string *ErrorStr)
|
||||
{
|
||||
try {
|
||||
if ( Filename != "-" )
|
||||
BytecodeFileAnalyzer bfa(Filename,bca);
|
||||
else
|
||||
BytecodeStdinAnalyzer bsa(bca);
|
||||
} catch (std::string &err) {
|
||||
if (ErrorStr) *ErrorStr = err;
|
||||
}
|
||||
}
|
||||
|
||||
// AnalyzeBytecodeBuffer - analyze a buffer
|
||||
void llvm::AnalyzeBytecodeBuffer(
|
||||
const unsigned char* Buffer, ///< Pointer to start of bytecode buffer
|
||||
unsigned BufferSize, ///< Size of the bytecode buffer
|
||||
BytecodeAnalysis& Results, ///< The results of the analysis
|
||||
std::string* ErrorStr ///< Errors, if any.
|
||||
)
|
||||
{
|
||||
try {
|
||||
BytecodeBufferAnalyzer(Buffer, BufferSize, Results, "<buffer>" );
|
||||
} catch (std::string& err ) {
|
||||
if ( ErrorStr) *ErrorStr = err;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// This function prints the contents of rhe BytecodeAnalysis structure in
|
||||
/// a human legible form.
|
||||
/// @brief Print BytecodeAnalysis structure to an ostream
|
||||
namespace {
|
||||
inline static void print(std::ostream& Out, const char*title,
|
||||
unsigned val, bool nl = true ) {
|
||||
Out << std::setw(30) << std::right << title
|
||||
<< std::setw(0) << ": "
|
||||
<< std::setw(9) << val << "\n";
|
||||
}
|
||||
|
||||
inline static void print(std::ostream&Out, const char*title,
|
||||
double val ) {
|
||||
Out << std::setw(30) << std::right << title
|
||||
<< std::setw(0) << ": "
|
||||
<< std::setw(9) << std::setprecision(6) << val << "\n" ;
|
||||
}
|
||||
|
||||
inline static void print(std::ostream&Out, const char*title,
|
||||
double top, double bot ) {
|
||||
Out << std::setw(30) << std::right << title
|
||||
<< std::setw(0) << ": "
|
||||
<< std::setw(9) << std::setprecision(6) << top
|
||||
<< " (" << std::left << std::setw(0) << std::setprecision(4)
|
||||
<< (top/bot)*100.0 << "%)\n";
|
||||
}
|
||||
inline static void print(std::ostream&Out, const char*title,
|
||||
std::string val, bool nl = true) {
|
||||
Out << std::setw(30) << std::right << title
|
||||
<< std::setw(0) << ": "
|
||||
<< std::left << val << (nl ? "\n" : "");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void llvm::PrintBytecodeAnalysis(BytecodeAnalysis& bca, std::ostream& Out )
|
||||
{
|
||||
print(Out, "Bytecode Analysis Of Module", bca.ModuleId);
|
||||
print(Out, "File Size", bca.byteSize);
|
||||
print(Out, "Bytecode Compression Index",std::string("TBD"));
|
||||
print(Out, "Number Of Bytecode Blocks", bca.numBlocks);
|
||||
print(Out, "Number Of Types", bca.numTypes);
|
||||
print(Out, "Number Of Values", bca.numValues);
|
||||
print(Out, "Number Of Constants", bca.numConstants);
|
||||
print(Out, "Number Of Global Variables", bca.numGlobalVars);
|
||||
print(Out, "Number Of Functions", bca.numFunctions);
|
||||
print(Out, "Number Of Basic Blocks", bca.numBasicBlocks);
|
||||
print(Out, "Number Of Instructions", bca.numInstructions);
|
||||
print(Out, "Number Of Operands", bca.numOperands);
|
||||
print(Out, "Number Of Compaction Tables", bca.numCmpctnTables);
|
||||
print(Out, "Number Of Symbol Tables", bca.numSymTab);
|
||||
print(Out, "Long Instructions", bca.longInstructions);
|
||||
print(Out, "Instruction Size", bca.instructionSize);
|
||||
print(Out, "Average Instruction Size",
|
||||
double(bca.instructionSize)/double(bca.numInstructions));
|
||||
print(Out, "Maximum Type Slot Number", bca.maxTypeSlot);
|
||||
print(Out, "Maximum Value Slot Number", bca.maxValueSlot);
|
||||
print(Out, "Bytes Thrown To Alignment", double(bca.numAlignment),
|
||||
double(bca.byteSize));
|
||||
print(Out, "File Density (bytes/def)", bca.fileDensity);
|
||||
print(Out, "Globals Density (bytes/def)", bca.globalsDensity);
|
||||
print(Out, "Function Density (bytes/func)", bca.functionDensity);
|
||||
print(Out, "Number of VBR 32-bit Integers", bca.vbrCount32);
|
||||
print(Out, "Number of VBR 64-bit Integers", bca.vbrCount64);
|
||||
print(Out, "Number of VBR Compressed Bytes", bca.vbrCompBytes);
|
||||
print(Out, "Number of VBR Expanded Bytes", bca.vbrExpdBytes);
|
||||
print(Out, "VBR Savings",
|
||||
double(bca.vbrExpdBytes)-double(bca.vbrCompBytes),
|
||||
double(bca.byteSize));
|
||||
|
||||
if ( bca.detailedResults ) {
|
||||
print(Out, "Module Bytes",
|
||||
double(bca.BlockSizes[BytecodeFormat::Module]),
|
||||
double(bca.byteSize));
|
||||
print(Out, "Function Bytes",
|
||||
double(bca.BlockSizes[BytecodeFormat::Function]),
|
||||
double(bca.byteSize));
|
||||
print(Out, "Constant Pool Bytes",
|
||||
double(bca.BlockSizes[BytecodeFormat::ConstantPool]),
|
||||
double(bca.byteSize));
|
||||
print(Out, "Symbol Table Bytes",
|
||||
double(bca.BlockSizes[BytecodeFormat::SymbolTable]),
|
||||
double(bca.byteSize));
|
||||
print(Out, "Module Global Info Bytes",
|
||||
double(bca.BlockSizes[BytecodeFormat::ModuleGlobalInfo]),
|
||||
double(bca.byteSize));
|
||||
print(Out, "Global Type Plane Bytes",
|
||||
double(bca.BlockSizes[BytecodeFormat::GlobalTypePlane]),
|
||||
double(bca.byteSize));
|
||||
print(Out, "Basic Block Bytes",
|
||||
double(bca.BlockSizes[BytecodeFormat::BasicBlock]),
|
||||
double(bca.byteSize));
|
||||
print(Out, "Instruction List Bytes",
|
||||
double(bca.BlockSizes[BytecodeFormat::InstructionList]),
|
||||
double(bca.byteSize));
|
||||
print(Out, "Compaction Table Bytes",
|
||||
double(bca.BlockSizes[BytecodeFormat::CompactionTable]),
|
||||
double(bca.byteSize));
|
||||
|
||||
std::map<const Function*,BytecodeAnalysis::BytecodeFunctionInfo>::iterator I =
|
||||
bca.FunctionInfo.begin();
|
||||
std::map<const Function*,BytecodeAnalysis::BytecodeFunctionInfo>::iterator E =
|
||||
bca.FunctionInfo.end();
|
||||
|
||||
while ( I != E ) {
|
||||
Out << std::left << std::setw(0);
|
||||
Out << "Function: " << I->second.name << "\n";
|
||||
print(Out, "Type:", I->second.description);
|
||||
print(Out, "Byte Size", I->second.byteSize);
|
||||
print(Out, "Instructions", I->second.numInstructions);
|
||||
print(Out, "Long Instructions", I->second.longInstructions);
|
||||
print(Out, "Instruction Size", I->second.instructionSize);
|
||||
print(Out, "Average Instruction Size",
|
||||
double(I->second.instructionSize)/double(I->second.numInstructions));
|
||||
print(Out, "Basic Blocks", I->second.numBasicBlocks);
|
||||
print(Out, "Operand", I->second.numOperands);
|
||||
print(Out, "Function Density", I->second.density);
|
||||
print(Out, "Number of VBR 32-bit Integers", I->second.vbrCount32);
|
||||
print(Out, "Number of VBR 64-bit Integers", I->second.vbrCount64);
|
||||
print(Out, "Number of VBR Compressed Bytes", I->second.vbrCompBytes);
|
||||
print(Out, "Number of VBR Expanded Bytes", I->second.vbrExpdBytes);
|
||||
print(Out, "VBR Savings",
|
||||
double(I->second.vbrExpdBytes)-double(I->second.vbrCompBytes),
|
||||
double(I->second.byteSize));
|
||||
++I;
|
||||
}
|
||||
}
|
||||
|
||||
if ( bca.dumpBytecode )
|
||||
Out << bca.BytecodeDump;
|
||||
}
|
||||
// vim: sw=2
|
|
@ -1,362 +0,0 @@
|
|||
//===- ConstantReader.cpp - Code to constants and types ====---------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by the LLVM research group and is distributed under
|
||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements functionality to deserialize constants and types from
|
||||
// bytecode files.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ReaderInternals.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/Constants.h"
|
||||
#include "llvm/Support/GetElementPtrTypeIterator.h"
|
||||
#include <algorithm>
|
||||
using namespace llvm;
|
||||
|
||||
const Type *BytecodeParser::parseTypeConstant(const unsigned char *&Buf,
|
||||
const unsigned char *EndBuf) {
|
||||
unsigned PrimType = read_vbr_uint(Buf, EndBuf);
|
||||
|
||||
const Type *Val = 0;
|
||||
if ((Val = Type::getPrimitiveType((Type::TypeID)PrimType)))
|
||||
return Val;
|
||||
|
||||
switch (PrimType) {
|
||||
case Type::FunctionTyID: {
|
||||
const Type *RetType = getType(read_vbr_uint(Buf, EndBuf));
|
||||
|
||||
unsigned NumParams = read_vbr_uint(Buf, EndBuf);
|
||||
|
||||
std::vector<const Type*> Params;
|
||||
while (NumParams--)
|
||||
Params.push_back(getType(read_vbr_uint(Buf, EndBuf)));
|
||||
|
||||
bool isVarArg = Params.size() && Params.back() == Type::VoidTy;
|
||||
if (isVarArg) Params.pop_back();
|
||||
|
||||
return FunctionType::get(RetType, Params, isVarArg);
|
||||
}
|
||||
case Type::ArrayTyID: {
|
||||
unsigned ElTyp = read_vbr_uint(Buf, EndBuf);
|
||||
const Type *ElementType = getType(ElTyp);
|
||||
|
||||
unsigned NumElements = read_vbr_uint(Buf, EndBuf);
|
||||
|
||||
BCR_TRACE(5, "Array Type Constant #" << ElTyp << " size="
|
||||
<< NumElements << "\n");
|
||||
return ArrayType::get(ElementType, NumElements);
|
||||
}
|
||||
case Type::StructTyID: {
|
||||
std::vector<const Type*> Elements;
|
||||
unsigned Typ = read_vbr_uint(Buf, EndBuf);
|
||||
while (Typ) { // List is terminated by void/0 typeid
|
||||
Elements.push_back(getType(Typ));
|
||||
Typ = read_vbr_uint(Buf, EndBuf);
|
||||
}
|
||||
|
||||
return StructType::get(Elements);
|
||||
}
|
||||
case Type::PointerTyID: {
|
||||
unsigned ElTyp = read_vbr_uint(Buf, EndBuf);
|
||||
BCR_TRACE(5, "Pointer Type Constant #" << ElTyp << "\n");
|
||||
return PointerType::get(getType(ElTyp));
|
||||
}
|
||||
|
||||
case Type::OpaqueTyID: {
|
||||
return OpaqueType::get();
|
||||
}
|
||||
|
||||
default:
|
||||
std::cerr << __FILE__ << ":" << __LINE__
|
||||
<< ": Don't know how to deserialize"
|
||||
<< " primitive Type " << PrimType << "\n";
|
||||
return Val;
|
||||
}
|
||||
}
|
||||
|
||||
// parseTypeConstants - We have to use this weird code to handle recursive
|
||||
// types. We know that recursive types will only reference the current slab of
|
||||
// values in the type plane, but they can forward reference types before they
|
||||
// have been read. For example, Type #0 might be '{ Ty#1 }' and Type #1 might
|
||||
// be 'Ty#0*'. When reading Type #0, type number one doesn't exist. To fix
|
||||
// this ugly problem, we pessimistically insert an opaque type for each type we
|
||||
// are about to read. This means that forward references will resolve to
|
||||
// something and when we reread the type later, we can replace the opaque type
|
||||
// with a new resolved concrete type.
|
||||
//
|
||||
void BytecodeParser::parseTypeConstants(const unsigned char *&Buf,
|
||||
const unsigned char *EndBuf,
|
||||
TypeValuesListTy &Tab,
|
||||
unsigned NumEntries) {
|
||||
assert(Tab.size() == 0 && "should not have read type constants in before!");
|
||||
|
||||
// Insert a bunch of opaque types to be resolved later...
|
||||
Tab.reserve(NumEntries);
|
||||
for (unsigned i = 0; i != NumEntries; ++i)
|
||||
Tab.push_back(OpaqueType::get());
|
||||
|
||||
// Loop through reading all of the types. Forward types will make use of the
|
||||
// opaque types just inserted.
|
||||
//
|
||||
for (unsigned i = 0; i != NumEntries; ++i) {
|
||||
const Type *NewTy = parseTypeConstant(Buf, EndBuf), *OldTy = Tab[i].get();
|
||||
if (NewTy == 0) throw std::string("Couldn't parse type!");
|
||||
BCR_TRACE(4, "#" << i << ": Read Type Constant: '" << NewTy <<
|
||||
"' Replacing: " << OldTy << "\n");
|
||||
|
||||
// Don't insertValue the new type... instead we want to replace the opaque
|
||||
// type with the new concrete value...
|
||||
//
|
||||
|
||||
// Refine the abstract type to the new type. This causes all uses of the
|
||||
// abstract type to use NewTy. This also will cause the opaque type to be
|
||||
// deleted...
|
||||
//
|
||||
cast<DerivedType>(const_cast<Type*>(OldTy))->refineAbstractTypeTo(NewTy);
|
||||
|
||||
// This should have replace the old opaque type with the new type in the
|
||||
// value table... or with a preexisting type that was already in the system
|
||||
assert(Tab[i] != OldTy && "refineAbstractType didn't work!");
|
||||
}
|
||||
|
||||
BCR_TRACE(5, "Resulting types:\n");
|
||||
for (unsigned i = 0; i < NumEntries; ++i) {
|
||||
BCR_TRACE(5, (void*)Tab[i].get() << " - " << Tab[i].get() << "\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Constant *BytecodeParser::parseConstantValue(const unsigned char *&Buf,
|
||||
const unsigned char *EndBuf,
|
||||
unsigned TypeID) {
|
||||
|
||||
// We must check for a ConstantExpr before switching by type because
|
||||
// a ConstantExpr can be of any type, and has no explicit value.
|
||||
//
|
||||
// 0 if not expr; numArgs if is expr
|
||||
unsigned isExprNumArgs = read_vbr_uint(Buf, EndBuf);
|
||||
|
||||
if (isExprNumArgs) {
|
||||
// FIXME: Encoding of constant exprs could be much more compact!
|
||||
std::vector<Constant*> ArgVec;
|
||||
ArgVec.reserve(isExprNumArgs);
|
||||
unsigned Opcode = read_vbr_uint(Buf, EndBuf);
|
||||
|
||||
// Read the slot number and types of each of the arguments
|
||||
for (unsigned i = 0; i != isExprNumArgs; ++i) {
|
||||
unsigned ArgValSlot = read_vbr_uint(Buf, EndBuf);
|
||||
unsigned ArgTypeSlot = read_vbr_uint(Buf, EndBuf);
|
||||
BCR_TRACE(4, "CE Arg " << i << ": Type: '" << *getType(ArgTypeSlot)
|
||||
<< "' slot: " << ArgValSlot << "\n");
|
||||
|
||||
// Get the arg value from its slot if it exists, otherwise a placeholder
|
||||
ArgVec.push_back(getConstantValue(ArgTypeSlot, ArgValSlot));
|
||||
}
|
||||
|
||||
// Construct a ConstantExpr of the appropriate kind
|
||||
if (isExprNumArgs == 1) { // All one-operand expressions
|
||||
assert(Opcode == Instruction::Cast);
|
||||
return ConstantExpr::getCast(ArgVec[0], getType(TypeID));
|
||||
} else if (Opcode == Instruction::GetElementPtr) { // GetElementPtr
|
||||
std::vector<Constant*> IdxList(ArgVec.begin()+1, ArgVec.end());
|
||||
|
||||
if (hasRestrictedGEPTypes) {
|
||||
const Type *BaseTy = ArgVec[0]->getType();
|
||||
generic_gep_type_iterator<std::vector<Constant*>::iterator>
|
||||
GTI = gep_type_begin(BaseTy, IdxList.begin(), IdxList.end()),
|
||||
E = gep_type_end(BaseTy, IdxList.begin(), IdxList.end());
|
||||
for (unsigned i = 0; GTI != E; ++GTI, ++i)
|
||||
if (isa<StructType>(*GTI)) {
|
||||
if (IdxList[i]->getType() != Type::UByteTy)
|
||||
throw std::string("Invalid index for getelementptr!");
|
||||
IdxList[i] = ConstantExpr::getCast(IdxList[i], Type::UIntTy);
|
||||
}
|
||||
}
|
||||
|
||||
return ConstantExpr::getGetElementPtr(ArgVec[0], IdxList);
|
||||
} else if (Opcode == Instruction::Select) {
|
||||
assert(ArgVec.size() == 3);
|
||||
return ConstantExpr::getSelect(ArgVec[0], ArgVec[1], ArgVec[2]);
|
||||
} else { // All other 2-operand expressions
|
||||
return ConstantExpr::get(Opcode, ArgVec[0], ArgVec[1]);
|
||||
}
|
||||
}
|
||||
|
||||
// Ok, not an ConstantExpr. We now know how to read the given type...
|
||||
const Type *Ty = getType(TypeID);
|
||||
switch (Ty->getTypeID()) {
|
||||
case Type::BoolTyID: {
|
||||
unsigned Val = read_vbr_uint(Buf, EndBuf);
|
||||
if (Val != 0 && Val != 1) throw std::string("Invalid boolean value read.");
|
||||
return ConstantBool::get(Val == 1);
|
||||
}
|
||||
|
||||
case Type::UByteTyID: // Unsigned integer types...
|
||||
case Type::UShortTyID:
|
||||
case Type::UIntTyID: {
|
||||
unsigned Val = read_vbr_uint(Buf, EndBuf);
|
||||
if (!ConstantUInt::isValueValidForType(Ty, Val))
|
||||
throw std::string("Invalid unsigned byte/short/int read.");
|
||||
return ConstantUInt::get(Ty, Val);
|
||||
}
|
||||
|
||||
case Type::ULongTyID: {
|
||||
return ConstantUInt::get(Ty, read_vbr_uint64(Buf, EndBuf));
|
||||
}
|
||||
|
||||
case Type::SByteTyID: // Signed integer types...
|
||||
case Type::ShortTyID:
|
||||
case Type::IntTyID: {
|
||||
case Type::LongTyID:
|
||||
int64_t Val = read_vbr_int64(Buf, EndBuf);
|
||||
if (!ConstantSInt::isValueValidForType(Ty, Val))
|
||||
throw std::string("Invalid signed byte/short/int/long read.");
|
||||
return ConstantSInt::get(Ty, Val);
|
||||
}
|
||||
|
||||
case Type::FloatTyID: {
|
||||
float F;
|
||||
input_data(Buf, EndBuf, &F, &F+1);
|
||||
return ConstantFP::get(Ty, F);
|
||||
}
|
||||
|
||||
case Type::DoubleTyID: {
|
||||
double Val;
|
||||
input_data(Buf, EndBuf, &Val, &Val+1);
|
||||
return ConstantFP::get(Ty, Val);
|
||||
}
|
||||
|
||||
case Type::TypeTyID:
|
||||
throw std::string("Type constants shouldn't live in constant table!");
|
||||
|
||||
case Type::ArrayTyID: {
|
||||
const ArrayType *AT = cast<ArrayType>(Ty);
|
||||
unsigned NumElements = AT->getNumElements();
|
||||
unsigned TypeSlot = getTypeSlot(AT->getElementType());
|
||||
std::vector<Constant*> Elements;
|
||||
Elements.reserve(NumElements);
|
||||
while (NumElements--) // Read all of the elements of the constant.
|
||||
Elements.push_back(getConstantValue(TypeSlot,
|
||||
read_vbr_uint(Buf, EndBuf)));
|
||||
return ConstantArray::get(AT, Elements);
|
||||
}
|
||||
|
||||
case Type::StructTyID: {
|
||||
const StructType *ST = cast<StructType>(Ty);
|
||||
|
||||
std::vector<Constant *> Elements;
|
||||
Elements.reserve(ST->getNumElements());
|
||||
for (unsigned i = 0; i != ST->getNumElements(); ++i)
|
||||
Elements.push_back(getConstantValue(ST->getElementType(i),
|
||||
read_vbr_uint(Buf, EndBuf)));
|
||||
|
||||
return ConstantStruct::get(ST, Elements);
|
||||
}
|
||||
|
||||
case Type::PointerTyID: { // ConstantPointerRef value...
|
||||
const PointerType *PT = cast<PointerType>(Ty);
|
||||
unsigned Slot = read_vbr_uint(Buf, EndBuf);
|
||||
BCR_TRACE(4, "CPR: Type: '" << Ty << "' slot: " << Slot << "\n");
|
||||
|
||||
// Check to see if we have already read this global variable...
|
||||
Value *Val = getValue(TypeID, Slot, false);
|
||||
GlobalValue *GV;
|
||||
if (Val) {
|
||||
if (!(GV = dyn_cast<GlobalValue>(Val)))
|
||||
throw std::string("Value of ConstantPointerRef not in ValueTable!");
|
||||
BCR_TRACE(5, "Value Found in ValueTable!\n");
|
||||
} else {
|
||||
throw std::string("Forward references are not allowed here.");
|
||||
}
|
||||
|
||||
return ConstantPointerRef::get(GV);
|
||||
}
|
||||
|
||||
default:
|
||||
throw std::string("Don't know how to deserialize constant value of type '"+
|
||||
Ty->getDescription());
|
||||
}
|
||||
}
|
||||
|
||||
void BytecodeParser::ParseGlobalTypes(const unsigned char *&Buf,
|
||||
const unsigned char *EndBuf) {
|
||||
ValueTable T;
|
||||
ParseConstantPool(Buf, EndBuf, T, ModuleTypeValues);
|
||||
}
|
||||
|
||||
void BytecodeParser::parseStringConstants(const unsigned char *&Buf,
|
||||
const unsigned char *EndBuf,
|
||||
unsigned NumEntries, ValueTable &Tab){
|
||||
for (; NumEntries; --NumEntries) {
|
||||
unsigned Typ = read_vbr_uint(Buf, EndBuf);
|
||||
const Type *Ty = getType(Typ);
|
||||
if (!isa<ArrayType>(Ty))
|
||||
throw std::string("String constant data invalid!");
|
||||
|
||||
const ArrayType *ATy = cast<ArrayType>(Ty);
|
||||
if (ATy->getElementType() != Type::SByteTy &&
|
||||
ATy->getElementType() != Type::UByteTy)
|
||||
throw std::string("String constant data invalid!");
|
||||
|
||||
// Read character data. The type tells us how long the string is.
|
||||
char Data[ATy->getNumElements()];
|
||||
input_data(Buf, EndBuf, Data, Data+ATy->getNumElements());
|
||||
|
||||
std::vector<Constant*> Elements(ATy->getNumElements());
|
||||
if (ATy->getElementType() == Type::SByteTy)
|
||||
for (unsigned i = 0, e = ATy->getNumElements(); i != e; ++i)
|
||||
Elements[i] = ConstantSInt::get(Type::SByteTy, (signed char)Data[i]);
|
||||
else
|
||||
for (unsigned i = 0, e = ATy->getNumElements(); i != e; ++i)
|
||||
Elements[i] = ConstantUInt::get(Type::UByteTy, (unsigned char)Data[i]);
|
||||
|
||||
// Create the constant, inserting it as needed.
|
||||
Constant *C = ConstantArray::get(ATy, Elements);
|
||||
unsigned Slot = insertValue(C, Typ, Tab);
|
||||
ResolveReferencesToConstant(C, Slot);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BytecodeParser::ParseConstantPool(const unsigned char *&Buf,
|
||||
const unsigned char *EndBuf,
|
||||
ValueTable &Tab,
|
||||
TypeValuesListTy &TypeTab) {
|
||||
while (Buf < EndBuf) {
|
||||
unsigned NumEntries = read_vbr_uint(Buf, EndBuf);
|
||||
unsigned Typ = read_vbr_uint(Buf, EndBuf);
|
||||
if (Typ == Type::TypeTyID) {
|
||||
BCR_TRACE(3, "Type: 'type' NumEntries: " << NumEntries << "\n");
|
||||
parseTypeConstants(Buf, EndBuf, TypeTab, NumEntries);
|
||||
} else if (Typ == Type::VoidTyID) {
|
||||
assert(&Tab == &ModuleValues && "Cannot read strings in functions!");
|
||||
parseStringConstants(Buf, EndBuf, NumEntries, Tab);
|
||||
} else {
|
||||
BCR_TRACE(3, "Type: '" << *getType(Typ) << "' NumEntries: "
|
||||
<< NumEntries << "\n");
|
||||
|
||||
for (unsigned i = 0; i < NumEntries; ++i) {
|
||||
Constant *C = parseConstantValue(Buf, EndBuf, Typ);
|
||||
assert(C && "parseConstantValue returned NULL!");
|
||||
BCR_TRACE(4, "Read Constant: '" << *C << "'\n");
|
||||
unsigned Slot = insertValue(C, Typ, Tab);
|
||||
|
||||
// If we are reading a function constant table, make sure that we adjust
|
||||
// the slot number to be the real global constant number.
|
||||
//
|
||||
if (&Tab != &ModuleValues && Typ < ModuleValues.size() &&
|
||||
ModuleValues[Typ])
|
||||
Slot += ModuleValues[Typ]->size();
|
||||
ResolveReferencesToConstant(C, Slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Buf > EndBuf) throw std::string("Read past end of buffer.");
|
||||
}
|
|
@ -1,274 +0,0 @@
|
|||
//===-- BytecodeDumper.cpp - Parsing Handler --------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by Reid Spencer and is distributed under the
|
||||
// University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This header file defines the BytecodeDumper class that gets called by the
|
||||
// AbstractBytecodeParser when parsing events occur. It merely dumps the
|
||||
// information presented to it from the parser.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "AnalyzerInternals.h"
|
||||
#include "llvm/Constant.h"
|
||||
#include "llvm/Constants.h"
|
||||
#include "llvm/DerivedTypes.h"
|
||||
#include "llvm/Instruction.h"
|
||||
#include "llvm/Type.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
class BytecodeDumper : public llvm::BytecodeHandler {
|
||||
public:
|
||||
|
||||
virtual bool handleError(const std::string& str )
|
||||
{
|
||||
std::cout << "ERROR: " << str << "\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void handleStart()
|
||||
{
|
||||
std::cout << "Bytecode {\n";
|
||||
}
|
||||
|
||||
virtual void handleFinish()
|
||||
{
|
||||
std::cout << "} End Bytecode\n";
|
||||
}
|
||||
|
||||
virtual void handleModuleBegin(const std::string& id)
|
||||
{
|
||||
std::cout << " Module " << id << " {\n";
|
||||
}
|
||||
|
||||
virtual void handleModuleEnd(const std::string& id)
|
||||
{
|
||||
std::cout << " } End Module " << id << "\n";
|
||||
}
|
||||
|
||||
virtual void handleVersionInfo(
|
||||
unsigned char RevisionNum, ///< Byte code revision number
|
||||
Module::Endianness Endianness, ///< Endianness indicator
|
||||
Module::PointerSize PointerSize ///< PointerSize indicator
|
||||
)
|
||||
{
|
||||
std::cout << " RevisionNum: " << int(RevisionNum)
|
||||
<< " Endianness: " << Endianness
|
||||
<< " PointerSize: " << PointerSize << "\n";
|
||||
}
|
||||
|
||||
virtual void handleModuleGlobalsBegin()
|
||||
{
|
||||
std::cout << " BLOCK: ModuleGlobalInfo {\n";
|
||||
}
|
||||
|
||||
virtual void handleGlobalVariable(
|
||||
const Type* ElemType, ///< The type of the global variable
|
||||
bool isConstant, ///< Whether the GV is constant or not
|
||||
GlobalValue::LinkageTypes Linkage ///< The linkage type of the GV
|
||||
)
|
||||
{
|
||||
std::cout << " GV: Uninitialized, "
|
||||
<< ( isConstant? "Constant, " : "Variable, ")
|
||||
<< " Linkage=" << Linkage << " Type="
|
||||
<< ElemType->getDescription() << "\n";
|
||||
}
|
||||
|
||||
virtual void handleInitializedGV(
|
||||
const Type* ElemType, ///< The type of the global variable
|
||||
bool isConstant, ///< Whether the GV is constant or not
|
||||
GlobalValue::LinkageTypes Linkage,///< The linkage type of the GV
|
||||
unsigned initSlot ///< Slot number of GV's initializer
|
||||
)
|
||||
{
|
||||
std::cout << " GV: Initialized, "
|
||||
<< ( isConstant? "Constant, " : "Variable, ")
|
||||
<< " Linkage=" << Linkage << " Type="
|
||||
<< ElemType->getDescription()
|
||||
<< " InitializerSlot=" << initSlot << "\n";
|
||||
}
|
||||
|
||||
virtual void handleType( const Type* Ty ) {
|
||||
std::cout << " Type: " << Ty->getDescription() << "\n";
|
||||
}
|
||||
|
||||
virtual void handleFunctionDeclaration(
|
||||
Function* Func,
|
||||
const FunctionType* FuncType) {
|
||||
std::cout << " Function: " << FuncType->getDescription() << "\n";
|
||||
}
|
||||
|
||||
virtual void handleModuleGlobalsEnd() {
|
||||
std::cout << " } END BLOCK: ModuleGlobalInfo\n";
|
||||
}
|
||||
|
||||
virtual void handleCompactionTableBegin() {
|
||||
std::cout << " BLOCK: CompactionTable {\n";
|
||||
}
|
||||
|
||||
virtual void handleCompactionTablePlane( unsigned Ty, unsigned NumEntries ) {
|
||||
std::cout << " Plane: Ty=" << Ty << " Size=" << NumEntries << "\n";
|
||||
}
|
||||
|
||||
virtual void handleCompactionTableType(
|
||||
unsigned i,
|
||||
unsigned TypSlot,
|
||||
const Type* Ty) {
|
||||
std::cout << " Type: " << i << " Slot:" << TypSlot
|
||||
<< " is " << Ty->getDescription() << "\n";
|
||||
}
|
||||
|
||||
virtual void handleCompactionTableValue(
|
||||
unsigned i,
|
||||
unsigned ValSlot,
|
||||
const Type* Ty ) {
|
||||
std::cout << " Value: " << i << " Slot:" << ValSlot
|
||||
<< " is " << Ty->getDescription() << "\n";
|
||||
}
|
||||
|
||||
virtual void handleCompactionTableEnd() {
|
||||
std::cout << " } END BLOCK: CompactionTable\n";
|
||||
}
|
||||
|
||||
virtual void handleSymbolTableBegin() {
|
||||
std::cout << " BLOCK: SymbolTable {\n";
|
||||
}
|
||||
|
||||
virtual void handleSymbolTablePlane(
|
||||
unsigned Ty,
|
||||
unsigned NumEntries,
|
||||
const Type* Typ) {
|
||||
std::cout << " Plane: Ty=" << Ty << " Size=" << NumEntries
|
||||
<< " Type: " << Typ->getDescription() << "\n";
|
||||
}
|
||||
|
||||
virtual void handleSymbolTableType(
|
||||
unsigned i,
|
||||
unsigned slot,
|
||||
const std::string& name ) {
|
||||
std::cout << " Type " << i << " Slot=" << slot
|
||||
<< " Name: " << name << "\n";
|
||||
}
|
||||
|
||||
virtual void handleSymbolTableValue(
|
||||
unsigned i,
|
||||
unsigned slot,
|
||||
const std::string& name ) {
|
||||
std::cout << " Value " << i << " Slot=" << slot
|
||||
<< " Name: " << name << "\n";
|
||||
}
|
||||
|
||||
virtual void handleSymbolTableEnd() {
|
||||
std::cout << " } END BLOCK: SymbolTable\n";
|
||||
}
|
||||
|
||||
virtual void handleFunctionBegin(
|
||||
const Type* FType, GlobalValue::LinkageTypes linkage ) {
|
||||
std::cout << "BLOCK: Function {\n";
|
||||
std::cout << " Linkage: " << linkage << "\n";
|
||||
std::cout << " Type: " << FType->getDescription() << "\n";
|
||||
}
|
||||
|
||||
virtual void handleFunctionEnd( const Type* FType) {
|
||||
std::cout << "} END BLOCK: Function\n";
|
||||
}
|
||||
|
||||
virtual void handleBasicBlockBegin( unsigned blocknum) {
|
||||
std::cout << " BLOCK: BasicBlock #" << blocknum << "{\n";
|
||||
}
|
||||
|
||||
virtual bool handleInstruction(
|
||||
unsigned Opcode,
|
||||
const Type* iType,
|
||||
std::vector<unsigned>& Operands,
|
||||
unsigned Size) {
|
||||
std::cout << " INST: OpCode="
|
||||
<< Instruction::getOpcodeName(Opcode) << " Type="
|
||||
<< iType->getDescription() << "\n";
|
||||
for ( unsigned i = 0; i < Operands.size(); ++i )
|
||||
std::cout << " Op#" << i << " Slot=" << Operands[i] << "\n";
|
||||
|
||||
return Instruction::isTerminator(Opcode);
|
||||
}
|
||||
|
||||
virtual void handleBasicBlockEnd(unsigned blocknum) {
|
||||
std::cout << " } END BLOCK: BasicBlock #" << blocknum << "{\n";
|
||||
}
|
||||
|
||||
virtual void handleGlobalConstantsBegin() {
|
||||
std::cout << " BLOCK: GlobalConstants {\n";
|
||||
}
|
||||
|
||||
virtual void handleConstantExpression(
|
||||
unsigned Opcode,
|
||||
const Type* Typ,
|
||||
std::vector<std::pair<const Type*,unsigned> > ArgVec
|
||||
) {
|
||||
std::cout << " EXPR: " << Instruction::getOpcodeName(Opcode)
|
||||
<< " Type=" << Typ->getDescription() << "\n";
|
||||
for ( unsigned i = 0; i < ArgVec.size(); ++i )
|
||||
std::cout << " Arg#" << i << " Type="
|
||||
<< ArgVec[i].first->getDescription() << " Slot="
|
||||
<< ArgVec[i].second << "\n";
|
||||
}
|
||||
|
||||
virtual void handleConstantValue( Constant * c ) {
|
||||
std::cout << " VALUE: ";
|
||||
c->print(std::cout);
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
||||
virtual void handleConstantArray(const ArrayType* AT,
|
||||
std::vector<unsigned>& Elements ) {
|
||||
std::cout << " ARRAY: " << AT->getDescription() << "\n";
|
||||
for ( unsigned i = 0; i < Elements.size(); ++i )
|
||||
std::cout << " #" << i << " Slot=" << Elements[i] << "\n";
|
||||
}
|
||||
|
||||
virtual void handleConstantStruct( const StructType* ST,
|
||||
std::vector<unsigned>& Elements) {
|
||||
std::cout << " STRUC: " << ST->getDescription() << "\n";
|
||||
for ( unsigned i = 0; i < Elements.size(); ++i )
|
||||
std::cout << " #" << i << " Slot=" << Elements[i] << "\n";
|
||||
}
|
||||
|
||||
virtual void handleConstantPointer(
|
||||
const PointerType* PT, unsigned Slot)
|
||||
{
|
||||
std::cout << " POINT: " << PT->getDescription()
|
||||
<< " Slot=" << Slot << "\n";
|
||||
}
|
||||
|
||||
virtual void handleConstantString( const ConstantArray* CA ) {
|
||||
std::cout << " STRNG: ";
|
||||
CA->print(std::cout);
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
||||
virtual void handleGlobalConstantsEnd() {
|
||||
std::cout << " } END BLOCK: GlobalConstants\n";
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
void BytecodeAnalyzer::DumpBytecode(
|
||||
const unsigned char *Buf,
|
||||
unsigned Length,
|
||||
BytecodeAnalysis& bca,
|
||||
const std::string &ModuleID) {
|
||||
BytecodeDumper TheHandler;
|
||||
AbstractBytecodeParser TheParser(&TheHandler);
|
||||
TheParser.ParseBytecode( Buf, Length, ModuleID );
|
||||
if ( bca.detailedResults )
|
||||
TheParser.ParseAllFunctionBodies();
|
||||
}
|
||||
|
||||
// vim: sw=2
|
|
@ -1,381 +0,0 @@
|
|||
//===- ReadInst.cpp - Code to read an instruction from bytecode -----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by the LLVM research group and is distributed under
|
||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the mechanism to read an instruction from a bytecode
|
||||
// stream.
|
||||
//
|
||||
// Note that this library should be as fast as possible, reentrant, and
|
||||
// threadsafe!!
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ReaderInternals.h"
|
||||
#include "llvm/iTerminators.h"
|
||||
#include "llvm/iMemory.h"
|
||||
#include "llvm/iPHINode.h"
|
||||
#include "llvm/iOther.h"
|
||||
#include "llvm/Module.h"
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
struct RawInst { // The raw fields out of the bytecode stream...
|
||||
unsigned NumOperands;
|
||||
unsigned Opcode;
|
||||
unsigned Type;
|
||||
|
||||
RawInst(const unsigned char *&Buf, const unsigned char *EndBuf,
|
||||
std::vector<unsigned> &Args);
|
||||
};
|
||||
}
|
||||
|
||||
RawInst::RawInst(const unsigned char *&Buf, const unsigned char *EndBuf,
|
||||
std::vector<unsigned> &Args) {
|
||||
unsigned Op = read(Buf, EndBuf);
|
||||
|
||||
// bits Instruction format: Common to all formats
|
||||
// --------------------------
|
||||
// 01-00: Opcode type, fixed to 1.
|
||||
// 07-02: Opcode
|
||||
Opcode = (Op >> 2) & 63;
|
||||
Args.resize((Op >> 0) & 03);
|
||||
|
||||
switch (Args.size()) {
|
||||
case 1:
|
||||
// bits Instruction format:
|
||||
// --------------------------
|
||||
// 19-08: Resulting type plane
|
||||
// 31-20: Operand #1 (if set to (2^12-1), then zero operands)
|
||||
//
|
||||
Type = (Op >> 8) & 4095;
|
||||
Args[0] = (Op >> 20) & 4095;
|
||||
if (Args[0] == 4095) // Handle special encoding for 0 operands...
|
||||
Args.resize(0);
|
||||
break;
|
||||
case 2:
|
||||
// bits Instruction format:
|
||||
// --------------------------
|
||||
// 15-08: Resulting type plane
|
||||
// 23-16: Operand #1
|
||||
// 31-24: Operand #2
|
||||
//
|
||||
Type = (Op >> 8) & 255;
|
||||
Args[0] = (Op >> 16) & 255;
|
||||
Args[1] = (Op >> 24) & 255;
|
||||
break;
|
||||
case 3:
|
||||
// bits Instruction format:
|
||||
// --------------------------
|
||||
// 13-08: Resulting type plane
|
||||
// 19-14: Operand #1
|
||||
// 25-20: Operand #2
|
||||
// 31-26: Operand #3
|
||||
//
|
||||
Type = (Op >> 8) & 63;
|
||||
Args[0] = (Op >> 14) & 63;
|
||||
Args[1] = (Op >> 20) & 63;
|
||||
Args[2] = (Op >> 26) & 63;
|
||||
break;
|
||||
case 0:
|
||||
Buf -= 4; // Hrm, try this again...
|
||||
Opcode = read_vbr_uint(Buf, EndBuf);
|
||||
Opcode >>= 2;
|
||||
Type = read_vbr_uint(Buf, EndBuf);
|
||||
|
||||
unsigned NumOperands = read_vbr_uint(Buf, EndBuf);
|
||||
Args.resize(NumOperands);
|
||||
|
||||
if (NumOperands == 0)
|
||||
throw std::string("Zero-argument instruction found; this is invalid.");
|
||||
|
||||
for (unsigned i = 0; i != NumOperands; ++i)
|
||||
Args[i] = read_vbr_uint(Buf, EndBuf);
|
||||
align32(Buf, EndBuf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BytecodeParser::ParseInstruction(const unsigned char *&Buf,
|
||||
const unsigned char *EndBuf,
|
||||
std::vector<unsigned> &Args,
|
||||
BasicBlock *BB) {
|
||||
Args.clear();
|
||||
RawInst RI(Buf, EndBuf, Args);
|
||||
const Type *InstTy = getType(RI.Type);
|
||||
|
||||
Instruction *Result = 0;
|
||||
if (RI.Opcode >= Instruction::BinaryOpsBegin &&
|
||||
RI.Opcode < Instruction::BinaryOpsEnd && Args.size() == 2)
|
||||
Result = BinaryOperator::create((Instruction::BinaryOps)RI.Opcode,
|
||||
getValue(RI.Type, Args[0]),
|
||||
getValue(RI.Type, Args[1]));
|
||||
|
||||
switch (RI.Opcode) {
|
||||
default:
|
||||
if (Result == 0) throw std::string("Illegal instruction read!");
|
||||
break;
|
||||
case Instruction::VAArg:
|
||||
Result = new VAArgInst(getValue(RI.Type, Args[0]), getType(Args[1]));
|
||||
break;
|
||||
case Instruction::VANext:
|
||||
Result = new VANextInst(getValue(RI.Type, Args[0]), getType(Args[1]));
|
||||
break;
|
||||
case Instruction::Cast:
|
||||
Result = new CastInst(getValue(RI.Type, Args[0]), getType(Args[1]));
|
||||
break;
|
||||
case Instruction::Select:
|
||||
Result = new SelectInst(getValue(Type::BoolTyID, Args[0]),
|
||||
getValue(RI.Type, Args[1]),
|
||||
getValue(RI.Type, Args[2]));
|
||||
break;
|
||||
case Instruction::PHI: {
|
||||
if (Args.size() == 0 || (Args.size() & 1))
|
||||
throw std::string("Invalid phi node encountered!\n");
|
||||
|
||||
PHINode *PN = new PHINode(InstTy);
|
||||
PN->op_reserve(Args.size());
|
||||
for (unsigned i = 0, e = Args.size(); i != e; i += 2)
|
||||
PN->addIncoming(getValue(RI.Type, Args[i]), getBasicBlock(Args[i+1]));
|
||||
Result = PN;
|
||||
break;
|
||||
}
|
||||
|
||||
case Instruction::Shl:
|
||||
case Instruction::Shr:
|
||||
Result = new ShiftInst((Instruction::OtherOps)RI.Opcode,
|
||||
getValue(RI.Type, Args[0]),
|
||||
getValue(Type::UByteTyID, Args[1]));
|
||||
break;
|
||||
case Instruction::Ret:
|
||||
if (Args.size() == 0)
|
||||
Result = new ReturnInst();
|
||||
else if (Args.size() == 1)
|
||||
Result = new ReturnInst(getValue(RI.Type, Args[0]));
|
||||
else
|
||||
throw std::string("Unrecognized instruction!");
|
||||
break;
|
||||
|
||||
case Instruction::Br:
|
||||
if (Args.size() == 1)
|
||||
Result = new BranchInst(getBasicBlock(Args[0]));
|
||||
else if (Args.size() == 3)
|
||||
Result = new BranchInst(getBasicBlock(Args[0]), getBasicBlock(Args[1]),
|
||||
getValue(Type::BoolTyID , Args[2]));
|
||||
else
|
||||
throw std::string("Invalid number of operands for a 'br' instruction!");
|
||||
break;
|
||||
case Instruction::Switch: {
|
||||
if (Args.size() & 1)
|
||||
throw std::string("Switch statement with odd number of arguments!");
|
||||
|
||||
SwitchInst *I = new SwitchInst(getValue(RI.Type, Args[0]),
|
||||
getBasicBlock(Args[1]));
|
||||
for (unsigned i = 2, e = Args.size(); i != e; i += 2)
|
||||
I->addCase(cast<Constant>(getValue(RI.Type, Args[i])),
|
||||
getBasicBlock(Args[i+1]));
|
||||
Result = I;
|
||||
break;
|
||||
}
|
||||
|
||||
case Instruction::Call: {
|
||||
if (Args.size() == 0)
|
||||
throw std::string("Invalid call instruction encountered!");
|
||||
|
||||
Value *F = getValue(RI.Type, Args[0]);
|
||||
|
||||
// Check to make sure we have a pointer to function type
|
||||
const PointerType *PTy = dyn_cast<PointerType>(F->getType());
|
||||
if (PTy == 0) throw std::string("Call to non function pointer value!");
|
||||
const FunctionType *FTy = dyn_cast<FunctionType>(PTy->getElementType());
|
||||
if (FTy == 0) throw std::string("Call to non function pointer value!");
|
||||
|
||||
std::vector<Value *> Params;
|
||||
if (!FTy->isVarArg()) {
|
||||
FunctionType::param_iterator It = FTy->param_begin();
|
||||
|
||||
for (unsigned i = 1, e = Args.size(); i != e; ++i) {
|
||||
if (It == FTy->param_end())
|
||||
throw std::string("Invalid call instruction!");
|
||||
Params.push_back(getValue(getTypeSlot(*It++), Args[i]));
|
||||
}
|
||||
if (It != FTy->param_end())
|
||||
throw std::string("Invalid call instruction!");
|
||||
} else {
|
||||
Args.erase(Args.begin(), Args.begin()+1);
|
||||
|
||||
unsigned FirstVariableOperand;
|
||||
if (Args.size() < FTy->getNumParams())
|
||||
throw std::string("Call instruction missing operands!");
|
||||
|
||||
// Read all of the fixed arguments
|
||||
for (unsigned i = 0, e = FTy->getNumParams(); i != e; ++i)
|
||||
Params.push_back(getValue(getTypeSlot(FTy->getParamType(i)),Args[i]));
|
||||
|
||||
FirstVariableOperand = FTy->getNumParams();
|
||||
|
||||
if ((Args.size()-FirstVariableOperand) & 1) // Must be pairs of type/value
|
||||
throw std::string("Invalid call instruction!");
|
||||
|
||||
for (unsigned i = FirstVariableOperand, e = Args.size(); i != e; i += 2)
|
||||
Params.push_back(getValue(Args[i], Args[i+1]));
|
||||
}
|
||||
|
||||
Result = new CallInst(F, Params);
|
||||
break;
|
||||
}
|
||||
case Instruction::Invoke: {
|
||||
if (Args.size() < 3) throw std::string("Invalid invoke instruction!");
|
||||
Value *F = getValue(RI.Type, Args[0]);
|
||||
|
||||
// Check to make sure we have a pointer to function type
|
||||
const PointerType *PTy = dyn_cast<PointerType>(F->getType());
|
||||
if (PTy == 0) throw std::string("Invoke to non function pointer value!");
|
||||
const FunctionType *FTy = dyn_cast<FunctionType>(PTy->getElementType());
|
||||
if (FTy == 0) throw std::string("Invoke to non function pointer value!");
|
||||
|
||||
std::vector<Value *> Params;
|
||||
BasicBlock *Normal, *Except;
|
||||
|
||||
if (!FTy->isVarArg()) {
|
||||
Normal = getBasicBlock(Args[1]);
|
||||
Except = getBasicBlock(Args[2]);
|
||||
|
||||
FunctionType::param_iterator It = FTy->param_begin();
|
||||
for (unsigned i = 3, e = Args.size(); i != e; ++i) {
|
||||
if (It == FTy->param_end())
|
||||
throw std::string("Invalid invoke instruction!");
|
||||
Params.push_back(getValue(getTypeSlot(*It++), Args[i]));
|
||||
}
|
||||
if (It != FTy->param_end())
|
||||
throw std::string("Invalid invoke instruction!");
|
||||
} else {
|
||||
Args.erase(Args.begin(), Args.begin()+1);
|
||||
|
||||
Normal = getBasicBlock(Args[0]);
|
||||
Except = getBasicBlock(Args[1]);
|
||||
|
||||
unsigned FirstVariableArgument = FTy->getNumParams()+2;
|
||||
for (unsigned i = 2; i != FirstVariableArgument; ++i)
|
||||
Params.push_back(getValue(getTypeSlot(FTy->getParamType(i-2)),
|
||||
Args[i]));
|
||||
|
||||
if (Args.size()-FirstVariableArgument & 1) // Must be pairs of type/value
|
||||
throw std::string("Invalid invoke instruction!");
|
||||
|
||||
for (unsigned i = FirstVariableArgument; i < Args.size(); i += 2)
|
||||
Params.push_back(getValue(Args[i], Args[i+1]));
|
||||
}
|
||||
|
||||
Result = new InvokeInst(F, Normal, Except, Params);
|
||||
break;
|
||||
}
|
||||
case Instruction::Malloc:
|
||||
if (Args.size() > 2) throw std::string("Invalid malloc instruction!");
|
||||
if (!isa<PointerType>(InstTy))
|
||||
throw std::string("Invalid malloc instruction!");
|
||||
|
||||
Result = new MallocInst(cast<PointerType>(InstTy)->getElementType(),
|
||||
Args.size() ? getValue(Type::UIntTyID,
|
||||
Args[0]) : 0);
|
||||
break;
|
||||
|
||||
case Instruction::Alloca:
|
||||
if (Args.size() > 2) throw std::string("Invalid alloca instruction!");
|
||||
if (!isa<PointerType>(InstTy))
|
||||
throw std::string("Invalid alloca instruction!");
|
||||
|
||||
Result = new AllocaInst(cast<PointerType>(InstTy)->getElementType(),
|
||||
Args.size() ? getValue(Type::UIntTyID, Args[0]) :0);
|
||||
break;
|
||||
case Instruction::Free:
|
||||
if (!isa<PointerType>(InstTy))
|
||||
throw std::string("Invalid free instruction!");
|
||||
Result = new FreeInst(getValue(RI.Type, Args[0]));
|
||||
break;
|
||||
case Instruction::GetElementPtr: {
|
||||
if (Args.size() == 0 || !isa<PointerType>(InstTy))
|
||||
throw std::string("Invalid getelementptr instruction!");
|
||||
|
||||
std::vector<Value*> Idx;
|
||||
|
||||
const Type *NextTy = InstTy;
|
||||
for (unsigned i = 1, e = Args.size(); i != e; ++i) {
|
||||
const CompositeType *TopTy = dyn_cast_or_null<CompositeType>(NextTy);
|
||||
if (!TopTy) throw std::string("Invalid getelementptr instruction!");
|
||||
|
||||
unsigned ValIdx = Args[i];
|
||||
unsigned IdxTy = 0;
|
||||
if (!hasRestrictedGEPTypes) {
|
||||
// Struct indices are always uints, sequential type indices can be any
|
||||
// of the 32 or 64-bit integer types. The actual choice of type is
|
||||
// encoded in the low two bits of the slot number.
|
||||
if (isa<StructType>(TopTy))
|
||||
IdxTy = Type::UIntTyID;
|
||||
else {
|
||||
switch (ValIdx & 3) {
|
||||
default:
|
||||
case 0: IdxTy = Type::UIntTyID; break;
|
||||
case 1: IdxTy = Type::IntTyID; break;
|
||||
case 2: IdxTy = Type::ULongTyID; break;
|
||||
case 3: IdxTy = Type::LongTyID; break;
|
||||
}
|
||||
ValIdx >>= 2;
|
||||
}
|
||||
} else {
|
||||
IdxTy = isa<StructType>(TopTy) ? Type::UByteTyID : Type::LongTyID;
|
||||
}
|
||||
|
||||
Idx.push_back(getValue(IdxTy, ValIdx));
|
||||
|
||||
// Convert ubyte struct indices into uint struct indices.
|
||||
if (isa<StructType>(TopTy) && hasRestrictedGEPTypes)
|
||||
if (ConstantUInt *C = dyn_cast<ConstantUInt>(Idx.back()))
|
||||
Idx[Idx.size()-1] = ConstantExpr::getCast(C, Type::UIntTy);
|
||||
|
||||
NextTy = GetElementPtrInst::getIndexedType(InstTy, Idx, true);
|
||||
}
|
||||
|
||||
Result = new GetElementPtrInst(getValue(RI.Type, Args[0]), Idx);
|
||||
break;
|
||||
}
|
||||
|
||||
case 62: // volatile load
|
||||
case Instruction::Load:
|
||||
if (Args.size() != 1 || !isa<PointerType>(InstTy))
|
||||
throw std::string("Invalid load instruction!");
|
||||
Result = new LoadInst(getValue(RI.Type, Args[0]), "", RI.Opcode == 62);
|
||||
break;
|
||||
|
||||
case 63: // volatile store
|
||||
case Instruction::Store: {
|
||||
if (!isa<PointerType>(InstTy) || Args.size() != 2)
|
||||
throw std::string("Invalid store instruction!");
|
||||
|
||||
Value *Ptr = getValue(RI.Type, Args[1]);
|
||||
const Type *ValTy = cast<PointerType>(Ptr->getType())->getElementType();
|
||||
Result = new StoreInst(getValue(getTypeSlot(ValTy), Args[0]), Ptr,
|
||||
RI.Opcode == 63);
|
||||
break;
|
||||
}
|
||||
case Instruction::Unwind:
|
||||
if (Args.size() != 0) throw std::string("Invalid unwind instruction!");
|
||||
Result = new UnwindInst();
|
||||
break;
|
||||
} // end switch(RI.Opcode)
|
||||
|
||||
unsigned TypeSlot;
|
||||
if (Result->getType() == InstTy)
|
||||
TypeSlot = RI.Type;
|
||||
else
|
||||
TypeSlot = getTypeSlot(Result->getType());
|
||||
|
||||
insertValue(Result, TypeSlot, Values);
|
||||
BB->getInstList().push_back(Result);
|
||||
BCR_TRACE(4, *Result);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,544 +0,0 @@
|
|||
//===-- Parser.h - Abstract Interface To Bytecode Parsing -------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by Reid Spencer and is distributed under the
|
||||
// University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This header file defines the interface to the Bytecode Parser and the
|
||||
// Bytecode Handler interface that it calls.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef BYTECODE_PARSER_H
|
||||
#define BYTECODE_PARSER_H
|
||||
|
||||
#include "llvm/Constants.h"
|
||||
#include "llvm/DerivedTypes.h"
|
||||
#include "llvm/GlobalValue.h"
|
||||
#include "llvm/Module.h"
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class BytecodeHandler; ///< Forward declare the handler interface
|
||||
|
||||
/// This class defines the interface for parsing a buffer of bytecode. The
|
||||
/// parser itself takes no action except to call the various functions of
|
||||
/// the handler interface. The parser's sole responsibility is the correct
|
||||
/// interpretation of the bytecode buffer. The handler is responsible for
|
||||
/// instantiating and keeping track of all values. As a convenience, the parser
|
||||
/// is responsible for materializing types and will pass them through the
|
||||
/// handler interface as necessary.
|
||||
/// @see BytecodeHandler
|
||||
/// @brief Abstract Bytecode Parser interface
|
||||
class AbstractBytecodeParser {
|
||||
|
||||
/// @name Constructors
|
||||
/// @{
|
||||
public:
|
||||
AbstractBytecodeParser(
|
||||
BytecodeHandler* h,
|
||||
bool repAlignment = false,
|
||||
bool repBlocks = false,
|
||||
bool repVBR = false
|
||||
) {
|
||||
handler = h;
|
||||
reportAlignment = repAlignment;
|
||||
reportBlocks = repBlocks;
|
||||
reportVBR = repVBR;
|
||||
}
|
||||
|
||||
~AbstractBytecodeParser() { }
|
||||
|
||||
/// @}
|
||||
/// @name Types
|
||||
/// @{
|
||||
public:
|
||||
/// @brief A convenience type for the buffer pointer
|
||||
typedef const unsigned char* BufPtr;
|
||||
|
||||
/// @brief The type used for vector of potentially abstract types
|
||||
typedef std::vector<PATypeHolder> TypeListTy;
|
||||
|
||||
/// @brief
|
||||
|
||||
/// @}
|
||||
/// @name Methods
|
||||
/// @{
|
||||
public:
|
||||
|
||||
/// @brief Main interface to parsing a bytecode buffer.
|
||||
void ParseBytecode(const unsigned char *Buf, unsigned Length,
|
||||
const std::string &ModuleID);
|
||||
|
||||
/// The ParseBytecode method lazily parses functions. Use this
|
||||
/// method to cause the parser to actually parse all the function bodies
|
||||
/// in the bytecode buffer.
|
||||
/// @see ParseBytecode
|
||||
/// @brief Parse all function bodies
|
||||
void ParseAllFunctionBodies ();
|
||||
|
||||
/// The Parsebytecode method lazily parses functions. Use this
|
||||
/// method to casue the parser to parse the next function of a given
|
||||
/// types. Note that this will remove the function from what is to be
|
||||
/// included by ParseAllFunctionBodies.
|
||||
/// @see ParseAllFunctionBodies
|
||||
/// @see ParseBytecode
|
||||
/// @brief Parse the next function of specific type
|
||||
void ParseNextFunction (Function* Func) ;
|
||||
|
||||
/// @}
|
||||
/// @name Parsing Units For Subclasses
|
||||
/// @{
|
||||
protected:
|
||||
/// @brief Parse whole module scope
|
||||
void ParseModule ();
|
||||
|
||||
/// @brief Parse the version information block
|
||||
void ParseVersionInfo ();
|
||||
|
||||
/// @brief Parse the ModuleGlobalInfo block
|
||||
void ParseModuleGlobalInfo ();
|
||||
|
||||
/// @brief Parse a symbol table
|
||||
void ParseSymbolTable ();
|
||||
|
||||
/// This function parses LLVM functions lazily. It obtains the type of the
|
||||
/// function and records where the body of the function is in the bytecode
|
||||
/// buffer. The caller can then use the ParseNextFunction and
|
||||
/// ParseAllFunctionBodies to get handler events for the functions.
|
||||
/// @brief Parse functions lazily.
|
||||
void ParseFunctionLazily ();
|
||||
|
||||
/// @brief Parse a function body
|
||||
void ParseFunctionBody (Function* Func);
|
||||
|
||||
/// @brief Parse a compaction table
|
||||
void ParseCompactionTable ();
|
||||
|
||||
/// @brief Parse global types
|
||||
void ParseGlobalTypes ();
|
||||
|
||||
/// @brief Parse a basic block (for LLVM 1.0 basic block blocks)
|
||||
void ParseBasicBlock (unsigned BlockNo);
|
||||
|
||||
/// @brief parse an instruction list (for post LLVM 1.0 instruction lists
|
||||
/// with blocks differentiated by terminating instructions.
|
||||
unsigned ParseInstructionList();
|
||||
|
||||
/// @brief Parse an instruction.
|
||||
bool ParseInstruction (std::vector<unsigned>& Args);
|
||||
|
||||
/// @brief Parse a constant pool
|
||||
void ParseConstantPool (TypeListTy& List);
|
||||
|
||||
/// @brief Parse a constant value
|
||||
void ParseConstantValue (unsigned TypeID);
|
||||
|
||||
/// @brief Parse a block of types.
|
||||
void ParseTypeConstants (TypeListTy &Tab, unsigned NumEntries);
|
||||
|
||||
/// @brief Parse a single type.
|
||||
const Type *ParseTypeConstant();
|
||||
|
||||
/// @brief Parse a string constants block
|
||||
void ParseStringConstants (unsigned NumEntries);
|
||||
|
||||
/// @}
|
||||
/// @name Data
|
||||
/// @{
|
||||
private:
|
||||
BufPtr MemStart; ///< Start of the memory buffer
|
||||
BufPtr MemEnd; ///< End of the memory buffer
|
||||
BufPtr BlockStart; ///< Start of current block being parsed
|
||||
BufPtr BlockEnd; ///< End of current block being parsed
|
||||
BufPtr At; ///< Where we're currently parsing at
|
||||
|
||||
bool reportAlignment; ///< Parser should report alignment?
|
||||
bool reportBlocks; ///< Parser should report blocks?
|
||||
bool reportVBR; ///< Report VBR compression events
|
||||
|
||||
// Information about the module, extracted from the bytecode revision number.
|
||||
unsigned char RevisionNum; // The rev # itself
|
||||
|
||||
// Flags to distinguish LLVM 1.0 & 1.1 bytecode formats (revision #0)
|
||||
|
||||
// Revision #0 had an explicit alignment of data only for the ModuleGlobalInfo
|
||||
// block. This was fixed to be like all other blocks in 1.2
|
||||
bool hasInconsistentModuleGlobalInfo;
|
||||
|
||||
// Revision #0 also explicitly encoded zero values for primitive types like
|
||||
// int/sbyte/etc.
|
||||
bool hasExplicitPrimitiveZeros;
|
||||
|
||||
// Flags to control features specific the LLVM 1.2 and before (revision #1)
|
||||
|
||||
// LLVM 1.2 and earlier required that getelementptr structure indices were
|
||||
// ubyte constants and that sequential type indices were longs.
|
||||
bool hasRestrictedGEPTypes;
|
||||
|
||||
|
||||
/// CompactionTable - If a compaction table is active in the current function,
|
||||
/// this is the mapping that it contains.
|
||||
std::vector<Type*> CompactionTypeTable;
|
||||
|
||||
// ConstantFwdRefs - This maintains a mapping between <Type, Slot #>'s and
|
||||
// forward references to constants. Such values may be referenced before they
|
||||
// are defined, and if so, the temporary object that they represent is held
|
||||
// here.
|
||||
//
|
||||
typedef std::map<std::pair<const Type*,unsigned>, Constant*> ConstantRefsType;
|
||||
ConstantRefsType ConstantFwdRefs;
|
||||
|
||||
// TypesLoaded - This vector mirrors the Values[TypeTyID] plane. It is used
|
||||
// to deal with forward references to types.
|
||||
//
|
||||
TypeListTy ModuleTypes;
|
||||
TypeListTy FunctionTypes;
|
||||
|
||||
// When the ModuleGlobalInfo section is read, we create a FunctionType object
|
||||
// for each function in the module. When the function is loaded, this type is
|
||||
// used to instantiate the actual function object.
|
||||
|
||||
std::vector<Function*> FunctionSignatureList;
|
||||
|
||||
// Constant values are read in after global variables. Because of this, we
|
||||
// must defer setting the initializers on global variables until after module
|
||||
// level constants have been read. In the mean time, this list keeps track of
|
||||
// what we must do.
|
||||
//
|
||||
std::vector<std::pair<GlobalVariable*, unsigned> > GlobalInits;
|
||||
|
||||
/// @}
|
||||
/// @name Implementation Details
|
||||
/// @{
|
||||
private:
|
||||
/// This stores the parser's handler. It makes virtual function calls through
|
||||
/// the BytecodeHandler to notify the handler of parsing events. What the
|
||||
/// handler does with the events is completely orthogonal to the business of
|
||||
/// parsing the bytecode.
|
||||
/// @brief The handler of bytecode parsing events.
|
||||
BytecodeHandler* handler;
|
||||
|
||||
/// For lazy reading-in of functions, we need to save away several pieces of
|
||||
/// information about each function: its begin and end pointer in the buffer
|
||||
/// and its FunctionSlot.
|
||||
struct LazyFunctionInfo {
|
||||
const unsigned char *Buf, *EndBuf;
|
||||
LazyFunctionInfo(const unsigned char *B = 0, const unsigned char *EB = 0)
|
||||
: Buf(B), EndBuf(EB) {}
|
||||
};
|
||||
typedef std::map<Function*, LazyFunctionInfo> LazyFunctionMap;
|
||||
LazyFunctionMap LazyFunctionLoadMap;
|
||||
|
||||
private:
|
||||
|
||||
/// Is there more to parse in the current block?
|
||||
inline bool moreInBlock();
|
||||
|
||||
/// Have we read past the end of the block
|
||||
inline void checkPastBlockEnd(const char * block_name);
|
||||
|
||||
/// Align to 32 bits
|
||||
inline void align32();
|
||||
|
||||
/// Reader interface
|
||||
inline unsigned read_uint();
|
||||
inline unsigned read_vbr_uint();
|
||||
inline uint64_t read_vbr_uint64();
|
||||
inline int64_t read_vbr_int64();
|
||||
inline std::string read_str();
|
||||
inline void read_data(void *Ptr, void *End);
|
||||
|
||||
/// Read a block header
|
||||
inline void readBlock(unsigned &Type, unsigned &Size);
|
||||
|
||||
const Type *AbstractBytecodeParser::getType(unsigned ID);
|
||||
/// getGlobalTableType - This is just like getType, but when a compaction
|
||||
/// table is in use, it is ignored. Also, no forward references or other
|
||||
/// fancy features are supported.
|
||||
const Type *getGlobalTableType(unsigned Slot) {
|
||||
if (Slot < Type::FirstDerivedTyID) {
|
||||
const Type *Ty = Type::getPrimitiveType((Type::TypeID)Slot);
|
||||
assert(Ty && "Not a primitive type ID?");
|
||||
return Ty;
|
||||
}
|
||||
Slot -= Type::FirstDerivedTyID;
|
||||
if (Slot >= ModuleTypes.size())
|
||||
throw std::string("Illegal compaction table type reference!");
|
||||
return ModuleTypes[Slot];
|
||||
}
|
||||
|
||||
unsigned getGlobalTableTypeSlot(const Type *Ty) {
|
||||
if (Ty->isPrimitiveType())
|
||||
return Ty->getTypeID();
|
||||
TypeListTy::iterator I = find(ModuleTypes.begin(),
|
||||
ModuleTypes.end(), Ty);
|
||||
if (I == ModuleTypes.end())
|
||||
throw std::string("Didn't find type in ModuleTypes.");
|
||||
return Type::FirstDerivedTyID + (&*I - &ModuleTypes[0]);
|
||||
}
|
||||
|
||||
AbstractBytecodeParser(const AbstractBytecodeParser &); // DO NOT IMPLEMENT
|
||||
void operator=(const AbstractBytecodeParser &); // DO NOT IMPLEMENT
|
||||
|
||||
/// @}
|
||||
};
|
||||
|
||||
/// This class provides the interface for the handling bytecode events during
|
||||
/// parsing. The methods on this interface are invoked by the
|
||||
/// AbstractBytecodeParser as it discovers the content of a bytecode stream.
|
||||
/// This class provides a a clear separation of concerns between recognizing
|
||||
/// the semantic units of a bytecode file and deciding what to do with them.
|
||||
/// The AbstractBytecodeParser recognizes the content of the bytecode file and
|
||||
/// calls the BytecodeHandler methods to determine what should be done. This
|
||||
/// arrangement allows Bytecode files to be read and handled for a number of
|
||||
/// purposes simply by creating a subclass of BytecodeHandler. None of the
|
||||
/// parsing details need to be understood, only the meaning of the calls
|
||||
/// made on this interface.
|
||||
///
|
||||
/// Another paradigm that uses this design pattern is the XML SAX Parser. The
|
||||
/// ContentHandler for SAX plays the same role as the BytecodeHandler here.
|
||||
/// @see AbstractbytecodeParser
|
||||
/// @brief Handle Bytecode Parsing Events
|
||||
class BytecodeHandler {
|
||||
|
||||
/// @name Constructors And Operators
|
||||
/// @{
|
||||
public:
|
||||
/// @brief Default constructor (empty)
|
||||
BytecodeHandler() {}
|
||||
/// @brief Virtual destructor (empty)
|
||||
virtual ~BytecodeHandler() {}
|
||||
|
||||
private:
|
||||
BytecodeHandler(const BytecodeHandler &); // DO NOT IMPLEMENT
|
||||
void operator=(const BytecodeHandler &); // DO NOT IMPLEMENT
|
||||
|
||||
/// @}
|
||||
/// @name Handler Methods
|
||||
/// @{
|
||||
public:
|
||||
|
||||
/// This method is called whenever the parser detects an error in the
|
||||
/// bytecode formatting. Returning true will cause the parser to keep
|
||||
/// going, however this is inadvisable in most cases. Returning false will
|
||||
/// cause the parser to throw the message as a std::string.
|
||||
/// @brief Handle parsing errors.
|
||||
virtual bool handleError(const std::string& str );
|
||||
|
||||
/// This method is called at the beginning of a parse before anything is
|
||||
/// read in order to give the handler a chance to initialize.
|
||||
/// @brief Handle the start of a bytecode parse
|
||||
virtual void handleStart();
|
||||
|
||||
/// This method is called at the end of a parse after everything has been
|
||||
/// read in order to give the handler a chance to terminate.
|
||||
/// @brief Handle the end of a bytecode parse
|
||||
virtual void handleFinish();
|
||||
|
||||
/// This method is called at the start of a module to indicate that a
|
||||
/// module is being parsed.
|
||||
/// @brief Handle the start of a module.
|
||||
virtual void handleModuleBegin(const std::string& id);
|
||||
|
||||
/// This method is called at the end of a module to indicate that the module
|
||||
/// previously being parsed has concluded.
|
||||
/// @brief Handle the end of a module.
|
||||
virtual void handleModuleEnd(const std::string& id);
|
||||
|
||||
/// This method is called once the version information has been parsed. It
|
||||
/// provides the information about the version of the bytecode file being
|
||||
/// read.
|
||||
/// @brief Handle the bytecode prolog
|
||||
virtual void handleVersionInfo(
|
||||
unsigned char RevisionNum, ///< Byte code revision number
|
||||
Module::Endianness Endianness, ///< Endianness indicator
|
||||
Module::PointerSize PointerSize ///< PointerSize indicator
|
||||
);
|
||||
|
||||
/// This method is called at the start of a module globals block which
|
||||
/// contains the global variables and the function placeholders
|
||||
virtual void handleModuleGlobalsBegin();
|
||||
|
||||
/// This method is called when a non-initialized global variable is
|
||||
/// recognized. Its type, constness, and linkage type are provided.
|
||||
/// @brief Handle a non-initialized global variable
|
||||
virtual void handleGlobalVariable(
|
||||
const Type* ElemType, ///< The type of the global variable
|
||||
bool isConstant, ///< Whether the GV is constant or not
|
||||
GlobalValue::LinkageTypes ///< The linkage type of the GV
|
||||
);
|
||||
|
||||
/// This method is called when an initialized global variable is recognized.
|
||||
/// Its type constness, linkage type, and the slot number of the initializer
|
||||
/// are provided.
|
||||
/// @brief Handle an intialized global variable.
|
||||
virtual void handleInitializedGV(
|
||||
const Type* ElemType, ///< The type of the global variable
|
||||
bool isConstant, ///< Whether the GV is constant or not
|
||||
GlobalValue::LinkageTypes,///< The linkage type of the GV
|
||||
unsigned initSlot ///< Slot number of GV's initializer
|
||||
);
|
||||
|
||||
/// This method is called when a new type is recognized. The type is
|
||||
/// converted from the bytecode and passed to this method.
|
||||
/// @brief Handle a type
|
||||
virtual void handleType( const Type* Ty );
|
||||
|
||||
/// This method is called when the function prototype for a function is
|
||||
/// encountered in the module globals block.
|
||||
virtual void handleFunctionDeclaration(
|
||||
Function* Func,
|
||||
const FunctionType* FuncType ///< The type of the function
|
||||
);
|
||||
|
||||
/// This method is called at the end of the module globals block.
|
||||
/// @brief Handle end of module globals block.
|
||||
virtual void handleModuleGlobalsEnd();
|
||||
|
||||
/// This method is called at the beginning of a compaction table.
|
||||
/// @brief Handle start of compaction table.
|
||||
virtual void handleCompactionTableBegin();
|
||||
|
||||
/// @brief Handle start of a compaction table plane
|
||||
virtual void handleCompactionTablePlane(
|
||||
unsigned Ty,
|
||||
unsigned NumEntries
|
||||
);
|
||||
|
||||
|
||||
/// @brief Handle a type entry in the compaction table
|
||||
virtual void handleCompactionTableType(
|
||||
unsigned i,
|
||||
unsigned TypSlot,
|
||||
const Type*
|
||||
);
|
||||
|
||||
/// @brief Handle a value entry in the compaction table
|
||||
virtual void handleCompactionTableValue(
|
||||
unsigned i,
|
||||
unsigned ValSlot,
|
||||
const Type*
|
||||
);
|
||||
|
||||
/// @brief Handle end of a compaction table
|
||||
virtual void handleCompactionTableEnd();
|
||||
|
||||
/// @brief Handle start of a symbol table
|
||||
virtual void handleSymbolTableBegin();
|
||||
|
||||
/// @brief Handle start of a symbol table plane
|
||||
virtual void handleSymbolTablePlane(
|
||||
unsigned Ty,
|
||||
unsigned NumEntries,
|
||||
const Type* Ty
|
||||
);
|
||||
|
||||
/// @brief Handle a named type in the symbol table
|
||||
virtual void handleSymbolTableType(
|
||||
unsigned i,
|
||||
unsigned slot,
|
||||
const std::string& name
|
||||
);
|
||||
|
||||
/// @brief Handle a named value in the symbol table
|
||||
virtual void handleSymbolTableValue(
|
||||
unsigned i,
|
||||
unsigned slot,
|
||||
const std::string& name
|
||||
);
|
||||
|
||||
/// @brief Handle the end of a symbol table
|
||||
virtual void handleSymbolTableEnd();
|
||||
|
||||
/// @brief Handle the beginning of a function body
|
||||
virtual void handleFunctionBegin(
|
||||
Function* Func, unsigned Size
|
||||
);
|
||||
|
||||
/// @brief Handle the end of a function body
|
||||
virtual void handleFunctionEnd(
|
||||
Function* Func
|
||||
);
|
||||
|
||||
/// @brief Handle the beginning of a basic block
|
||||
virtual void handleBasicBlockBegin(
|
||||
unsigned blocknum
|
||||
);
|
||||
|
||||
/// This method is called for each instruction that is parsed.
|
||||
/// @returns true if the instruction is a block terminating instruction
|
||||
/// @brief Handle an instruction
|
||||
virtual bool handleInstruction(
|
||||
unsigned Opcode,
|
||||
const Type* iType,
|
||||
std::vector<unsigned>& Operands,
|
||||
unsigned Length
|
||||
);
|
||||
|
||||
/// @brief Handle the end of a basic block
|
||||
virtual void handleBasicBlockEnd(unsigned blocknum);
|
||||
|
||||
/// @brief Handle start of global constants block.
|
||||
virtual void handleGlobalConstantsBegin();
|
||||
|
||||
/// @brief Handle a constant expression
|
||||
virtual void handleConstantExpression(
|
||||
unsigned Opcode,
|
||||
const Type* Typ,
|
||||
std::vector<std::pair<const Type*,unsigned> > ArgVec
|
||||
);
|
||||
|
||||
/// @brief Handle a constant array
|
||||
virtual void handleConstantArray(
|
||||
const ArrayType* AT,
|
||||
std::vector<unsigned>& ElementSlots
|
||||
);
|
||||
|
||||
/// @brief Handle a constant structure
|
||||
virtual void handleConstantStruct(
|
||||
const StructType* ST,
|
||||
std::vector<unsigned>& ElementSlots
|
||||
);
|
||||
|
||||
/// @brief Handle a constant pointer
|
||||
virtual void handleConstantPointer(
|
||||
const PointerType* PT,
|
||||
unsigned Slot
|
||||
);
|
||||
|
||||
/// @brief Handle a constant strings (array special case)
|
||||
virtual void handleConstantString(
|
||||
const ConstantArray* CA
|
||||
);
|
||||
|
||||
/// @brief Handle a primitive constant value
|
||||
virtual void handleConstantValue( Constant * c );
|
||||
|
||||
/// @brief Handle the end of the global constants
|
||||
virtual void handleGlobalConstantsEnd();
|
||||
|
||||
/// @brief Handle an alignment event
|
||||
virtual void handleAlignment(unsigned numBytes);
|
||||
|
||||
virtual void handleBlock(
|
||||
unsigned BType, ///< The type of block
|
||||
const unsigned char* StartPtr, ///< The start of the block
|
||||
unsigned Size ///< The size of the block
|
||||
);
|
||||
virtual void handleVBR32(unsigned Size );
|
||||
virtual void handleVBR64(unsigned Size );
|
||||
/// @}
|
||||
|
||||
};
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
// vim: sw=2
|
||||
#endif
|
|
@ -1,297 +0,0 @@
|
|||
//===-- ReaderInternals.h - Definitions internal to the reader --*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by the LLVM research group and is distributed under
|
||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This header file defines various stuff that is used by the bytecode reader.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef READER_INTERNALS_H
|
||||
#define READER_INTERNALS_H
|
||||
|
||||
#include "ReaderPrimitives.h"
|
||||
#include "llvm/Constants.h"
|
||||
#include "llvm/DerivedTypes.h"
|
||||
#include "llvm/Function.h"
|
||||
#include "llvm/ModuleProvider.h"
|
||||
#include <utility>
|
||||
#include <map>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
// Enable to trace to figure out what the heck is going on when parsing fails
|
||||
//#define TRACE_LEVEL 10
|
||||
//#define DEBUG_OUTPUT
|
||||
|
||||
#if TRACE_LEVEL // ByteCodeReading_TRACEr
|
||||
#define BCR_TRACE(n, X) \
|
||||
if (n < TRACE_LEVEL) std::cerr << std::string(n*2, ' ') << X
|
||||
#else
|
||||
#define BCR_TRACE(n, X)
|
||||
#endif
|
||||
|
||||
struct LazyFunctionInfo {
|
||||
const unsigned char *Buf, *EndBuf;
|
||||
LazyFunctionInfo(const unsigned char *B = 0, const unsigned char *EB = 0)
|
||||
: Buf(B), EndBuf(EB) {}
|
||||
};
|
||||
|
||||
class BytecodeParser : public ModuleProvider {
|
||||
BytecodeParser(const BytecodeParser &); // DO NOT IMPLEMENT
|
||||
void operator=(const BytecodeParser &); // DO NOT IMPLEMENT
|
||||
public:
|
||||
BytecodeParser() {}
|
||||
|
||||
~BytecodeParser() {
|
||||
freeState();
|
||||
}
|
||||
void freeState() {
|
||||
freeTable(Values);
|
||||
freeTable(ModuleValues);
|
||||
}
|
||||
|
||||
Module* materializeModule() {
|
||||
while (! LazyFunctionLoadMap.empty()) {
|
||||
std::map<Function*, LazyFunctionInfo>::iterator i =
|
||||
LazyFunctionLoadMap.begin();
|
||||
materializeFunction((*i).first);
|
||||
}
|
||||
|
||||
return TheModule;
|
||||
}
|
||||
|
||||
Module* releaseModule() {
|
||||
// Since we're losing control of this Module, we must hand it back complete
|
||||
Module *M = ModuleProvider::releaseModule();
|
||||
freeState();
|
||||
return M;
|
||||
}
|
||||
|
||||
void ParseBytecode(const unsigned char *Buf, unsigned Length,
|
||||
const std::string &ModuleID);
|
||||
|
||||
void dump() const {
|
||||
std::cerr << "BytecodeParser instance!\n";
|
||||
}
|
||||
|
||||
private:
|
||||
struct ValueList : public User {
|
||||
ValueList() : User(Type::TypeTy, Value::TypeVal) {}
|
||||
|
||||
// vector compatibility methods
|
||||
unsigned size() const { return getNumOperands(); }
|
||||
void push_back(Value *V) { Operands.push_back(Use(V, this)); }
|
||||
Value *back() const { return Operands.back(); }
|
||||
void pop_back() { Operands.pop_back(); }
|
||||
bool empty() const { return Operands.empty(); }
|
||||
|
||||
virtual void print(std::ostream& OS) const {
|
||||
OS << "Bytecode Reader UseHandle!";
|
||||
}
|
||||
};
|
||||
|
||||
// Information about the module, extracted from the bytecode revision number.
|
||||
unsigned char RevisionNum; // The rev # itself
|
||||
|
||||
// Flags to distinguish LLVM 1.0 & 1.1 bytecode formats (revision #0)
|
||||
|
||||
// Revision #0 had an explicit alignment of data only for the ModuleGlobalInfo
|
||||
// block. This was fixed to be like all other blocks in 1.2
|
||||
bool hasInconsistentModuleGlobalInfo;
|
||||
|
||||
// Revision #0 also explicitly encoded zero values for primitive types like
|
||||
// int/sbyte/etc.
|
||||
bool hasExplicitPrimitiveZeros;
|
||||
|
||||
// Flags to control features specific the LLVM 1.2 and before (revision #1)
|
||||
|
||||
// LLVM 1.2 and earlier required that getelementptr structure indices were
|
||||
// ubyte constants and that sequential type indices were longs.
|
||||
bool hasRestrictedGEPTypes;
|
||||
|
||||
|
||||
typedef std::vector<ValueList*> ValueTable;
|
||||
ValueTable Values;
|
||||
ValueTable ModuleValues;
|
||||
std::map<std::pair<unsigned,unsigned>, Value*> ForwardReferences;
|
||||
|
||||
/// CompactionTable - If a compaction table is active in the current function,
|
||||
/// this is the mapping that it contains.
|
||||
std::vector<std::vector<Value*> > CompactionTable;
|
||||
|
||||
std::vector<BasicBlock*> ParsedBasicBlocks;
|
||||
|
||||
// ConstantFwdRefs - This maintains a mapping between <Type, Slot #>'s and
|
||||
// forward references to constants. Such values may be referenced before they
|
||||
// are defined, and if so, the temporary object that they represent is held
|
||||
// here.
|
||||
//
|
||||
typedef std::map<std::pair<const Type*,unsigned>, Constant*> ConstantRefsType;
|
||||
ConstantRefsType ConstantFwdRefs;
|
||||
|
||||
// TypesLoaded - This vector mirrors the Values[TypeTyID] plane. It is used
|
||||
// to deal with forward references to types.
|
||||
//
|
||||
typedef std::vector<PATypeHolder> TypeValuesListTy;
|
||||
TypeValuesListTy ModuleTypeValues;
|
||||
TypeValuesListTy FunctionTypeValues;
|
||||
|
||||
// When the ModuleGlobalInfo section is read, we create a function object for
|
||||
// each function in the module. When the function is loaded, this function is
|
||||
// filled in.
|
||||
//
|
||||
std::vector<Function*> FunctionSignatureList;
|
||||
|
||||
// Constant values are read in after global variables. Because of this, we
|
||||
// must defer setting the initializers on global variables until after module
|
||||
// level constants have been read. In the mean time, this list keeps track of
|
||||
// what we must do.
|
||||
//
|
||||
std::vector<std::pair<GlobalVariable*, unsigned> > GlobalInits;
|
||||
|
||||
// For lazy reading-in of functions, we need to save away several pieces of
|
||||
// information about each function: its begin and end pointer in the buffer
|
||||
// and its FunctionSlot.
|
||||
//
|
||||
std::map<Function*, LazyFunctionInfo> LazyFunctionLoadMap;
|
||||
|
||||
private:
|
||||
void freeTable(ValueTable &Tab) {
|
||||
while (!Tab.empty()) {
|
||||
delete Tab.back();
|
||||
Tab.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
/// getGlobalTableType - This is just like getType, but when a compaction
|
||||
/// table is in use, it is ignored. Also, no forward references or other
|
||||
/// fancy features are supported.
|
||||
const Type *getGlobalTableType(unsigned Slot) {
|
||||
if (Slot < Type::FirstDerivedTyID) {
|
||||
const Type *Ty = Type::getPrimitiveType((Type::TypeID)Slot);
|
||||
assert(Ty && "Not a primitive type ID?");
|
||||
return Ty;
|
||||
}
|
||||
Slot -= Type::FirstDerivedTyID;
|
||||
if (Slot >= ModuleTypeValues.size())
|
||||
throw std::string("Illegal compaction table type reference!");
|
||||
return ModuleTypeValues[Slot];
|
||||
}
|
||||
|
||||
unsigned getGlobalTableTypeSlot(const Type *Ty) {
|
||||
if (Ty->isPrimitiveType())
|
||||
return Ty->getTypeID();
|
||||
TypeValuesListTy::iterator I = find(ModuleTypeValues.begin(),
|
||||
ModuleTypeValues.end(), Ty);
|
||||
if (I == ModuleTypeValues.end())
|
||||
throw std::string("Didn't find type in ModuleTypeValues.");
|
||||
return Type::FirstDerivedTyID + (&*I - &ModuleTypeValues[0]);
|
||||
}
|
||||
|
||||
/// getGlobalTableValue - This is just like getValue, but when a compaction
|
||||
/// table is in use, it is ignored. Also, no forward references or other
|
||||
/// fancy features are supported.
|
||||
Value *getGlobalTableValue(const Type *Ty, unsigned SlotNo) {
|
||||
// FIXME: getTypeSlot is inefficient!
|
||||
unsigned TyID = getGlobalTableTypeSlot(Ty);
|
||||
|
||||
if (TyID != Type::LabelTyID) {
|
||||
if (SlotNo == 0)
|
||||
return Constant::getNullValue(Ty);
|
||||
--SlotNo;
|
||||
}
|
||||
|
||||
if (TyID >= ModuleValues.size() || ModuleValues[TyID] == 0 ||
|
||||
SlotNo >= ModuleValues[TyID]->getNumOperands()) {
|
||||
std::cerr << TyID << ", " << SlotNo << ": " << ModuleValues.size() << ", "
|
||||
<< (void*)ModuleValues[TyID] << ", "
|
||||
<< ModuleValues[TyID]->getNumOperands() << "\n";
|
||||
throw std::string("Corrupt compaction table entry!");
|
||||
}
|
||||
return ModuleValues[TyID]->getOperand(SlotNo);
|
||||
}
|
||||
|
||||
public:
|
||||
void ParseModule(const unsigned char * Buf, const unsigned char *End);
|
||||
void materializeFunction(Function *F);
|
||||
|
||||
private:
|
||||
void ParseVersionInfo (const unsigned char *&Buf, const unsigned char *End);
|
||||
void ParseModuleGlobalInfo(const unsigned char *&Buf, const unsigned char *E);
|
||||
void ParseSymbolTable(const unsigned char *&Buf, const unsigned char *End,
|
||||
SymbolTable *, Function *CurrentFunction);
|
||||
void ParseFunction(const unsigned char *&Buf, const unsigned char *End);
|
||||
void ParseCompactionTable(const unsigned char *&Buf,const unsigned char *End);
|
||||
void ParseGlobalTypes(const unsigned char *&Buf, const unsigned char *EndBuf);
|
||||
|
||||
BasicBlock *ParseBasicBlock(const unsigned char *&Buf,
|
||||
const unsigned char *End,
|
||||
unsigned BlockNo);
|
||||
unsigned ParseInstructionList(Function *F, const unsigned char *&Buf,
|
||||
const unsigned char *EndBuf);
|
||||
|
||||
void ParseInstruction(const unsigned char *&Buf, const unsigned char *End,
|
||||
std::vector<unsigned> &Args, BasicBlock *BB);
|
||||
|
||||
void ParseConstantPool(const unsigned char *&Buf, const unsigned char *EndBuf,
|
||||
ValueTable &Tab, TypeValuesListTy &TypeTab);
|
||||
Constant *parseConstantValue(const unsigned char *&Buf,
|
||||
const unsigned char *End,
|
||||
unsigned TypeID);
|
||||
void parseTypeConstants(const unsigned char *&Buf,
|
||||
const unsigned char *EndBuf,
|
||||
TypeValuesListTy &Tab, unsigned NumEntries);
|
||||
const Type *parseTypeConstant(const unsigned char *&Buf,
|
||||
const unsigned char *EndBuf);
|
||||
void parseStringConstants(const unsigned char *&Buf,
|
||||
const unsigned char *EndBuf,
|
||||
unsigned NumEntries, ValueTable &Tab);
|
||||
|
||||
Value *getValue(unsigned TypeID, unsigned num, bool Create = true);
|
||||
const Type *getType(unsigned ID);
|
||||
BasicBlock *getBasicBlock(unsigned ID);
|
||||
Constant *getConstantValue(unsigned TypeID, unsigned num);
|
||||
Constant *getConstantValue(const Type *Ty, unsigned num) {
|
||||
return getConstantValue(getTypeSlot(Ty), num);
|
||||
}
|
||||
|
||||
unsigned insertValue(Value *V, unsigned Type, ValueTable &Table);
|
||||
|
||||
unsigned getTypeSlot(const Type *Ty);
|
||||
|
||||
// resolve all references to the placeholder (if any) for the given constant
|
||||
void ResolveReferencesToConstant(Constant *C, unsigned Slot);
|
||||
};
|
||||
|
||||
template<class SuperType>
|
||||
class PlaceholderDef : public SuperType {
|
||||
unsigned ID;
|
||||
PlaceholderDef(); // DO NOT IMPLEMENT
|
||||
void operator=(const PlaceholderDef &); // DO NOT IMPLEMENT
|
||||
public:
|
||||
PlaceholderDef(const Type *Ty, unsigned id) : SuperType(Ty), ID(id) {}
|
||||
unsigned getID() { return ID; }
|
||||
};
|
||||
|
||||
struct ConstantPlaceHolderHelper : public ConstantExpr {
|
||||
ConstantPlaceHolderHelper(const Type *Ty)
|
||||
: ConstantExpr(Instruction::UserOp1, Constant::getNullValue(Ty), Ty) {}
|
||||
};
|
||||
|
||||
typedef PlaceholderDef<ConstantPlaceHolderHelper> ConstPHolder;
|
||||
|
||||
static inline void readBlock(const unsigned char *&Buf,
|
||||
const unsigned char *EndBuf,
|
||||
unsigned &Type, unsigned &Size) {
|
||||
Type = read(Buf, EndBuf);
|
||||
Size = read(Buf, EndBuf);
|
||||
}
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
|
@ -1,101 +0,0 @@
|
|||
//===-- ReaderPrimitives.h - Bytecode file format reading prims -*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by the LLVM research group and is distributed under
|
||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This header defines some basic functions for reading basic primitive types
|
||||
// from a bytecode stream.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef READERPRIMITIVES_H
|
||||
#define READERPRIMITIVES_H
|
||||
|
||||
#include "Support/DataTypes.h"
|
||||
#include <string>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// @brief Read an unsigned integer
|
||||
static inline unsigned read(const unsigned char *&Buf,
|
||||
const unsigned char *EndBuf) {
|
||||
if (Buf+4 > EndBuf) throw std::string("Ran out of data!");
|
||||
Buf += 4;
|
||||
return Buf[-4] | (Buf[-3] << 8) | (Buf[-2] << 16) | (Buf[-1] << 24);
|
||||
}
|
||||
|
||||
|
||||
/// @brief Read an unsigned integer encoded in variable bitrate format.
|
||||
static inline unsigned read_vbr_uint(const unsigned char *&Buf,
|
||||
const unsigned char *EndBuf) {
|
||||
unsigned Shift = 0;
|
||||
unsigned Result = 0;
|
||||
|
||||
do {
|
||||
if (Buf == EndBuf) throw std::string("Ran out of data!");
|
||||
Result |= (unsigned)((*Buf++) & 0x7F) << Shift;
|
||||
Shift += 7;
|
||||
} while (Buf[-1] & 0x80);
|
||||
return Result;
|
||||
}
|
||||
|
||||
static inline uint64_t read_vbr_uint64(const unsigned char *&Buf,
|
||||
const unsigned char *EndBuf) {
|
||||
unsigned Shift = 0;
|
||||
uint64_t Result = 0;
|
||||
|
||||
do {
|
||||
if (Buf == EndBuf) throw std::string("Ran out of data!");
|
||||
Result |= (uint64_t)((*Buf++) & 0x7F) << Shift;
|
||||
Shift += 7;
|
||||
} while (Buf[-1] & 0x80);
|
||||
return Result;
|
||||
}
|
||||
|
||||
static inline int64_t read_vbr_int64(const unsigned char *&Buf,
|
||||
const unsigned char *EndBuf) {
|
||||
uint64_t R = read_vbr_uint64(Buf, EndBuf);
|
||||
if (R & 1) {
|
||||
if (R != 1)
|
||||
return -(int64_t)(R >> 1);
|
||||
else // There is no such thing as -0 with integers. "-0" really means
|
||||
// 0x8000000000000000.
|
||||
return 1LL << 63;
|
||||
} else
|
||||
return (int64_t)(R >> 1);
|
||||
}
|
||||
|
||||
// align32 - Round up to multiple of 32 bits...
|
||||
static inline void align32(const unsigned char *&Buf,
|
||||
const unsigned char *EndBuf) {
|
||||
Buf = (const unsigned char *)((unsigned long)(Buf+3) & (~3UL));
|
||||
if (Buf > EndBuf) throw std::string("Ran out of data!");
|
||||
}
|
||||
|
||||
static inline std::string read_str(const unsigned char *&Buf,
|
||||
const unsigned char *EndBuf) {
|
||||
unsigned Size = read_vbr_uint(Buf, EndBuf);
|
||||
const unsigned char *OldBuf = Buf;
|
||||
Buf += Size;
|
||||
if (Buf > EndBuf) // Size invalid?
|
||||
throw std::string("Ran out of data reading a string!");
|
||||
return std::string((char*)OldBuf, Size);
|
||||
}
|
||||
|
||||
static inline void input_data(const unsigned char *&Buf,
|
||||
const unsigned char *EndBuf,
|
||||
void *Ptr, void *End) {
|
||||
unsigned char *Start = (unsigned char *)Ptr;
|
||||
unsigned Amount = (unsigned char *)End - Start;
|
||||
if (Buf+Amount > EndBuf) throw std::string("Ran out of data!");
|
||||
std::copy(Buf, Buf+Amount, Start);
|
||||
Buf += Amount;
|
||||
}
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue