For PR1205:
authorReid Spencer <rspencer@reidspencer.com>
Mon, 26 Feb 2007 23:54:03 +0000 (23:54 +0000)
committerReid Spencer <rspencer@reidspencer.com>
Mon, 26 Feb 2007 23:54:03 +0000 (23:54 +0000)
Implement the first step towards arbitrary precision integer support in
LLVM. The APInt class provides arbitrary precision arithmetic and value
representation. This patch changes ConstantInt to use APInt as its value
representation without supporting bit widths > 64 yet. That change will
come after ConstantFolding handles bit widths > 64 bits.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@34647 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Constants.h
lib/VMCore/Constants.cpp

index 1fb65e0c2979c4c38c3eabeccf0342fb525c1f52..6ae7a528710f7b1e2a4ee6ac7032a3c6e00e648f 100644 (file)
@@ -22,6 +22,7 @@
 
 #include "llvm/Constant.h"
 #include "llvm/Type.h"
+#include "llvm/ADT/APInt.h"
 
 namespace llvm {
 
@@ -42,30 +43,39 @@ struct ConvertConstantType;
 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;
   }
 
@@ -85,6 +95,7 @@ public:
   /// 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.
@@ -118,7 +129,7 @@ public:
   /// @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
@@ -127,13 +138,10 @@ public:
   /// 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
@@ -142,13 +150,10 @@ public:
   /// 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
index fa35a8953c7ce2520799581d37038a44ba027886..dc017b355af34beec69074a75d9f3234c5fa617e 100644 (file)
@@ -138,8 +138,9 @@ ConstantVector *ConstantVector::getAllOnesValue(const VectorType *Ty) {
 //                                ConstantInt
 //===----------------------------------------------------------------------===//
 
-ConstantInt::ConstantInt(const IntegerType *Ty, uint64_t 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;
@@ -166,32 +167,55 @@ ConstantInt *ConstantInt::CreateTrueFalseVals(bool WhichOne) {
 
 
 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 val;
+      const Type* type;
+      KeyTy(const APInt& V, const Type* Ty) : val(V), type(Ty) {}
+      KeyTy(const KeyTy& that) : val(that.val), type(that.type) {}
+      bool operator==(const KeyTy& that) const {
+        return type == that.type && this->val == that.val;
+      }
+      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.type) ^ 
+        Key.val.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 a Type and APInt. Note that the value stored in 
+// the DenseMap as the key is a DensMapAPIntKeyInfo::KeyTy which has provided
+// operator== and operator!= to ensure that the DenseMap doesn't attempt to
+// compare APInt's of different widths, which would violate an APInt class
+// invariant which generates an assertion.
+ConstantInt *ConstantInt::get(const Type *Ty, const APInt& V) {
+  const IntegerType *ITy = cast<IntegerType>(Ty);
+  assert(ITy->getBitWidth() == V.getBitWidth() && "Invalid type for constant");
+  // get an existing value or the insertion position
+  DenseMapAPIntKeyInfo::KeyTy Key(V, Ty);
+  ConstantInt *&Slot = (*IntConstants)[Key]; 
+  // if it exists, return it.
+  if (Slot)
+    return Slot;
+  // otherwise create a new one, insert it, and return it.
   return Slot = new ConstantInt(ITy, V);
 }
 
@@ -215,6 +239,15 @@ bool ConstantFP::isExactlyValue(double V) const {
 
 
 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); }