From 500984b9187a3ad4c3524fa09cd4334b5573eef0 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Fri, 23 May 2003 20:03:32 +0000 Subject: [PATCH] Fix Bug: Linker/2003-04-26-NullPtrLinkProblem.ll This was a problem with constants having their types resolved to some new type, but there was already a constant of the new type created. Before, these types were never merged together, now they are. llvm-svn: 6314 --- lib/VMCore/Constants.cpp | 299 +++++++++++++++++++++++++-------------- 1 file changed, 195 insertions(+), 104 deletions(-) diff --git a/lib/VMCore/Constants.cpp b/lib/VMCore/Constants.cpp index 273ab07293c..76904ad3f97 100644 --- a/lib/VMCore/Constants.cpp +++ b/lib/VMCore/Constants.cpp @@ -451,52 +451,72 @@ void ConstantExpr::replaceUsesOfWithOnConstant(Value *From, Value *ToV) { destroyConstant(); } - - //===----------------------------------------------------------------------===// // Factory Function Implementation -template -struct ValueMap { - typedef std::pair ConstHashKey; - std::map Map; - - inline ConstantClass *get(const Type *Ty, ValType V) { - typename std::map::iterator I = - Map.find(ConstHashKey(Ty, V)); - return (I != Map.end()) ? I->second : 0; - } - - inline void add(const Type *Ty, ValType V, ConstantClass *CP) { - Map.insert(std::make_pair(ConstHashKey(Ty, V), CP)); - } - - inline void remove(ConstantClass *CP) { - for (typename std::map::iterator - I = Map.begin(), E = Map.end(); I != E; ++I) - if (I->second == CP) { - Map.erase(I); - return; - } +// ConstantCreator - A class that is used to create constants by +// ValueMap*. This class should be partially specialized if there is +// something strange that needs to be done to interface to the ctor for the +// constant. +// +template +struct ConstantCreator { + static ConstantClass *create(const TypeClass *Ty, const ValType &V) { + return new ConstantClass(Ty, V); } }; +namespace { + template + class ValueMap { + protected: + typedef std::pair ConstHashKey; + std::map Map; + public: + // getOrCreate - Return the specified constant from the map, creating it if + // necessary. + ConstantClass *getOrCreate(const TypeClass *Ty, const ValType &V) { + ConstHashKey Lookup(Ty, V); + typename std::map::iterator I = + Map.lower_bound(Lookup); + if (I != Map.end() && I->first == Lookup) + return I->second; // Is it in the map? + + // If no preexisting value, create one now... + ConstantClass *Result = + ConstantCreator::create(Ty, V); + + Map.insert(I, std::make_pair(ConstHashKey(Ty, V), Result)); + return Result; + } + + void remove(ConstantClass *CP) { + // FIXME: This could be sped up a LOT. If this gets to be a performance + // problem, someone should look at this. + for (typename std::map::iterator + I = Map.begin(), E = Map.end(); I != E; ++I) + if (I->second == CP) { + Map.erase(I); + return; + } + assert(0 && "Constant not found in constant table!"); + } + }; +} + + + //---- ConstantUInt::get() and ConstantSInt::get() implementations... // -static ValueMap IntConstants; +static ValueMap< int64_t, Type, ConstantSInt> SIntConstants; +static ValueMap UIntConstants; ConstantSInt *ConstantSInt::get(const Type *Ty, int64_t V) { - ConstantSInt *Result = (ConstantSInt*)IntConstants.get(Ty, (uint64_t)V); - if (!Result) // If no preexisting value, create one now... - IntConstants.add(Ty, V, Result = new ConstantSInt(Ty, V)); - return Result; + return SIntConstants.getOrCreate(Ty, V); } ConstantUInt *ConstantUInt::get(const Type *Ty, uint64_t V) { - ConstantUInt *Result = (ConstantUInt*)IntConstants.get(Ty, V); - if (!Result) // If no preexisting value, create one now... - IntConstants.add(Ty, V, Result = new ConstantUInt(Ty, V)); - return Result; + return UIntConstants.getOrCreate(Ty, V); } ConstantInt *ConstantInt::get(const Type *Ty, unsigned char V) { @@ -507,27 +527,46 @@ ConstantInt *ConstantInt::get(const Type *Ty, unsigned char V) { //---- ConstantFP::get() implementation... // -static ValueMap FPConstants; +static ValueMap FPConstants; ConstantFP *ConstantFP::get(const Type *Ty, double V) { - ConstantFP *Result = FPConstants.get(Ty, V); - if (!Result) // If no preexisting value, create one now... - FPConstants.add(Ty, V, Result = new ConstantFP(Ty, V)); - return Result; + return FPConstants.getOrCreate(Ty, V); } //---- ConstantArray::get() implementation... // -static ValueMap, ConstantArray> ArrayConstants; +static ValueMap, ArrayType, + ConstantArray> ArrayConstants; ConstantArray *ConstantArray::get(const ArrayType *Ty, const std::vector &V) { - ConstantArray *Result = ArrayConstants.get(Ty, V); - if (!Result) // If no preexisting value, create one now... - ArrayConstants.add(Ty, V, Result = new ConstantArray(Ty, V)); - return Result; + return ArrayConstants.getOrCreate(Ty, V); } +// destroyConstant - Remove the constant from the constant table... +// +void ConstantArray::destroyConstant() { + ArrayConstants.remove(this); + destroyConstantImpl(); +} + +/// refineAbstractType - If this callback is invoked, then this constant is of a +/// derived type, change all users to use a concrete constant of the new type. +/// +void ConstantArray::refineAbstractType(const DerivedType *OldTy, + const Type *NewTy) { + Value::refineAbstractType(OldTy, NewTy); + + // Make everyone now use a constant of the new type... + std::vector C; + for (unsigned i = 0, e = getNumOperands(); i != e; ++i) + C.push_back(cast(getOperand(i))); + replaceAllUsesWith(ConstantArray::get(cast(NewTy), + C)); + destroyConstant(); // This constant is now dead, destroy it. +} + + // ConstantArray::get(const string&) - Return an array that is initialized to // contain the specified string. A null terminator is added to the specified // string so that it may be used in a natural way... @@ -545,14 +584,6 @@ ConstantArray *ConstantArray::get(const std::string &Str) { return ConstantArray::get(ATy, ElementVals); } - -// destroyConstant - Remove the constant from the constant table... -// -void ConstantArray::destroyConstant() { - ArrayConstants.remove(this); - destroyConstantImpl(); -} - // getAsString - If the sub-element type of this array is either sbyte or ubyte, // then this method converts the array to an std::string and returns it. // Otherwise, it asserts out. @@ -573,14 +604,12 @@ std::string ConstantArray::getAsString() const { //---- ConstantStruct::get() implementation... // -static ValueMap, ConstantStruct> StructConstants; +static ValueMap, StructType, + ConstantStruct> StructConstants; ConstantStruct *ConstantStruct::get(const StructType *Ty, const std::vector &V) { - ConstantStruct *Result = StructConstants.get(Ty, V); - if (!Result) // If no preexisting value, create one now... - StructConstants.add(Ty, V, Result = new ConstantStruct(Ty, V)); - return Result; + return StructConstants.getOrCreate(Ty, V); } // destroyConstant - Remove the constant from the constant table... @@ -590,16 +619,38 @@ void ConstantStruct::destroyConstant() { destroyConstantImpl(); } +/// refineAbstractType - If this callback is invoked, then this constant is of a +/// derived type, change all users to use a concrete constant of the new type. +/// +void ConstantStruct::refineAbstractType(const DerivedType *OldTy, + const Type *NewTy) { + Value::refineAbstractType(OldTy, NewTy); + + // Make everyone now use a constant of the new type... + std::vector C; + for (unsigned i = 0, e = getNumOperands(); i != e; ++i) + C.push_back(cast(getOperand(i))); + replaceAllUsesWith(ConstantStruct::get(cast(NewTy), + C)); + destroyConstant(); // This constant is now dead, destroy it. +} + //---- ConstantPointerNull::get() implementation... // -static ValueMap NullPtrConstants; + +// ConstantPointerNull does not take extra "value" argument... +template +struct ConstantCreator { + static ConstantPointerNull *create(const PointerType *Ty, const ValType &V){ + return new ConstantPointerNull(Ty); + } +}; + +static ValueMap NullPtrConstants; ConstantPointerNull *ConstantPointerNull::get(const PointerType *Ty) { - ConstantPointerNull *Result = NullPtrConstants.get(Ty, 0); - if (!Result) // If no preexisting value, create one now... - NullPtrConstants.add(Ty, 0, Result = new ConstantPointerNull(Ty)); - return Result; + return NullPtrConstants.getOrCreate(Ty, 0); } // destroyConstant - Remove the constant from the constant table... @@ -609,6 +660,21 @@ void ConstantPointerNull::destroyConstant() { destroyConstantImpl(); } +/// refineAbstractType - If this callback is invoked, then this constant is of a +/// derived type, change all users to use a concrete constant of the new type. +/// +void ConstantPointerNull::refineAbstractType(const DerivedType *OldTy, + const Type *NewTy) { + Value::refineAbstractType(OldTy, NewTy); + + // Make everyone now use a constant of the new type... + replaceAllUsesWith(ConstantPointerNull::get(cast(NewTy))); + + // This constant is now dead, destroy it. + destroyConstant(); +} + + //---- ConstantPointerRef::get() implementation... // @@ -630,7 +696,31 @@ void ConstantPointerRef::destroyConstant() { //---- ConstantExpr::get() implementations... // typedef std::pair > ExprMapKeyType; -static ValueMap ExprConstants; + +template<> +struct ConstantCreator { + static ConstantExpr *create(const Type *Ty, const ExprMapKeyType &V) { + if (V.first == Instruction::Cast) + return new ConstantExpr(Instruction::Cast, V.second[0], Ty); + if ((V.first >= Instruction::BinaryOpsBegin && + V.first < Instruction::BinaryOpsEnd) || + V.first == Instruction::Shl || V.first == Instruction::Shr) + return new ConstantExpr(V.first, V.second[0], V.second[1]); + + assert(V.first == Instruction::GetElementPtr && "Invalid ConstantExpr!"); + + // Check that the indices list is valid... + std::vector ValIdxList(V.second.begin()+1, V.second.end()); + const Type *DestTy = GetElementPtrInst::getIndexedType(Ty, ValIdxList, + true); + assert(DestTy && "Invalid index list for GetElementPtr expression"); + + std::vector IdxList(V.second.begin()+1, V.second.end()); + return new ConstantExpr(V.second[0], IdxList, PointerType::get(DestTy)); + } +}; + +static ValueMap ExprConstants; Constant *ConstantExpr::getCast(Constant *C, const Type *Ty) { if (Constant *FC = ConstantFoldCastInstruction(C, Ty)) @@ -638,14 +728,8 @@ Constant *ConstantExpr::getCast(Constant *C, const Type *Ty) { // Look up the constant in the table first to ensure uniqueness std::vector argVec(1, C); - const ExprMapKeyType &Key = std::make_pair(Instruction::Cast, argVec); - ConstantExpr *Result = ExprConstants.get(Ty, Key); - if (Result) return Result; - - // Its not in the table so create a new one and put it in the table. - Result = new ConstantExpr(Instruction::Cast, C, Ty); - ExprConstants.add(Ty, Key, Result); - return Result; + ExprMapKeyType Key = std::make_pair(Instruction::Cast, argVec); + return ExprConstants.getOrCreate(Ty, Key); } Constant *ConstantExpr::get(unsigned Opcode, Constant *C1, Constant *C2) { @@ -659,16 +743,9 @@ Constant *ConstantExpr::get(unsigned Opcode, Constant *C1, Constant *C2) { if (Constant *FC = ConstantFoldBinaryInstruction(Opcode, C1, C2)) return FC; // Fold a few common cases... - // Look up the constant in the table first to ensure uniqueness std::vector argVec(1, C1); argVec.push_back(C2); - const ExprMapKeyType &Key = std::make_pair(Opcode, argVec); - ConstantExpr *Result = ExprConstants.get(C1->getType(), Key); - if (Result) return Result; - - // It's not in the table so create a new one and put it in the table. - Result = new ConstantExpr(Opcode, C1, C2); - ExprConstants.add(C1->getType(), Key, Result); - return Result; + ExprMapKeyType Key = std::make_pair(Opcode, argVec); + return ExprConstants.getOrCreate(C1->getType(), Key); } /// getShift - Return a shift left or shift right constant expr @@ -685,14 +762,8 @@ Constant *ConstantExpr::getShift(unsigned Opcode, Constant *C1, Constant *C2) { // Look up the constant in the table first to ensure uniqueness std::vector argVec(1, C1); argVec.push_back(C2); - const ExprMapKeyType &Key = std::make_pair(Opcode, argVec); - ConstantExpr *Result = ExprConstants.get(C1->getType(), Key); - if (Result) return Result; - - // It's not in the table so create a new one and put it in the table. - Result = new ConstantExpr(Opcode, C1, C2); - ExprConstants.add(C1->getType(), Key, Result); - return Result; + ExprMapKeyType Key = std::make_pair(Opcode, argVec); + return ExprConstants.getOrCreate(C1->getType(), Key); } @@ -701,29 +772,15 @@ Constant *ConstantExpr::getGetElementPtr(Constant *C, if (Constant *FC = ConstantFoldGetElementPtr(C, IdxList)) return FC; // Fold a few common cases... const Type *Ty = C->getType(); + assert(isa(Ty) && + "Non-pointer type for constant GetElementPtr expression"); // Look up the constant in the table first to ensure uniqueness std::vector argVec(1, C); argVec.insert(argVec.end(), IdxList.begin(), IdxList.end()); const ExprMapKeyType &Key = std::make_pair(Instruction::GetElementPtr,argVec); - ConstantExpr *Result = ExprConstants.get(Ty, Key); - if (Result) return Result; - - // Its not in the table so create a new one and put it in the table. - // Check the operands for consistency first - // - assert(isa(Ty) && - "Non-pointer type for constant GelElementPtr expression"); - - // Check that the indices list is valid... - std::vector ValIdxList(IdxList.begin(), IdxList.end()); - const Type *DestTy = GetElementPtrInst::getIndexedType(Ty, ValIdxList, true); - assert(DestTy && "Invalid index list for constant GelElementPtr expression"); - - Result = new ConstantExpr(C, IdxList, PointerType::get(DestTy)); - ExprConstants.add(Ty, Key, Result); - return Result; + return ExprConstants.getOrCreate(Ty, Key); } // destroyConstant - Remove the constant from the constant table... @@ -733,6 +790,40 @@ void ConstantExpr::destroyConstant() { destroyConstantImpl(); } +/// refineAbstractType - If this callback is invoked, then this constant is of a +/// derived type, change all users to use a concrete constant of the new type. +/// +void ConstantExpr::refineAbstractType(const DerivedType *OldTy, + const Type *NewTy) { + Value::refineAbstractType(OldTy, NewTy); + + // FIXME: These need to use a lower-level implementation method, because the + // ::get methods intuit the type of the result based on the types of the + // operands. The operand types may not have had their types resolved yet. + // + if (getOpcode() == Instruction::Cast) { + replaceAllUsesWith(getCast(getOperand(0), NewTy)); + } else if (getOpcode() >= Instruction::BinaryOpsBegin && + getOpcode() < Instruction::BinaryOpsEnd) { + replaceAllUsesWith(get(getOpcode(), getOperand(0), getOperand(0))); + } else if (getOpcode() == Instruction::Shl || getOpcode() ==Instruction::Shr){ + replaceAllUsesWith(getShift(getOpcode(), getOperand(0), getOperand(0))); + } else { + assert(getOpcode() == Instruction::GetElementPtr); + + // Make everyone now use a constant of the new type... + std::vector C; + for (unsigned i = 1, e = getNumOperands(); i != e; ++i) + C.push_back(cast(getOperand(i))); + replaceAllUsesWith(ConstantExpr::getGetElementPtr(getOperand(0), + C)); + } + destroyConstant(); // This constant is now dead, destroy it. +} + + + + const char *ConstantExpr::getOpcodeName() const { return Instruction::getOpcodeName(getOpcode()); }