One more time .. This one avoids collisions in the IntConstants map by using APInt directly in the DenseMap. This was made possible by relaxing APInt::operator= and using a small structure for the key type so that we can do operator== correctly for APInt (handling different bit widths).
This passes tests. I'm likely to commit this soonish. Reid. On Mon, 2007-02-26 at 12:44 -0800, Reid Spencer wrote: > Chris, > > Here is round two. This is a slightly larger patch that also includes > the following changes: > > * APInt::getValue() -> getSExtValue() and getZExtValue() > * const APInt& ConstantInt::getValue() const { return Val; } > * ConstantInt::get(const Type*, const APInt&) > * APInt constructor for ConstantInt::get to use > * APInt::getHashValue() -- used for the DenseMap of ConstantInt > values. > * Changes in Constants.cpp to use getHashValue() for the key in > the map of ConstantInt values. > Reid. > > On Mon, 2007-02-26 at 10:46 -0800, Reid Spencer wrote: > > Hi, > > > > I would like to commit this small patch but thought I should send it out > > first. This changes ConstantInt to use an APInt object as its value > > instead of a uint64_t. The interface to ConstantInt still uses uint64_t > > so the APInt is just being used as a glorified uint64_t as all bit > > widths are <= 64. This change passes DejaGnu, the MultiSource/Benchmarks > > test suite, and a few of the SPEC benchmarks that I tried (444.namd, > > 176.gcc, 473.astar). > > > > Okay to commit? > > > > Reid. > > _______________________________________________ > > llvm-commits mailing list > > llvm-commits@cs.uiuc.edu > > http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits > _______________________________________________ > llvm-commits mailing list > llvm-commits@cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
Index: include/llvm/Constants.h =================================================================== RCS file: /var/cvs/llvm/llvm/include/llvm/Constants.h,v retrieving revision 1.132 diff -t -d -u -p -5 -r1.132 Constants.h --- include/llvm/Constants.h 20 Feb 2007 07:18:01 -0000 1.132 +++ include/llvm/Constants.h 26 Feb 2007 23:07:24 -0000 @@ -20,10 +20,11 @@ #ifndef LLVM_CONSTANTS_H #define LLVM_CONSTANTS_H #include "llvm/Constant.h" #include "llvm/Type.h" +#include "llvm/ADT/APInt.h" namespace llvm { class ArrayType; class StructType; @@ -41,33 +42,43 @@ struct ConvertConstantType; /// @brief Class for constant integers. class ConstantInt : public Constant { static ConstantInt *TheTrueVal, *TheFalseVal; ConstantInt(const ConstantInt &); // DO NOT IMPLEMENT ConstantInt(const IntegerType *Ty, uint64_t V); - uint64_t Val; + ConstantInt(const IntegerType *Ty, const APInt& V); + APInt Val; public: + /// Return the constant as an APInt value reference. This allows clients to + /// obtain a copy of the value, with all its precision in tact. + /// @brief Return the constant's value. + inline const APInt& getValue() const { + return Val; + } + /// Return the constant as a 64-bit unsigned integer value after it - /// has been zero extended as appropriate for the type of this constant. + /// has been zero extended as appropriate for the type of this constant. Note + /// that this method can assert if the value does not fit in 64 bits. + /// @deprecated /// @brief Return the zero extended value. inline uint64_t getZExtValue() const { - return Val; + return Val.getZExtValue(); } /// Return the constant as a 64-bit integer value after it has been sign - /// sign extended as appropriate for the type of this constant. + /// sign extended as appropriate for the type of this constant. Note that + /// this method can assert if the value does not fit in 64 bits. + /// @deprecated /// @brief Return the sign extended value. inline int64_t getSExtValue() const { - unsigned Size = Value::getType()->getPrimitiveSizeInBits(); - return (int64_t(Val) << (64-Size)) >> (64-Size); + return Val.getSExtValue(); } + /// A helper method that can be used to determine if the constant contained /// within is equal to a constant. This only works for very small values, /// because this is all that can be represented with all types. /// @brief Determine if this constant's value is same as an unsigned char. - bool equalsInt(unsigned char V) const { - assert(V <= 127 && - "equalsInt: Can only be used with very small positive constants!"); + bool equalsInt(uint64_t V) const { return Val == V; } /// getTrue/getFalse - Return the singleton true/false values. static inline ConstantInt *getTrue() { @@ -83,10 +94,11 @@ public: /// value V will be canonicalized to a uint64_t but accessing it with either /// getSExtValue() or getZExtValue() (ConstantInt) will yield the correct /// sized/signed value for the type Ty. /// @brief Get a ConstantInt for a specific value. static ConstantInt *get(const Type *Ty, int64_t V); + static ConstantInt *get(const Type *Ty, const APInt& V); /// getType - Specialize the getType() method to always return an IntegerType, /// which reduces the amount of casting needed in parts of the compiler. /// inline const IntegerType *getType() const { @@ -116,41 +128,35 @@ public: /// This function will return true iff every bit in this constant is set /// to true. /// @returns true iff this constant's bits are all set to true. /// @brief Determine if the value is all ones. bool isAllOnesValue() const { - return getSExtValue() == -1; + return Val.isAllOnesValue(); } /// This function will return true iff this constant represents the largest /// value that may be represented by the constant's type. /// @returns true iff this is the largest value that may be represented /// by this type. /// @brief Determine if the value is maximal. bool isMaxValue(bool isSigned) const { - if (isSigned) { - int64_t V = getSExtValue(); - if (V < 0) return false; // Be careful about wrap-around on 'long's - ++V; - return !isValueValidForType(Value::getType(), V) || V < 0; - } - return isAllOnesValue(); + if (isSigned) + return Val.isMaxSignedValue(); + else + return Val.isMaxValue(); } /// This function will return true iff this constant represents the smallest /// value that may be represented by this constant's type. /// @returns true if this is the smallest value that may be represented by /// this type. /// @brief Determine if the value is minimal. bool isMinValue(bool isSigned) const { - if (isSigned) { - int64_t V = getSExtValue(); - if (V > 0) return false; // Be careful about wrap-around on 'long's - --V; - return !isValueValidForType(Value::getType(), V) || V > 0; - } - return getZExtValue() == 0; + if (isSigned) + return Val.isMinSignedValue(); + else + return Val.isMinValue(); } /// @returns the value for an integer constant of the given type that has all /// its bits set to true. /// @brief Get the all ones value Index: lib/Support/APInt.cpp =================================================================== RCS file: /var/cvs/llvm/llvm/lib/Support/APInt.cpp,v retrieving revision 1.49 diff -t -d -u -p -5 -r1.49 APInt.cpp --- lib/Support/APInt.cpp 26 Feb 2007 21:02:27 -0000 1.49 +++ lib/Support/APInt.cpp 26 Feb 2007 23:07:25 -0000 @@ -97,30 +97,57 @@ APInt::APInt(const APInt& that) } } APInt::~APInt() { if (!isSingleWord() && pVal) - delete[] pVal; + delete [] pVal; } APInt& APInt::operator=(const APInt& RHS) { - assert(BitWidth == RHS.BitWidth && "Bit widths must be the same"); - if (isSingleWord()) + // Don't do anything for X = X + if (this == &RHS) + return *this; + + // If the bitwidths are the same, we can avoid mucking with memory + if (BitWidth == RHS.getBitWidth()) { + if (isSingleWord()) + VAL = RHS.VAL; + else + memcpy(pVal, RHS.pVal, getNumWords() * APINT_WORD_SIZE); + return *this; + } + + if (isSingleWord()) + if (RHS.isSingleWord()) + VAL = RHS.VAL; + else { + VAL = 0; + pVal = getMemory(RHS.getNumWords()); + memcpy(pVal, RHS.pVal, RHS.getNumWords() * APINT_WORD_SIZE); + } + else if (getNumWords() == RHS.getNumWords()) + memcpy(pVal, RHS.pVal, RHS.getNumWords() * APINT_WORD_SIZE); + else if (RHS.isSingleWord()) { + delete [] pVal; VAL = RHS.VAL; - else - memcpy(pVal, RHS.pVal, getNumWords() * APINT_WORD_SIZE); - return *this; + } else { + delete [] pVal; + pVal = getMemory(RHS.getNumWords()); + memcpy(pVal, RHS.pVal, RHS.getNumWords() * APINT_WORD_SIZE); + } + BitWidth = RHS.BitWidth; + return clearUnusedBits(); } APInt& APInt::operator=(uint64_t RHS) { if (isSingleWord()) VAL = RHS; else { pVal[0] = RHS; memset(pVal+1, 0, (getNumWords() - 1) * APINT_WORD_SIZE); } - return *this; + return clearUnusedBits(); } /// add_1 - This function adds a single "digit" integer, y, to the multiple /// "digit" integer array, x[]. x[] is modified to reflect the addition and /// 1 is returned if there is a carry out, otherwise 0 is returned. @@ -455,10 +482,11 @@ bool APInt::operator[](uint32_t bitPosit return (maskBit(bitPosition) & (isSingleWord() ? VAL : pVal[whichWord(bitPosition)])) != 0; } bool APInt::operator==(const APInt& RHS) const { + assert(BitWidth == RHS.BitWidth && "Comparison requires equal bit widths"); if (isSingleWord()) return VAL == RHS.VAL; // Get some facts about the number of bits used in the two operands. uint32_t n1 = getActiveBits(); @@ -660,21 +688,19 @@ APInt APInt::getAllOnesValue(uint32_t nu APInt APInt::getNullValue(uint32_t numBits) { return getMinValue(numBits, false); } uint64_t APInt::getHashValue() const { - // LLVM only supports bit widths up to 2^23 so shift the bitwidth into the - // high range. This makes the hash unique for integer values < 2^41 bits and - // doesn't hurt for larger values. - uint64_t hash = uint64_t(BitWidth) << (APINT_BITS_PER_WORD - 23); + // Put the bit width into the low order bits. + uint64_t hash = BitWidth; // Add the sum of the words to the hash. if (isSingleWord()) - hash += VAL; + hash += VAL << 6; // clear separation of up to 64 bits else for (uint32_t i = 0; i < getNumWords(); ++i) - hash += pVal[i]; + hash += pVal[i] << 6; // clear sepration of up to 64 bits return hash; } /// HiBits - This function returns the high "numBits" bits of this APInt. APInt APInt::getHiBits(uint32_t numBits) const { @@ -865,16 +891,16 @@ void APInt::trunc(uint32_t width) { uint32_t wordsAfter = getNumWords(); if (wordsBefore != wordsAfter) { if (wordsAfter == 1) { uint64_t *tmp = pVal; VAL = pVal[0]; - delete tmp; + delete [] tmp; } else { uint64_t *newVal = getClearedMemory(wordsAfter); for (uint32_t i = 0; i < wordsAfter; ++i) newVal[i] = pVal[i]; - delete pVal; + delete [] pVal; pVal = newVal; } } clearUnusedBits(); } @@ -918,11 +944,11 @@ void APInt::sext(uint32_t width) { newVal[wordsBefore-1] |= mask; } for (uint32_t i = wordsBefore; i < wordsAfter; i++) newVal[i] = -1ULL; if (wordsBefore != 1) - delete pVal; + delete [] pVal; pVal = newVal; clearUnusedBits(); } // Zero extend to a new width. @@ -938,11 +964,11 @@ void APInt::zext(uint32_t width) { newVal[0] = VAL; else for (uint32_t i = 0; i < wordsBefore; ++i) newVal[i] = pVal[i]; if (wordsBefore != 1) - delete pVal; + delete [] pVal; pVal = newVal; } } /// Arithmetic right-shift this APInt by shiftAmt. @@ -1405,11 +1431,11 @@ void APInt::divide(const APInt LHS, uint // Set up the Quotient value's memory. if (Quotient->BitWidth != LHS.BitWidth) { if (Quotient->isSingleWord()) Quotient->VAL = 0; else - delete Quotient->pVal; + delete [] Quotient->pVal; Quotient->BitWidth = LHS.BitWidth; if (!Quotient->isSingleWord()) Quotient->pVal = getClearedMemory(Quotient->getNumWords()); } else Quotient->clear(); @@ -1436,11 +1462,11 @@ void APInt::divide(const APInt LHS, uint // Set up the Remainder value's memory. if (Remainder->BitWidth != RHS.BitWidth) { if (Remainder->isSingleWord()) Remainder->VAL = 0; else - delete Remainder->pVal; + delete [] Remainder->pVal; Remainder->BitWidth = RHS.BitWidth; if (!Remainder->isSingleWord()) Remainder->pVal = getClearedMemory(Remainder->getNumWords()); } else Remainder->clear(); Index: lib/VMCore/Constants.cpp =================================================================== RCS file: /var/cvs/llvm/llvm/lib/VMCore/Constants.cpp,v retrieving revision 1.220 diff -t -d -u -p -5 -r1.220 Constants.cpp --- lib/VMCore/Constants.cpp 20 Feb 2007 21:30:56 -0000 1.220 +++ lib/VMCore/Constants.cpp 26 Feb 2007 23:07:26 -0000 @@ -137,11 +137,16 @@ ConstantVector *ConstantVector::getAllOn //===----------------------------------------------------------------------===// // ConstantInt //===----------------------------------------------------------------------===// ConstantInt::ConstantInt(const IntegerType *Ty, uint64_t V) + : Constant(Ty, ConstantIntVal, 0, 0), Val(Ty->getBitWidth(), V) { +} + +ConstantInt::ConstantInt(const IntegerType *Ty, const APInt& V) : Constant(Ty, ConstantIntVal, 0, 0), Val(V) { + assert(V.getBitWidth() == Ty->getBitWidth() && "Invalid constant for type"); } ConstantInt *ConstantInt::TheTrueVal = 0; ConstantInt *ConstantInt::TheFalseVal = 0; @@ -164,36 +169,57 @@ ConstantInt *ConstantInt::CreateTrueFals return WhichOne ? TheTrueVal : TheFalseVal; } namespace { - struct DenseMapInt64KeyInfo { - typedef std::pair<uint64_t, const Type*> KeyTy; - static inline KeyTy getEmptyKey() { return KeyTy(0, 0); } - static inline KeyTy getTombstoneKey() { return KeyTy(1, 0); } + struct DenseMapAPIntKeyInfo { + struct KeyTy { + APInt first; + const Type* second; + KeyTy(const APInt& one, const Type* two) : first(one), second(two) {} + KeyTy(const KeyTy& that) : first(that.first), second(that.second) {} + bool operator==(const KeyTy& that) const { + if (this == &that) + return true; + return second == that.second && + this->first.getBitWidth() == that.first.getBitWidth() && + this->first == that.first; + } + bool operator!=(const KeyTy& that) const { + return !this->operator==(that); + } + }; + static inline KeyTy getEmptyKey() { return KeyTy(APInt(1,0), 0); } + static inline KeyTy getTombstoneKey() { return KeyTy(APInt(1,1), 0); } static unsigned getHashValue(const KeyTy &Key) { - return DenseMapKeyInfo<void*>::getHashValue(Key.second) ^ Key.first; + return DenseMapKeyInfo<void*>::getHashValue(Key.second) ^ + Key.first.getHashValue(); } static bool isPod() { return true; } }; } -typedef DenseMap<DenseMapInt64KeyInfo::KeyTy, ConstantInt*, - DenseMapInt64KeyInfo> IntMapTy; +typedef DenseMap<DenseMapAPIntKeyInfo::KeyTy, ConstantInt*, + DenseMapAPIntKeyInfo> IntMapTy; static ManagedStatic<IntMapTy> IntConstants; -// Get a ConstantInt from an int64_t. Note here that we canoncialize the value -// to a uint64_t value that has been zero extended down to the size of the -// integer type of the ConstantInt. This allows the getZExtValue method to -// just return the stored value while getSExtValue has to convert back to sign -// extended. getZExtValue is more common in LLVM than getSExtValue(). ConstantInt *ConstantInt::get(const Type *Ty, int64_t V) { const IntegerType *ITy = cast<IntegerType>(Ty); - V &= ITy->getBitMask(); - ConstantInt *&Slot = (*IntConstants)[std::make_pair(uint64_t(V), Ty)]; - if (Slot) return Slot; + APInt Tmp(ITy->getBitWidth(), V); + return get(Ty, Tmp); +} + +// Get a ConstantInt from an APInt. Note that the value stored in the DenseMap +// as the key is the hash value of the APInt. Consequently, when +ConstantInt *ConstantInt::get(const Type *Ty, const APInt& V) { + const IntegerType *ITy = cast<IntegerType>(Ty); + assert(ITy->getBitWidth() == V.getBitWidth() && "Invalid type for constant"); + DenseMapAPIntKeyInfo::KeyTy Key(V, Ty); + ConstantInt *&Slot = (*IntConstants)[Key]; + if (Slot) + return Slot; return Slot = new ConstantInt(ITy, V); } //===----------------------------------------------------------------------===// // ConstantFP @@ -213,10 +239,19 @@ bool ConstantFP::isExactlyValue(double V return DoubleToBits(V) == DoubleToBits(Val); } namespace { + struct DenseMapInt64KeyInfo { + typedef std::pair<uint64_t, const Type*> KeyTy; + static inline KeyTy getEmptyKey() { return KeyTy(0, 0); } + static inline KeyTy getTombstoneKey() { return KeyTy(1, 0); } + static unsigned getHashValue(const KeyTy &Key) { + return DenseMapKeyInfo<void*>::getHashValue(Key.second) ^ Key.first; + } + static bool isPod() { return true; } + }; struct DenseMapInt32KeyInfo { typedef std::pair<uint32_t, const Type*> KeyTy; static inline KeyTy getEmptyKey() { return KeyTy(0, 0); } static inline KeyTy getTombstoneKey() { return KeyTy(1, 0); } static unsigned getHashValue(const KeyTy &Key) {
_______________________________________________ llvm-commits mailing list llvm-commits@cs.uiuc.edu http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits