Skip to content

Commit 2005f48

Browse files
authored
[clang][NFC] Refactor Selector to use PointerIntPair inside (#69916)
Refactor `uintptr_t` inside of `clang::Selector` that holds a pointer to `IdentifierInfo` or `MultiKeywordSelector` and `IdentifierInfoFlag` enum into `PointerIntPair`. This is a part of `PointerIntPair` migration outlined in #69835. Unlike `uintpt_t`, `PointerIntPair` required pointee types to be complete, so I had to shuffle definitions of `MultiKeywordSelector` and `detail::DeclarationNameExtra` around to make them complete at `Selector`. Also, there were outdated specializations of `PointerLikeTypeTraits` for `IdentifierInfo *`, which are no longer needed, because `alignof` that primary template use works just fine. Not just that, but they declared that `IdentifierInfo *` has only 1 spare lower bit, but today they are 8-byte aligned.
1 parent 80db833 commit 2005f48

File tree

3 files changed

+164
-181
lines changed

3 files changed

+164
-181
lines changed

clang/include/clang/AST/DeclarationName.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,8 @@ class DeclarationName {
362362
}
363363

364364
/// Construct a declaration name from an Objective-C selector.
365-
DeclarationName(Selector Sel) : Ptr(Sel.InfoPtr) {}
365+
DeclarationName(Selector Sel)
366+
: Ptr(reinterpret_cast<uintptr_t>(Sel.InfoPtr.getOpaqueValue())) {}
366367

367368
/// Returns the name for all C++ using-directives.
368369
static DeclarationName getUsingDirectiveName() {

clang/include/clang/Basic/IdentifierTable.h

+161-122
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
#include "clang/Basic/LLVM.h"
2020
#include "clang/Basic/TokenKinds.h"
2121
#include "llvm/ADT/DenseMapInfo.h"
22+
#include "llvm/ADT/FoldingSet.h"
23+
#include "llvm/ADT/PointerIntPair.h"
24+
#include "llvm/ADT/PointerUnion.h"
2225
#include "llvm/ADT/SmallString.h"
2326
#include "llvm/ADT/StringMap.h"
2427
#include "llvm/ADT/StringRef.h"
@@ -794,6 +797,121 @@ enum ObjCStringFormatFamily {
794797
SFF_CFString
795798
};
796799

800+
namespace detail {
801+
802+
/// DeclarationNameExtra is used as a base of various uncommon special names.
803+
/// This class is needed since DeclarationName has not enough space to store
804+
/// the kind of every possible names. Therefore the kind of common names is
805+
/// stored directly in DeclarationName, and the kind of uncommon names is
806+
/// stored in DeclarationNameExtra. It is aligned to 8 bytes because
807+
/// DeclarationName needs the lower 3 bits to store the kind of common names.
808+
/// DeclarationNameExtra is tightly coupled to DeclarationName and any change
809+
/// here is very likely to require changes in DeclarationName(Table).
810+
class alignas(IdentifierInfoAlignment) DeclarationNameExtra {
811+
friend class clang::DeclarationName;
812+
friend class clang::DeclarationNameTable;
813+
814+
protected:
815+
/// The kind of "extra" information stored in the DeclarationName. See
816+
/// @c ExtraKindOrNumArgs for an explanation of how these enumerator values
817+
/// are used. Note that DeclarationName depends on the numerical values
818+
/// of the enumerators in this enum. See DeclarationName::StoredNameKind
819+
/// for more info.
820+
enum ExtraKind {
821+
CXXDeductionGuideName,
822+
CXXLiteralOperatorName,
823+
CXXUsingDirective,
824+
ObjCMultiArgSelector
825+
};
826+
827+
/// ExtraKindOrNumArgs has one of the following meaning:
828+
/// * The kind of an uncommon C++ special name. This DeclarationNameExtra
829+
/// is in this case in fact either a CXXDeductionGuideNameExtra or
830+
/// a CXXLiteralOperatorIdName.
831+
///
832+
/// * It may be also name common to C++ using-directives (CXXUsingDirective),
833+
///
834+
/// * Otherwise it is ObjCMultiArgSelector+NumArgs, where NumArgs is
835+
/// the number of arguments in the Objective-C selector, in which
836+
/// case the DeclarationNameExtra is also a MultiKeywordSelector.
837+
unsigned ExtraKindOrNumArgs;
838+
839+
DeclarationNameExtra(ExtraKind Kind) : ExtraKindOrNumArgs(Kind) {}
840+
DeclarationNameExtra(unsigned NumArgs)
841+
: ExtraKindOrNumArgs(ObjCMultiArgSelector + NumArgs) {}
842+
843+
/// Return the corresponding ExtraKind.
844+
ExtraKind getKind() const {
845+
return static_cast<ExtraKind>(ExtraKindOrNumArgs >
846+
(unsigned)ObjCMultiArgSelector
847+
? (unsigned)ObjCMultiArgSelector
848+
: ExtraKindOrNumArgs);
849+
}
850+
851+
/// Return the number of arguments in an ObjC selector. Only valid when this
852+
/// is indeed an ObjCMultiArgSelector.
853+
unsigned getNumArgs() const {
854+
assert(ExtraKindOrNumArgs >= (unsigned)ObjCMultiArgSelector &&
855+
"getNumArgs called but this is not an ObjC selector!");
856+
return ExtraKindOrNumArgs - (unsigned)ObjCMultiArgSelector;
857+
}
858+
};
859+
860+
} // namespace detail
861+
862+
/// One of these variable length records is kept for each
863+
/// selector containing more than one keyword. We use a folding set
864+
/// to unique aggregate names (keyword selectors in ObjC parlance). Access to
865+
/// this class is provided strictly through Selector.
866+
class alignas(IdentifierInfoAlignment) MultiKeywordSelector
867+
: public detail::DeclarationNameExtra,
868+
public llvm::FoldingSetNode {
869+
MultiKeywordSelector(unsigned nKeys) : DeclarationNameExtra(nKeys) {}
870+
871+
public:
872+
// Constructor for keyword selectors.
873+
MultiKeywordSelector(unsigned nKeys, IdentifierInfo **IIV)
874+
: DeclarationNameExtra(nKeys) {
875+
assert((nKeys > 1) && "not a multi-keyword selector");
876+
877+
// Fill in the trailing keyword array.
878+
IdentifierInfo **KeyInfo = reinterpret_cast<IdentifierInfo **>(this + 1);
879+
for (unsigned i = 0; i != nKeys; ++i)
880+
KeyInfo[i] = IIV[i];
881+
}
882+
883+
// getName - Derive the full selector name and return it.
884+
std::string getName() const;
885+
886+
using DeclarationNameExtra::getNumArgs;
887+
888+
using keyword_iterator = IdentifierInfo *const *;
889+
890+
keyword_iterator keyword_begin() const {
891+
return reinterpret_cast<keyword_iterator>(this + 1);
892+
}
893+
894+
keyword_iterator keyword_end() const {
895+
return keyword_begin() + getNumArgs();
896+
}
897+
898+
IdentifierInfo *getIdentifierInfoForSlot(unsigned i) const {
899+
assert(i < getNumArgs() && "getIdentifierInfoForSlot(): illegal index");
900+
return keyword_begin()[i];
901+
}
902+
903+
static void Profile(llvm::FoldingSetNodeID &ID, keyword_iterator ArgTys,
904+
unsigned NumArgs) {
905+
ID.AddInteger(NumArgs);
906+
for (unsigned i = 0; i != NumArgs; ++i)
907+
ID.AddPointer(ArgTys[i]);
908+
}
909+
910+
void Profile(llvm::FoldingSetNodeID &ID) {
911+
Profile(ID, keyword_begin(), getNumArgs());
912+
}
913+
};
914+
797915
/// Smart pointer class that efficiently represents Objective-C method
798916
/// names.
799917
///
@@ -809,43 +927,58 @@ class Selector {
809927
enum IdentifierInfoFlag {
810928
// Empty selector = 0. Note that these enumeration values must
811929
// correspond to the enumeration values of DeclarationName::StoredNameKind
812-
ZeroArg = 0x01,
813-
OneArg = 0x02,
930+
ZeroArg = 0x01,
931+
OneArg = 0x02,
932+
// IMPORTANT NOTE: see comments in InfoPtr (below) about this enumerator
933+
// value.
814934
MultiArg = 0x07,
815-
ArgFlags = 0x07
816935
};
817936

818-
/// A pointer to the MultiKeywordSelector or IdentifierInfo. We use the low
819-
/// three bits of InfoPtr to store an IdentifierInfoFlag. Note that in any
820-
/// case IdentifierInfo and MultiKeywordSelector are already aligned to
821-
/// 8 bytes even on 32 bits archs because of DeclarationName.
822-
uintptr_t InfoPtr = 0;
937+
/// IMPORTANT NOTE: the order of the types in this PointerUnion are
938+
/// important! The DeclarationName class has bidirectional conversion
939+
/// to/from Selector through an opaque pointer (void *) which corresponds
940+
/// to this PointerIntPair. The discriminator bit from the PointerUnion
941+
/// corresponds to the high bit in the MultiArg enumerator. So while this
942+
/// PointerIntPair only has two bits for the integer (and we mask off the
943+
/// high bit in `MultiArg` when it is used), that discrimator bit is
944+
/// still necessary for the opaque conversion. The discriminator bit
945+
/// from the PointerUnion and the two integer bits from the
946+
/// PointerIntPair are also exposed via the DeclarationName::StoredNameKind
947+
/// enumeration; see the comments in DeclarationName.h for more details.
948+
/// Do not reorder or add any arguments to this template
949+
/// without thoroughly understanding how tightly coupled these classes are.
950+
llvm::PointerIntPair<
951+
llvm::PointerUnion<IdentifierInfo *, MultiKeywordSelector *>, 2>
952+
InfoPtr;
823953

824954
Selector(IdentifierInfo *II, unsigned nArgs) {
825-
InfoPtr = reinterpret_cast<uintptr_t>(II);
826-
assert((InfoPtr & ArgFlags) == 0 &&"Insufficiently aligned IdentifierInfo");
827955
assert(nArgs < 2 && "nArgs not equal to 0/1");
828-
InfoPtr |= nArgs+1;
956+
InfoPtr.setPointerAndInt(II, nArgs + 1);
829957
}
830958

831959
Selector(MultiKeywordSelector *SI) {
832-
InfoPtr = reinterpret_cast<uintptr_t>(SI);
833-
assert((InfoPtr & ArgFlags) == 0 &&"Insufficiently aligned IdentifierInfo");
834-
InfoPtr |= MultiArg;
960+
// IMPORTANT NOTE: we mask off the upper bit of this value because we only
961+
// reserve two bits for the integer in the PointerIntPair. See the comments
962+
// in `InfoPtr` for more details.
963+
InfoPtr.setPointerAndInt(SI, MultiArg & 0b11);
835964
}
836965

837966
IdentifierInfo *getAsIdentifierInfo() const {
838-
if (getIdentifierInfoFlag() < MultiArg)
839-
return reinterpret_cast<IdentifierInfo *>(InfoPtr & ~ArgFlags);
840-
return nullptr;
967+
return InfoPtr.getPointer().dyn_cast<IdentifierInfo *>();
841968
}
842969

843970
MultiKeywordSelector *getMultiKeywordSelector() const {
844-
return reinterpret_cast<MultiKeywordSelector *>(InfoPtr & ~ArgFlags);
971+
return InfoPtr.getPointer().get<MultiKeywordSelector *>();
845972
}
846973

847974
unsigned getIdentifierInfoFlag() const {
848-
return InfoPtr & ArgFlags;
975+
unsigned new_flags = InfoPtr.getInt();
976+
// IMPORTANT NOTE: We have to reconstitute this data rather than use the
977+
// value directly from the PointerIntPair. See the comments in `InfoPtr`
978+
// for more details.
979+
if (InfoPtr.getPointer().is<MultiKeywordSelector *>())
980+
new_flags |= MultiArg;
981+
return new_flags;
849982
}
850983

851984
static ObjCMethodFamily getMethodFamilyImpl(Selector sel);
@@ -856,31 +989,27 @@ class Selector {
856989
/// The default ctor should only be used when creating data structures that
857990
/// will contain selectors.
858991
Selector() = default;
859-
explicit Selector(uintptr_t V) : InfoPtr(V) {}
992+
explicit Selector(uintptr_t V) {
993+
InfoPtr.setFromOpaqueValue(reinterpret_cast<void *>(V));
994+
}
860995

861996
/// operator==/!= - Indicate whether the specified selectors are identical.
862997
bool operator==(Selector RHS) const {
863-
return InfoPtr == RHS.InfoPtr;
998+
return InfoPtr.getOpaqueValue() == RHS.InfoPtr.getOpaqueValue();
864999
}
8651000
bool operator!=(Selector RHS) const {
866-
return InfoPtr != RHS.InfoPtr;
1001+
return InfoPtr.getOpaqueValue() != RHS.InfoPtr.getOpaqueValue();
8671002
}
8681003

869-
void *getAsOpaquePtr() const {
870-
return reinterpret_cast<void*>(InfoPtr);
871-
}
1004+
void *getAsOpaquePtr() const { return InfoPtr.getOpaqueValue(); }
8721005

8731006
/// Determine whether this is the empty selector.
874-
bool isNull() const { return InfoPtr == 0; }
1007+
bool isNull() const { return InfoPtr.getOpaqueValue() == nullptr; }
8751008

8761009
// Predicates to identify the selector type.
877-
bool isKeywordSelector() const {
878-
return getIdentifierInfoFlag() != ZeroArg;
879-
}
1010+
bool isKeywordSelector() const { return InfoPtr.getInt() != ZeroArg; }
8801011

881-
bool isUnarySelector() const {
882-
return getIdentifierInfoFlag() == ZeroArg;
883-
}
1012+
bool isUnarySelector() const { return InfoPtr.getInt() == ZeroArg; }
8841013

8851014
/// If this selector is the specific keyword selector described by Names.
8861015
bool isKeywordSelector(ArrayRef<StringRef> Names) const;
@@ -991,68 +1120,6 @@ class SelectorTable {
9911120
static std::string getPropertyNameFromSetterSelector(Selector Sel);
9921121
};
9931122

994-
namespace detail {
995-
996-
/// DeclarationNameExtra is used as a base of various uncommon special names.
997-
/// This class is needed since DeclarationName has not enough space to store
998-
/// the kind of every possible names. Therefore the kind of common names is
999-
/// stored directly in DeclarationName, and the kind of uncommon names is
1000-
/// stored in DeclarationNameExtra. It is aligned to 8 bytes because
1001-
/// DeclarationName needs the lower 3 bits to store the kind of common names.
1002-
/// DeclarationNameExtra is tightly coupled to DeclarationName and any change
1003-
/// here is very likely to require changes in DeclarationName(Table).
1004-
class alignas(IdentifierInfoAlignment) DeclarationNameExtra {
1005-
friend class clang::DeclarationName;
1006-
friend class clang::DeclarationNameTable;
1007-
1008-
protected:
1009-
/// The kind of "extra" information stored in the DeclarationName. See
1010-
/// @c ExtraKindOrNumArgs for an explanation of how these enumerator values
1011-
/// are used. Note that DeclarationName depends on the numerical values
1012-
/// of the enumerators in this enum. See DeclarationName::StoredNameKind
1013-
/// for more info.
1014-
enum ExtraKind {
1015-
CXXDeductionGuideName,
1016-
CXXLiteralOperatorName,
1017-
CXXUsingDirective,
1018-
ObjCMultiArgSelector
1019-
};
1020-
1021-
/// ExtraKindOrNumArgs has one of the following meaning:
1022-
/// * The kind of an uncommon C++ special name. This DeclarationNameExtra
1023-
/// is in this case in fact either a CXXDeductionGuideNameExtra or
1024-
/// a CXXLiteralOperatorIdName.
1025-
///
1026-
/// * It may be also name common to C++ using-directives (CXXUsingDirective),
1027-
///
1028-
/// * Otherwise it is ObjCMultiArgSelector+NumArgs, where NumArgs is
1029-
/// the number of arguments in the Objective-C selector, in which
1030-
/// case the DeclarationNameExtra is also a MultiKeywordSelector.
1031-
unsigned ExtraKindOrNumArgs;
1032-
1033-
DeclarationNameExtra(ExtraKind Kind) : ExtraKindOrNumArgs(Kind) {}
1034-
DeclarationNameExtra(unsigned NumArgs)
1035-
: ExtraKindOrNumArgs(ObjCMultiArgSelector + NumArgs) {}
1036-
1037-
/// Return the corresponding ExtraKind.
1038-
ExtraKind getKind() const {
1039-
return static_cast<ExtraKind>(ExtraKindOrNumArgs >
1040-
(unsigned)ObjCMultiArgSelector
1041-
? (unsigned)ObjCMultiArgSelector
1042-
: ExtraKindOrNumArgs);
1043-
}
1044-
1045-
/// Return the number of arguments in an ObjC selector. Only valid when this
1046-
/// is indeed an ObjCMultiArgSelector.
1047-
unsigned getNumArgs() const {
1048-
assert(ExtraKindOrNumArgs >= (unsigned)ObjCMultiArgSelector &&
1049-
"getNumArgs called but this is not an ObjC selector!");
1050-
return ExtraKindOrNumArgs - (unsigned)ObjCMultiArgSelector;
1051-
}
1052-
};
1053-
1054-
} // namespace detail
1055-
10561123
} // namespace clang
10571124

10581125
namespace llvm {
@@ -1089,34 +1156,6 @@ struct PointerLikeTypeTraits<clang::Selector> {
10891156
static constexpr int NumLowBitsAvailable = 0;
10901157
};
10911158

1092-
// Provide PointerLikeTypeTraits for IdentifierInfo pointers, which
1093-
// are not guaranteed to be 8-byte aligned.
1094-
template<>
1095-
struct PointerLikeTypeTraits<clang::IdentifierInfo*> {
1096-
static void *getAsVoidPointer(clang::IdentifierInfo* P) {
1097-
return P;
1098-
}
1099-
1100-
static clang::IdentifierInfo *getFromVoidPointer(void *P) {
1101-
return static_cast<clang::IdentifierInfo*>(P);
1102-
}
1103-
1104-
static constexpr int NumLowBitsAvailable = 1;
1105-
};
1106-
1107-
template<>
1108-
struct PointerLikeTypeTraits<const clang::IdentifierInfo*> {
1109-
static const void *getAsVoidPointer(const clang::IdentifierInfo* P) {
1110-
return P;
1111-
}
1112-
1113-
static const clang::IdentifierInfo *getFromVoidPointer(const void *P) {
1114-
return static_cast<const clang::IdentifierInfo*>(P);
1115-
}
1116-
1117-
static constexpr int NumLowBitsAvailable = 1;
1118-
};
1119-
11201159
} // namespace llvm
11211160

11221161
#endif // LLVM_CLANG_BASIC_IDENTIFIERTABLE_H

0 commit comments

Comments
 (0)