Refactor BitcodeReader: move Metadata and ValueId handling in their own class/file

Summary:
I'm planning on changing the way we load metadata to enable laziness.
I'm getting lost in this gigantic files, and gigantic class that is the bitcode
reader. This is a first toward splitting it in a few coarse components that
are more easily understandable.

Reviewers: pcc, tejohnson

Subscribers: mgorny, llvm-commits, dexonsmith

Differential Revision: https://reviews.llvm.org/D27646

llvm-svn: 289461
This commit is contained in:
Mehdi Amini 2016-12-12 19:34:26 +00:00
parent 7aff2bb3d2
commit ef27db879c
6 changed files with 1694 additions and 1395 deletions

File diff suppressed because it is too large Load Diff

View File

@ -2,6 +2,8 @@ add_llvm_library(LLVMBitReader
BitReader.cpp
BitcodeReader.cpp
BitstreamReader.cpp
MetadataLoader.cpp
ValueList.cpp
ADDITIONAL_HEADER_DIRS
${LLVM_MAIN_INCLUDE_DIR}/llvm/Bitcode

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,79 @@
//===-- Bitcode/Reader/MetadataLoader.h - Load Metadatas -------*- C++ -*-====//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This class handles loading Metadatas.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIB_BITCODE_READER_METADATALOADER_H
#define LLVM_LIB_BITCODE_READER_METADATALOADER_H
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Error.h"
#include <functional>
#include <memory>
namespace llvm {
class BitcodeReaderValueList;
class BitstreamCursor;
class DISubprogram;
class Error;
class Function;
class Instruction;
class Metadata;
class MDNode;
class Module;
class Type;
/// Helper class that handles loading Metadatas and keeping them available.
class MetadataLoader {
class MetadataLoaderImpl;
std::unique_ptr<MetadataLoaderImpl> Pimpl;
Error parseMetadata(bool ModuleLevel);
public:
~MetadataLoader();
MetadataLoader(BitstreamCursor &Stream, Module &TheModule,
BitcodeReaderValueList &ValueList,
std::function<Type *(unsigned)> getTypeByID);
MetadataLoader &operator=(MetadataLoader &&);
MetadataLoader(MetadataLoader &&);
// Parse a module metadata block
Error parseModuleMetadata() { return parseMetadata(true); }
// Parse a function metadata block
Error parseFunctionMetadata() { return parseMetadata(false); }
// Return true there are remaining unresolved forward references.
bool hasFwdRefs() const;
/// Return the given metadata, creating a replaceable forward reference if
/// necessary.
Metadata *getMetadataFwdRef(unsigned Idx);
MDNode *getMDNodeFwdRefOrNull(unsigned Idx);
/// Return the DISubprogra metadata for a Function if any, null otherwise.
DISubprogram *lookupSubprogramForFunction(Function *F);
/// Parse a `METADATA_ATTACHMENT` block for a function.
Error parseMetadataAttachment(
Function &F, const SmallVectorImpl<Instruction *> &InstructionList);
/// Parse a `METADATA_KIND` block for the current module.
Error parseMetadataKinds();
unsigned size() const;
void shrinkTo(unsigned N);
};
}
#endif // LLVM_LIB_BITCODE_READER_METADATALOADER_H

View File

@ -0,0 +1,199 @@
//===----- ValueList.cpp - Internal BitcodeReader implementation ----------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "ValueList.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Instructions.h"
using namespace llvm;
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 &) = delete;
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);
};
} // end anonymous namespace
// FIXME: can we inherit this from ConstantExpr?
template <>
struct OperandTraits<ConstantPlaceHolder>
: public FixedNumOperandTraits<ConstantPlaceHolder, 1> {};
DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ConstantPlaceHolder, Value)
} // end namespace llvm
void BitcodeReaderValueList::assignValue(Value *V, unsigned Idx) {
if (Idx == size()) {
push_back(V);
return;
}
if (Idx >= size())
resize(Idx + 1);
WeakVH &OldV = ValuePtrs[Idx];
if (!OldV) {
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;
}
}
Constant *BitcodeReaderValueList::getConstantFwdRef(unsigned Idx, Type *Ty) {
if (Idx >= size())
resize(Idx + 1);
if (Value *V = ValuePtrs[Idx]) {
if (Ty != V->getType())
report_fatal_error("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 *BitcodeReaderValueList::getValueFwdRef(unsigned Idx, Type *Ty) {
// Bail out for a clearly invalid value. This would make us call resize(0)
if (Idx == std::numeric_limits<unsigned>::max())
return nullptr;
if (Idx >= size())
resize(Idx + 1);
if (Value *V = ValuePtrs[Idx]) {
// If the types don't match, it's invalid.
if (Ty && Ty != V->getType())
return nullptr;
return V;
}
// No type specified, must be invalid reference.
if (!Ty)
return nullptr;
// Create and return a placeholder, which will later be RAUW'd.
Value *V = new Argument(Ty);
ValuePtrs[Idx] = V;
return V;
}
/// 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 BitcodeReaderValueList::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()) {
auto UI = Placeholder->user_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;
}
}

View File

@ -0,0 +1,76 @@
//===-- Bitcode/Reader/ValueEnumerator.h - Number values --------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This class gives values and types Unique ID's.
//
//===----------------------------------------------------------------------===//
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/ValueHandle.h"
#include <vector>
namespace llvm {
class Constant;
class BitcodeReaderValueList {
std::vector<WeakVH> ValuePtrs;
/// As we resolve forward-referenced constants, we add information about them
/// to this vector. This allows us to resolve them in bulk instead of
/// resolving each reference at a time. See the code in
/// ResolveConstantForwardRefs for more information about this.
///
/// The key of this vector is the placeholder constant, the value is the slot
/// number that holds the resolved value.
typedef std::vector<std::pair<Constant *, unsigned>> ResolveConstantsTy;
ResolveConstantsTy ResolveConstants;
LLVMContext &Context;
public:
BitcodeReaderValueList(LLVMContext &C) : Context(C) {}
~BitcodeReaderValueList() {
assert(ResolveConstants.empty() && "Constants not resolved?");
}
// vector compatibility methods
unsigned size() const { return ValuePtrs.size(); }
void resize(unsigned N) { ValuePtrs.resize(N); }
void push_back(Value *V) { ValuePtrs.emplace_back(V); }
void clear() {
assert(ResolveConstants.empty() && "Constants not resolved?");
ValuePtrs.clear();
}
Value *operator[](unsigned i) const {
assert(i < ValuePtrs.size());
return ValuePtrs[i];
}
Value *back() const { return ValuePtrs.back(); }
void pop_back() { ValuePtrs.pop_back(); }
bool empty() const { return ValuePtrs.empty(); }
void shrinkTo(unsigned N) {
assert(N <= size() && "Invalid shrinkTo request!");
ValuePtrs.resize(N);
}
Constant *getConstantFwdRef(unsigned Idx, Type *Ty);
Value *getValueFwdRef(unsigned Idx, Type *Ty);
void assignValue(Value *V, unsigned Idx);
/// Once all constants are read, this method bulk resolves any forward
/// references.
void resolveConstantForwardRefs();
};
} // namespace llvm