diff --git a/lib/Bitcode/Reader/BitcodeReader.cpp b/lib/Bitcode/Reader/BitcodeReader.cpp index d974ace209c..fa75e00e6ca 100644 --- a/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/lib/Bitcode/Reader/BitcodeReader.cpp @@ -55,6 +55,39 @@ static GlobalValue::VisibilityTypes GetDecodedVisibility(unsigned Val) { } } +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 { + ConstantPlaceHolder(); // DO NOT IMPLEMENT + void operator=(const ConstantPlaceHolder &); // DO NOT IMPLEMENT +public: + Use Op; + ConstantPlaceHolder(const Type *Ty) + : ConstantExpr(Ty, Instruction::UserOp1, &Op, 1), + Op(UndefValue::get(Type::Int32Ty), this) { + } + }; +} + +Constant *BitcodeReaderValueList::getConstantFwdRef(unsigned Idx, + const Type *Ty) { + if (Idx >= size()) { + // Insert a bunch of null values. + Uses.resize(Idx+1); + OperandList = &Uses[0]; + NumOperands = Idx+1; + } + + if (Uses[Idx]) + return cast(getOperand(Idx)); + + // Create and return a placeholder, which will later be RAUW'd. + Constant *C = new ConstantPlaceHolder(Ty); + Uses[Idx].init(C, this); + return C; +} + const Type *BitcodeReader::getTypeByID(unsigned ID, bool isTypeTable) { // If the TypeID is in range, return it. @@ -324,6 +357,7 @@ bool BitcodeReader::ParseConstants(BitstreamReader &Stream) { // Read all the records for this value table. const Type *CurTy = Type::Int32Ty; + unsigned NextCstNo = ValueList.size(); while (1) { unsigned Code = Stream.ReadCode(); if (Code == bitc::END_BLOCK) { @@ -341,6 +375,9 @@ bool BitcodeReader::ParseConstants(BitstreamReader &Stream) { } } + if (NextCstNo != ValueList.size()) + return Error("Invalid constant reference!"); + return Stream.ReadBlockEnd(); } @@ -403,9 +440,48 @@ bool BitcodeReader::ParseConstants(BitstreamReader &Stream) { else V = UndefValue::get(CurTy); break; + + case bitc::CST_CODE_AGGREGATE: {// AGGREGATE: [n, n x value number] + if (Record.empty() || Record.size() < Record[0]+1) + return Error("Invalid CST_AGGREGATE record"); + + unsigned Size = Record[0]; + std::vector Elts; + + if (const StructType *STy = dyn_cast(CurTy)) { + for (unsigned i = 0; i != Size; ++i) + Elts.push_back(ValueList.getConstantFwdRef(Record[i+1], + STy->getElementType(i))); + V = ConstantStruct::get(STy, Elts); + } else if (const ArrayType *ATy = dyn_cast(CurTy)) { + const Type *EltTy = ATy->getElementType(); + for (unsigned i = 0; i != Size; ++i) + Elts.push_back(ValueList.getConstantFwdRef(Record[i+1], EltTy)); + V = ConstantArray::get(ATy, Elts); + } else if (const VectorType *VTy = dyn_cast(CurTy)) { + const Type *EltTy = VTy->getElementType(); + for (unsigned i = 0; i != Size; ++i) + Elts.push_back(ValueList.getConstantFwdRef(Record[i+1], EltTy)); + V = ConstantVector::get(Elts); + } else { + V = UndefValue::get(CurTy); + } + } } - ValueList.push_back(V); + if (NextCstNo == ValueList.size()) + ValueList.push_back(V); + else if (ValueList[NextCstNo] == 0) + ValueList.initVal(NextCstNo, V); + else { + // If there was a forward reference to this constant, + Value *OldV = ValueList[NextCstNo]; + ValueList.setOperand(NextCstNo, V); + OldV->replaceAllUsesWith(V); + delete OldV; + } + + ++NextCstNo; } } diff --git a/lib/Bitcode/Reader/BitcodeReader.h b/lib/Bitcode/Reader/BitcodeReader.h index bdb64c8c99e..c7c61529ffc 100644 --- a/lib/Bitcode/Reader/BitcodeReader.h +++ b/lib/Bitcode/Reader/BitcodeReader.h @@ -14,21 +14,48 @@ #ifndef BITCODE_READER_H #define BITCODE_READER_H -#include "llvm/Type.h" #include "llvm/ModuleProvider.h" +#include "llvm/Type.h" +#include "llvm/User.h" #include "llvm/Bitcode/LLVMBitCodes.h" #include namespace llvm { class BitstreamReader; - class Value; - class GlobalVariable; + +class BitcodeReaderValueList : public User { + std::vector Uses; +public: + BitcodeReaderValueList() : User(Type::VoidTy, Value::ArgumentVal, 0, 0) {} + + // vector compatibility methods + unsigned size() const { return getNumOperands(); } + void push_back(Value *V) { + Uses.push_back(Use(V, this)); + OperandList = &Uses[0]; + ++NumOperands; + } + + Value *operator[](unsigned i) const { return getOperand(i); } + + Value *back() const { return Uses.back(); } + void pop_back() { Uses.pop_back(); --NumOperands; } + bool empty() const { return NumOperands == 0; } + virtual void print(std::ostream&) const {} + + Constant *getConstantFwdRef(unsigned Idx, const Type *Ty); + void initVal(unsigned Idx, Value *V) { + assert(Uses[Idx] == 0 && "Cannot init an already init'd Use!"); + Uses[Idx].init(V, this); + } +}; + class BitcodeReader : public ModuleProvider { const char *ErrorString; std::vector TypeList; - std::vector ValueList; + BitcodeReaderValueList ValueList; std::vector > GlobalInits; public: virtual ~BitcodeReader() {}