Replace the PointerLikeTypeTraits::getNumLowBitsAvailable
authorChris Lattner <sabre@nondot.org>
Sun, 29 Mar 2009 04:32:37 +0000 (04:32 +0000)
committerChris Lattner <sabre@nondot.org>
Sun, 29 Mar 2009 04:32:37 +0000 (04:32 +0000)
function with a new NumLowBitsAvailable enum, which makes the
value available as an integer constant expression.

Add PointerLikeTypeTraits specializations for Instruction* and
Use** since they are only guaranteed 4-byte aligned.

Enhance PointerIntPair to know about (and enforce) the alignment
specified by PointerLikeTypeTraits.  This should allow things
like PointerIntPair<PointerIntPair<void*, 1,bool>, 1, bool>
because the inner one knows that 2 low bits are free.

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

include/llvm/ADT/PointerIntPair.h
include/llvm/Instruction.h
include/llvm/Support/PointerLikeTypeTraits.h
include/llvm/Use.h

index 7b3283c96d220c40a834d899bedb2e7ae9e27f4c..999b802ffca1160dfc194f9ca69116aa7b8a3d1c 100644 (file)
 #define LLVM_ADT_POINTERINTPAIR_H
 
 #include "llvm/Support/DataTypes.h"
+#include "llvm/Support/PointerLikeTypeTraits.h"
 #include <cassert>
 
 namespace llvm {
 
 template<typename T>
 struct DenseMapInfo;
-template<typename>
-class PointerLikeTypeTraits;
 
 /// PointerIntPair - This class implements a pair of a pointer and small
 /// integer.  It is designed to represent this in the space required by one
 /// pointer by bitmangling the integer into the low part of the pointer.  This
 /// can only be done for small integers: typically up to 3 bits, but it depends
-/// on the alignment returned by the allocator in use.
+/// on the number of bits available according to PointerLikeTypeTraits for the
+/// type.
+///
+/// Note that PointerIntPair always puts the Int part in the highest bits
+/// possible.  For example, PointerIntPair<void*, 1,bool> will put the bit for
+/// the bool into bit #2, not bit #0, which allows the low two bits to be used
+/// for something else.  For example, this allows:
+///   PointerIntPair<PointerIntPair<void*, 1,bool>, 1, bool>
+/// ... and the two bools will land in different bits.
 ///
 template <typename PointerTy, unsigned IntBits, typename IntType=unsigned>
 class PointerIntPair {
   intptr_t Value;
+  typedef PointerLikeTypeTraits<PointerTy> PtrTraits;
+  enum {
+    /// PointerBitMask - The bits that come from the pointer.
+    PointerBitMask = ~(((intptr_t)1 << PtrTraits::NumLowBitsAvailable)-1),
+    /// IntShift - The number of low bits that we reserve for other uses, and
+    /// keep zero.
+    IntShift = PtrTraits::NumLowBitsAvailable-IntBits,
+    
+    /// IntMask - This is the unshifted mask for valid bits of the int type.
+    IntMask = ((intptr_t)1 << IntBits)-1,
+    
+    // ShiftedIntMask - This is the bits for the integer shifted in place.
+    ShiftedIntMask = IntMask << IntShift
+  };
 public:
   PointerIntPair() : Value(0) {}
   PointerIntPair(PointerTy Ptr, IntType Int) : Value(0) {
+    assert(IntBits <= PtrTraits::NumLowBitsAvailable &&
+           "PointerIntPair formed with integer size too large for pointer");
     setPointer(Ptr);
     setInt(Int);
   }
 
   PointerTy getPointer() const {
-    return reinterpret_cast<PointerTy>(Value & ~((1 << IntBits)-1));
+    return reinterpret_cast<PointerTy>(Value & PointerBitMask);
   }
 
   IntType getInt() const {
-    return (IntType)(Value & ((1 << IntBits)-1));
+    return (IntType)((Value >> IntShift) & IntMask);
   }
 
   void setPointer(PointerTy Ptr) {
     intptr_t PtrVal = reinterpret_cast<intptr_t>(Ptr);
-    assert((PtrVal & ((1 << IntBits)-1)) == 0 &&
+    assert((PtrVal & ((1 << PtrTraits::NumLowBitsAvailable)-1)) == 0 &&
            "Pointer is not sufficiently aligned");
-    Value = PtrVal | (intptr_t)getInt();
+    // Preserve all low bits, just update the pointer.
+    Value = PtrVal | (Value & ~PointerBitMask);
   }
 
   void setInt(IntType Int) {
     intptr_t IntVal = Int;
     assert(IntVal < (1 << IntBits) && "Integer too large for field");
-    Value = reinterpret_cast<intptr_t>(getPointer()) | IntVal;
+    
+    // Preserve all bits other than the ones we are updating.
+    Value &= ~ShiftedIntMask;     // Remove integer field.
+    Value |= IntVal << IntShift;  // Set new integer.
   }
 
   void *getOpaqueValue() const { return reinterpret_cast<void*>(Value); }
@@ -107,7 +134,10 @@ public:
   getFromVoidPointer(void *P) {
     return PointerIntPair<PointerTy, IntBits, IntType>::getFromOpaqueValue(P);
   }
-  static inline unsigned getNumLowBitsAvailable() { return 0; }
+  enum {
+    NumLowBitsAvailable = 
+           PointerLikeTypeTraits<PointerTy>::NumLowBitsAvailable - IntBits
+  };
 };
 
 } // end namespace llvm
index a9cc000a25e37145da57ac03801a968b7131b8f2..856531c90685f8a82698fc0856ba2888c5be2ece 100644 (file)
@@ -227,6 +227,18 @@ public:
   };
 };
 
+// Instruction* is only 4-byte aligned.
+template<>
+class PointerLikeTypeTraits<Instruction*> {
+  typedef Instruction* PT;
+public:
+  static inline void *getAsVoidPointer(PT P) { return P; }
+  static inline PT getFromVoidPointer(void *P) {
+    return static_cast<PT>(P);
+  }
+  enum { NumLowBitsAvailable = 2 };
+};
+  
 } // End llvm namespace
 
 #endif
index 41b2302381f0f4bdd4b2759af479cc962fa634d9..000919ca109ad09dcff462d39c55f8d00ce14149 100644 (file)
@@ -42,7 +42,7 @@ public:
   ///
   /// All clients should use assertions to do a run-time check to ensure that
   /// this is actually true.
-  static inline unsigned getNumLowBitsAvailable() { return 3; }
+  enum { NumLowBitsAvailable = 3 };
 };
   
 // Provide PointerLikeTypeTraits for const pointers.
@@ -53,7 +53,7 @@ public:
   static inline const T *getFromVoidPointer(const void *P) {
     return static_cast<const T*>(P);
   }
-  static inline unsigned getNumLowBitsAvailable() { return 3; }
+  enum { NumLowBitsAvailable = 3 };
 };
   
 } // end namespace llvm
index cde4366a5a05517559855ab80bbe9d13b070cd34..53df699e703601c438c880f3313f704ac7c47f03 100644 (file)
@@ -24,11 +24,21 @@ namespace llvm {
 
 class Value;
 class User;
-
+class Use;
 
 /// Tag - generic tag type for (at least 32 bit) pointers
 enum Tag { noTag, tagOne, tagTwo, tagThree };
 
+// Use** is only 4-byte aligned.
+template<>
+class PointerLikeTypeTraits<Use**> {
+public:
+  static inline void *getAsVoidPointer(Use** P) { return P; }
+  static inline Use **getFromVoidPointer(void *P) {
+    return static_cast<Use**>(P);
+  }
+  enum { NumLowBitsAvailable = 2 };
+};
 
 //===----------------------------------------------------------------------===//
 //                                  Use Class
@@ -212,7 +222,7 @@ template<> struct simplify_type<value_use_iterator<const User> > {
 
 template<> struct simplify_type<const value_use_iterator<const User> >
   : public simplify_type<value_use_iterator<const User> > {};
-
 } // End llvm namespace
 
 #endif