1 //===- Identifier.h - MLIR Identifier Class ---------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef MLIR_IR_IDENTIFIER_H
10 #define MLIR_IR_IDENTIFIER_H
11 
12 #include "mlir/Support/LLVM.h"
13 #include "llvm/ADT/DenseMapInfo.h"
14 #include "llvm/ADT/StringMapEntry.h"
15 #include "llvm/Support/PointerLikeTypeTraits.h"
16 
17 namespace mlir {
18 class MLIRContext;
19 
20 /// This class represents a uniqued string owned by an MLIRContext.  Strings
21 /// represented by this type cannot contain nul characters, and may not have a
22 /// zero length.
23 ///
24 /// This is a POD type with pointer size, so it should be passed around by
25 /// value.  The underlying data is owned by MLIRContext and is thus immortal for
26 /// almost all clients.
27 class Identifier {
28   using EntryType = llvm::StringMapEntry<llvm::NoneType>;
29 
30 public:
31   /// Return an identifier for the specified string.
32   static Identifier get(StringRef str, MLIRContext *context);
33   Identifier(const Identifier &) = default;
34   Identifier &operator=(const Identifier &other) = default;
35 
36   /// Return a StringRef for the string.
strref()37   StringRef strref() const { return entry->first(); }
38 
39   /// Identifiers implicitly convert to StringRefs.
StringRef()40   operator StringRef() const { return strref(); }
41 
42   /// Return an std::string.
str()43   std::string str() const { return strref().str(); }
44 
45   /// Return a null terminated C string.
c_str()46   const char *c_str() const { return entry->getKeyData(); }
47 
48   /// Return a pointer to the start of the string data.
data()49   const char *data() const { return entry->getKeyData(); }
50 
51   /// Return the number of bytes in this string.
size()52   unsigned size() const { return entry->getKeyLength(); }
53 
begin()54   const char *begin() const { return data(); }
end()55   const char *end() const { return entry->getKeyData() + size(); }
56 
57   bool operator==(Identifier other) const { return entry == other.entry; }
58   bool operator!=(Identifier rhs) const { return !(*this == rhs); }
59 
60   void print(raw_ostream &os) const;
61   void dump() const;
62 
getAsOpaquePointer()63   const void *getAsOpaquePointer() const {
64     return static_cast<const void *>(entry);
65   }
getFromOpaquePointer(const void * entry)66   static Identifier getFromOpaquePointer(const void *entry) {
67     return Identifier(static_cast<const EntryType *>(entry));
68   }
69 
70   /// Compare the underlying StringRef.
compare(Identifier rhs)71   int compare(Identifier rhs) const { return strref().compare(rhs.strref()); }
72 
73 private:
74   /// This contains the bytes of the string, which is guaranteed to be nul
75   /// terminated.
76   const EntryType *entry;
Identifier(const EntryType * entry)77   explicit Identifier(const EntryType *entry) : entry(entry) {}
78 };
79 
80 inline raw_ostream &operator<<(raw_ostream &os, Identifier identifier) {
81   identifier.print(os);
82   return os;
83 }
84 
85 // Identifier/Identifier equality comparisons are defined inline.
86 inline bool operator==(Identifier lhs, StringRef rhs) {
87   return lhs.strref() == rhs;
88 }
89 inline bool operator!=(Identifier lhs, StringRef rhs) { return !(lhs == rhs); }
90 
91 inline bool operator==(StringRef lhs, Identifier rhs) {
92   return rhs.strref() == lhs;
93 }
94 inline bool operator!=(StringRef lhs, Identifier rhs) { return !(lhs == rhs); }
95 
96 // Make identifiers hashable.
hash_value(Identifier arg)97 inline llvm::hash_code hash_value(Identifier arg) {
98   // Identifiers are uniqued, so we can just hash the pointer they contain.
99   return llvm::hash_value(arg.getAsOpaquePointer());
100 }
101 } // end namespace mlir
102 
103 namespace llvm {
104 // Identifiers hash just like pointers, there is no need to hash the bytes.
105 template <>
106 struct DenseMapInfo<mlir::Identifier> {
107   static mlir::Identifier getEmptyKey() {
108     auto pointer = llvm::DenseMapInfo<const void *>::getEmptyKey();
109     return mlir::Identifier::getFromOpaquePointer(pointer);
110   }
111   static mlir::Identifier getTombstoneKey() {
112     auto pointer = llvm::DenseMapInfo<const void *>::getTombstoneKey();
113     return mlir::Identifier::getFromOpaquePointer(pointer);
114   }
115   static unsigned getHashValue(mlir::Identifier val) {
116     return mlir::hash_value(val);
117   }
118   static bool isEqual(mlir::Identifier lhs, mlir::Identifier rhs) {
119     return lhs == rhs;
120   }
121 };
122 
123 /// The pointer inside of an identifier comes from a StringMap, so its alignment
124 /// is always at least 4 and probably 8 (on 64-bit machines).  Allow LLVM to
125 /// steal the low bits.
126 template <>
127 struct PointerLikeTypeTraits<mlir::Identifier> {
128 public:
129   static inline void *getAsVoidPointer(mlir::Identifier i) {
130     return const_cast<void *>(i.getAsOpaquePointer());
131   }
132   static inline mlir::Identifier getFromVoidPointer(void *p) {
133     return mlir::Identifier::getFromOpaquePointer(p);
134   }
135   static constexpr int NumLowBitsAvailable = 2;
136 };
137 
138 } // end namespace llvm
139 #endif
140