X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=include%2Fllvm%2FADT%2FPointerUnion.h;h=f27b81113ec504eb91d321f201285f0a94db3150;hb=1e2c16606dc69989c6358918d57099320d9acb51;hp=01272b80e2b7551d48709511b18fb44032bdb4a5;hpb=3a9fe06bfe30da6fb1e0a540f05877c3640c7335;p=oota-llvm.git diff --git a/include/llvm/ADT/PointerUnion.h b/include/llvm/ADT/PointerUnion.h index 01272b80e2b..f27b81113ec 100644 --- a/include/llvm/ADT/PointerUnion.h +++ b/include/llvm/ADT/PointerUnion.h @@ -15,21 +15,39 @@ #ifndef LLVM_ADT_POINTERUNION_H #define LLVM_ADT_POINTERUNION_H +#include "llvm/ADT/DenseMapInfo.h" #include "llvm/ADT/PointerIntPair.h" +#include "llvm/Support/Compiler.h" namespace llvm { - /// getPointerUnionTypeNum - If the argument has type PT1* or PT2* return - /// false or true respectively. - template - static inline bool getPointerUnionTypeNum(PT1 *P) { return false; } - template - static inline bool getPointerUnionTypeNum(PT2 *P) { return true; } - // Enable, if we could use static_assert. - //template - //static inline bool getPointerUnionTypeNum(...) { abort() } - - + template + struct PointerUnionTypeSelectorReturn { + typedef T Return; + }; + + /// \brief Get a type based on whether two types are the same or not. For: + /// @code + /// typedef typename PointerUnionTypeSelector::Return Ret; + /// @endcode + /// Ret will be EQ type if T1 is same as T2 or NE type otherwise. + template + struct PointerUnionTypeSelector { + typedef typename PointerUnionTypeSelectorReturn::Return Return; + }; + + template + struct PointerUnionTypeSelector { + typedef typename PointerUnionTypeSelectorReturn::Return Return; + }; + + template + struct PointerUnionTypeSelectorReturn< + PointerUnionTypeSelector > { + typedef typename PointerUnionTypeSelector::Return + Return; + }; + /// Provide PointerLikeTypeTraits for void* that is used by PointerUnion /// for the two template arguments. template @@ -38,12 +56,12 @@ namespace llvm { static inline void *getAsVoidPointer(void *P) { return P; } static inline void *getFromVoidPointer(void *P) { return P; } enum { - PT1BitsAv = PointerLikeTypeTraits::NumLowBitsAvailable, - PT2BitsAv = PointerLikeTypeTraits::NumLowBitsAvailable, + PT1BitsAv = (int)(PointerLikeTypeTraits::NumLowBitsAvailable), + PT2BitsAv = (int)(PointerLikeTypeTraits::NumLowBitsAvailable), NumLowBitsAvailable = PT1BitsAv < PT2BitsAv ? PT1BitsAv : PT2BitsAv }; }; - + /// PointerUnion - This implements a discriminated union of two pointer types, /// and keeps the discriminator bit-mangled into the low bits of the pointer. /// This allows the implementation to be extremely efficient in space, but @@ -55,77 +73,135 @@ namespace llvm { /// printf("%d %d", P.is(), P.is()); // prints "1 0" /// X = P.get(); // ok. /// Y = P.get(); // runtime assertion failure. - /// Z = P.get(); // does not compile. + /// Z = P.get(); // compile time failure. /// P = (float*)0; /// Y = P.get(); // ok. /// X = P.get(); // runtime assertion failure. template class PointerUnion { public: - typedef PointerIntPair > ValTy; private: ValTy Val; + + struct IsPT1 { + static const int Num = 0; + }; + struct IsPT2 { + static const int Num = 1; + }; + template + struct UNION_DOESNT_CONTAIN_TYPE { }; + public: PointerUnion() {} - - PointerUnion(PT1 V) { - Val.setPointer(V); - Val.setInt(0); + + PointerUnion(PT1 V) : Val( + const_cast(PointerLikeTypeTraits::getAsVoidPointer(V))) { } - PointerUnion(PT2 V) { - Val.setPointer(V); - Val.setInt(1); + PointerUnion(PT2 V) : Val( + const_cast(PointerLikeTypeTraits::getAsVoidPointer(V)), 1) { } - - /// isNull - Return true if the pointer help in the union is null, + + /// isNull - Return true if the pointer held in the union is null, /// regardless of which type it is. - bool isNull() const { return Val.getPointer() == 0; } - + bool isNull() const { + // Convert from the void* to one of the pointer types, to make sure that + // we recursively strip off low bits if we have a nested PointerUnion. + return !PointerLikeTypeTraits::getFromVoidPointer(Val.getPointer()); + } + explicit operator bool() const { return !isNull(); } + /// is() return true if the Union currently holds the type matching T. template int is() const { - return Val.getInt() == ::llvm::getPointerUnionTypeNum((T*)0); + typedef typename + ::llvm::PointerUnionTypeSelector > >::Return Ty; + int TyNo = Ty::Num; + return static_cast(Val.getInt()) == TyNo; } - + /// get() - Return the value of the specified pointer type. If the /// specified pointer type is incorrect, assert. template T get() const { assert(is() && "Invalid accessor called"); - return static_cast(Val.getPointer()); + return PointerLikeTypeTraits::getFromVoidPointer(Val.getPointer()); } - + /// dyn_cast() - If the current value is of the specified pointer type, /// return it, otherwise return null. template T dyn_cast() const { - if (is()) return static_cast(Val.getPointer()); + if (is()) return get(); return T(); } - + + /// \brief If the union is set to the first pointer type get an address + /// pointing to it. + PT1 const *getAddrOfPtr1() const { + return const_cast(this)->getAddrOfPtr1(); + } + + /// \brief If the union is set to the first pointer type get an address + /// pointing to it. + PT1 *getAddrOfPtr1() { + assert(is() && "Val is not the first pointer"); + assert(get() == Val.getPointer() && + "Can't get the address because PointerLikeTypeTraits changes the ptr"); + return (PT1 *)Val.getAddrOfPointer(); + } + + /// \brief Assignment from nullptr which just clears the union. + const PointerUnion &operator=(std::nullptr_t) { + Val.initWithPointer(nullptr); + return *this; + } + /// Assignment operators - Allow assigning into this union from either /// pointer type, setting the discriminator to remember what it came from. const PointerUnion &operator=(const PT1 &RHS) { - Val.setPointer(RHS); - Val.setInt(0); + Val.initWithPointer( + const_cast(PointerLikeTypeTraits::getAsVoidPointer(RHS))); return *this; } const PointerUnion &operator=(const PT2 &RHS) { - Val.setPointer(RHS); - Val.setInt(1); + Val.setPointerAndInt( + const_cast(PointerLikeTypeTraits::getAsVoidPointer(RHS)), + 1); return *this; } - + void *getOpaqueValue() const { return Val.getOpaqueValue(); } - static PointerUnion getFromOpaqueValue(void *VP) { + static inline PointerUnion getFromOpaqueValue(void *VP) { PointerUnion V; V.Val = ValTy::getFromOpaqueValue(VP); return V; } }; - - // Teach SmallPtrSet that PointerIntPair is "basically a pointer", that has + + template + static bool operator==(PointerUnion lhs, + PointerUnion rhs) { + return lhs.getOpaqueValue() == rhs.getOpaqueValue(); + } + + template + static bool operator!=(PointerUnion lhs, + PointerUnion rhs) { + return lhs.getOpaqueValue() != rhs.getOpaqueValue(); + } + + template + static bool operator<(PointerUnion lhs, + PointerUnion rhs) { + return lhs.getOpaqueValue() < rhs.getOpaqueValue(); + } + + // Teach SmallPtrSet that PointerUnion is "basically a pointer", that has // # low bits available = min(PT1bits,PT2bits)-1. template class PointerLikeTypeTraits > { @@ -138,13 +214,299 @@ namespace llvm { getFromVoidPointer(void *P) { return PointerUnion::getFromOpaqueValue(P); } - + + // The number of bits available are the min of the two pointer types. + enum { + NumLowBitsAvailable = + PointerLikeTypeTraits::ValTy> + ::NumLowBitsAvailable + }; + }; + + + /// PointerUnion3 - This is a pointer union of three pointer types. See + /// documentation for PointerUnion for usage. + template + class PointerUnion3 { + public: + typedef PointerUnion InnerUnion; + typedef PointerUnion ValTy; + private: + ValTy Val; + + struct IsInnerUnion { + ValTy Val; + IsInnerUnion(ValTy val) : Val(val) { } + template + int is() const { + return Val.template is() && + Val.template get().template is(); + } + template + T get() const { + return Val.template get().template get(); + } + }; + + struct IsPT3 { + ValTy Val; + IsPT3(ValTy val) : Val(val) { } + template + int is() const { + return Val.template is(); + } + template + T get() const { + return Val.template get(); + } + }; + + public: + PointerUnion3() {} + + PointerUnion3(PT1 V) { + Val = InnerUnion(V); + } + PointerUnion3(PT2 V) { + Val = InnerUnion(V); + } + PointerUnion3(PT3 V) { + Val = V; + } + + /// isNull - Return true if the pointer held in the union is null, + /// regardless of which type it is. + bool isNull() const { return Val.isNull(); } + explicit operator bool() const { return !isNull(); } + + /// is() return true if the Union currently holds the type matching T. + template + int is() const { + // If T is PT1/PT2 choose IsInnerUnion otherwise choose IsPT3. + typedef typename + ::llvm::PointerUnionTypeSelector + >::Return Ty; + return Ty(Val).template is(); + } + + /// get() - Return the value of the specified pointer type. If the + /// specified pointer type is incorrect, assert. + template + T get() const { + assert(is() && "Invalid accessor called"); + // If T is PT1/PT2 choose IsInnerUnion otherwise choose IsPT3. + typedef typename + ::llvm::PointerUnionTypeSelector + >::Return Ty; + return Ty(Val).template get(); + } + + /// dyn_cast() - If the current value is of the specified pointer type, + /// return it, otherwise return null. + template + T dyn_cast() const { + if (is()) return get(); + return T(); + } + + /// \brief Assignment from nullptr which just clears the union. + const PointerUnion3 &operator=(std::nullptr_t) { + Val = nullptr; + return *this; + } + + /// Assignment operators - Allow assigning into this union from either + /// pointer type, setting the discriminator to remember what it came from. + const PointerUnion3 &operator=(const PT1 &RHS) { + Val = InnerUnion(RHS); + return *this; + } + const PointerUnion3 &operator=(const PT2 &RHS) { + Val = InnerUnion(RHS); + return *this; + } + const PointerUnion3 &operator=(const PT3 &RHS) { + Val = RHS; + return *this; + } + + void *getOpaqueValue() const { return Val.getOpaqueValue(); } + static inline PointerUnion3 getFromOpaqueValue(void *VP) { + PointerUnion3 V; + V.Val = ValTy::getFromOpaqueValue(VP); + return V; + } + }; + + // Teach SmallPtrSet that PointerUnion3 is "basically a pointer", that has + // # low bits available = min(PT1bits,PT2bits,PT2bits)-2. + template + class PointerLikeTypeTraits > { + public: + static inline void * + getAsVoidPointer(const PointerUnion3 &P) { + return P.getOpaqueValue(); + } + static inline PointerUnion3 + getFromVoidPointer(void *P) { + return PointerUnion3::getFromOpaqueValue(P); + } + // The number of bits available are the min of the two pointer types. enum { - NumLowBitsAvailable = - PointerUnion::ValTy::NumLowBitsAvailable + NumLowBitsAvailable = + PointerLikeTypeTraits::ValTy> + ::NumLowBitsAvailable }; }; + + /// PointerUnion4 - This is a pointer union of four pointer types. See + /// documentation for PointerUnion for usage. + template + class PointerUnion4 { + public: + typedef PointerUnion InnerUnion1; + typedef PointerUnion InnerUnion2; + typedef PointerUnion ValTy; + private: + ValTy Val; + public: + PointerUnion4() {} + + PointerUnion4(PT1 V) { + Val = InnerUnion1(V); + } + PointerUnion4(PT2 V) { + Val = InnerUnion1(V); + } + PointerUnion4(PT3 V) { + Val = InnerUnion2(V); + } + PointerUnion4(PT4 V) { + Val = InnerUnion2(V); + } + + /// isNull - Return true if the pointer held in the union is null, + /// regardless of which type it is. + bool isNull() const { return Val.isNull(); } + explicit operator bool() const { return !isNull(); } + + /// is() return true if the Union currently holds the type matching T. + template + int is() const { + // If T is PT1/PT2 choose InnerUnion1 otherwise choose InnerUnion2. + typedef typename + ::llvm::PointerUnionTypeSelector + >::Return Ty; + return Val.template is() && + Val.template get().template is(); + } + + /// get() - Return the value of the specified pointer type. If the + /// specified pointer type is incorrect, assert. + template + T get() const { + assert(is() && "Invalid accessor called"); + // If T is PT1/PT2 choose InnerUnion1 otherwise choose InnerUnion2. + typedef typename + ::llvm::PointerUnionTypeSelector + >::Return Ty; + return Val.template get().template get(); + } + + /// dyn_cast() - If the current value is of the specified pointer type, + /// return it, otherwise return null. + template + T dyn_cast() const { + if (is()) return get(); + return T(); + } + + /// \brief Assignment from nullptr which just clears the union. + const PointerUnion4 &operator=(std::nullptr_t) { + Val = nullptr; + return *this; + } + + /// Assignment operators - Allow assigning into this union from either + /// pointer type, setting the discriminator to remember what it came from. + const PointerUnion4 &operator=(const PT1 &RHS) { + Val = InnerUnion1(RHS); + return *this; + } + const PointerUnion4 &operator=(const PT2 &RHS) { + Val = InnerUnion1(RHS); + return *this; + } + const PointerUnion4 &operator=(const PT3 &RHS) { + Val = InnerUnion2(RHS); + return *this; + } + const PointerUnion4 &operator=(const PT4 &RHS) { + Val = InnerUnion2(RHS); + return *this; + } + + void *getOpaqueValue() const { return Val.getOpaqueValue(); } + static inline PointerUnion4 getFromOpaqueValue(void *VP) { + PointerUnion4 V; + V.Val = ValTy::getFromOpaqueValue(VP); + return V; + } + }; + + // Teach SmallPtrSet that PointerUnion4 is "basically a pointer", that has + // # low bits available = min(PT1bits,PT2bits,PT2bits)-2. + template + class PointerLikeTypeTraits > { + public: + static inline void * + getAsVoidPointer(const PointerUnion4 &P) { + return P.getOpaqueValue(); + } + static inline PointerUnion4 + getFromVoidPointer(void *P) { + return PointerUnion4::getFromOpaqueValue(P); + } + + // The number of bits available are the min of the two pointer types. + enum { + NumLowBitsAvailable = + PointerLikeTypeTraits::ValTy> + ::NumLowBitsAvailable + }; + }; + + // Teach DenseMap how to use PointerUnions as keys. + template + struct DenseMapInfo > { + typedef PointerUnion Pair; + typedef DenseMapInfo FirstInfo; + typedef DenseMapInfo SecondInfo; + + static inline Pair getEmptyKey() { + return Pair(FirstInfo::getEmptyKey()); + } + static inline Pair getTombstoneKey() { + return Pair(FirstInfo::getTombstoneKey()); + } + static unsigned getHashValue(const Pair &PairVal) { + intptr_t key = (intptr_t)PairVal.getOpaqueValue(); + return DenseMapInfo::getHashValue(key); + } + static bool isEqual(const Pair &LHS, const Pair &RHS) { + return LHS.template is() == RHS.template is() && + (LHS.template is() ? + FirstInfo::isEqual(LHS.template get(), + RHS.template get()) : + SecondInfo::isEqual(LHS.template get(), + RHS.template get())); + } + }; } #endif