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

Reply via email to