| //===- Identifier.h - MLIR Identifier Class ---------------------*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef MLIR_IR_IDENTIFIER_H |
| #define MLIR_IR_IDENTIFIER_H |
| |
| #include "mlir/Support/LLVM.h" |
| #include "llvm/ADT/DenseMapInfo.h" |
| #include "llvm/ADT/PointerUnion.h" |
| #include "llvm/ADT/StringMapEntry.h" |
| #include "llvm/Support/PointerLikeTypeTraits.h" |
| |
| namespace mlir { |
| class Dialect; |
| class MLIRContext; |
| |
| /// This class represents a uniqued string owned by an MLIRContext. Strings |
| /// represented by this type cannot contain nul characters, and may not have a |
| /// zero length. |
| /// |
| /// This is a POD type with pointer size, so it should be passed around by |
| /// value. The underlying data is owned by MLIRContext and is thus immortal for |
| /// almost all clients. |
| /// |
| /// An Identifier may be prefixed with a dialect namespace followed by a single |
| /// dot `.`. This is particularly useful when used as a key in a NamedAttribute |
| /// to differentiate a dependent attribute (specific to an operation) from a |
| /// generic attribute defined by the dialect (in general applicable to multiple |
| /// operations). |
| class Identifier { |
| using EntryType = |
| llvm::StringMapEntry<PointerUnion<Dialect *, MLIRContext *>>; |
| |
| public: |
| /// Return an identifier for the specified string. |
| static Identifier get(StringRef str, MLIRContext *context); |
| Identifier(const Identifier &) = default; |
| Identifier &operator=(const Identifier &other) = default; |
| |
| /// Return a StringRef for the string. |
| StringRef strref() const { return entry->first(); } |
| |
| /// Identifiers implicitly convert to StringRefs. |
| operator StringRef() const { return strref(); } |
| |
| /// Return an std::string. |
| std::string str() const { return strref().str(); } |
| |
| /// Return a null terminated C string. |
| const char *c_str() const { return entry->getKeyData(); } |
| |
| /// Return a pointer to the start of the string data. |
| const char *data() const { return entry->getKeyData(); } |
| |
| /// Return the number of bytes in this string. |
| unsigned size() const { return entry->getKeyLength(); } |
| |
| /// Return the dialect loaded in the context for this identifier or nullptr if |
| /// this identifier isn't prefixed with a loaded dialect. For example the |
| /// `llvm.fastmathflags` identifier would return the LLVM dialect here, |
| /// assuming it is loaded in the context. |
| Dialect *getDialect(); |
| |
| /// Return the current MLIRContext associated with this identifier. |
| MLIRContext *getContext(); |
| |
| const char *begin() const { return data(); } |
| const char *end() const { return entry->getKeyData() + size(); } |
| |
| bool operator==(Identifier other) const { return entry == other.entry; } |
| bool operator!=(Identifier rhs) const { return !(*this == rhs); } |
| |
| void print(raw_ostream &os) const; |
| void dump() const; |
| |
| const void *getAsOpaquePointer() const { |
| return static_cast<const void *>(entry); |
| } |
| static Identifier getFromOpaquePointer(const void *entry) { |
| return Identifier(static_cast<const EntryType *>(entry)); |
| } |
| |
| /// Compare the underlying StringRef. |
| int compare(Identifier rhs) const { return strref().compare(rhs.strref()); } |
| |
| private: |
| /// This contains the bytes of the string, which is guaranteed to be nul |
| /// terminated. |
| const EntryType *entry; |
| explicit Identifier(const EntryType *entry) : entry(entry) {} |
| }; |
| |
| inline raw_ostream &operator<<(raw_ostream &os, Identifier identifier) { |
| identifier.print(os); |
| return os; |
| } |
| |
| // Identifier/Identifier equality comparisons are defined inline. |
| inline bool operator==(Identifier lhs, StringRef rhs) { |
| return lhs.strref() == rhs; |
| } |
| inline bool operator!=(Identifier lhs, StringRef rhs) { return !(lhs == rhs); } |
| |
| inline bool operator==(StringRef lhs, Identifier rhs) { |
| return rhs.strref() == lhs; |
| } |
| inline bool operator!=(StringRef lhs, Identifier rhs) { return !(lhs == rhs); } |
| |
| // Make identifiers hashable. |
| inline llvm::hash_code hash_value(Identifier arg) { |
| // Identifiers are uniqued, so we can just hash the pointer they contain. |
| return llvm::hash_value(arg.getAsOpaquePointer()); |
| } |
| } // end namespace mlir |
| |
| namespace llvm { |
| // Identifiers hash just like pointers, there is no need to hash the bytes. |
| template <> |
| struct DenseMapInfo<mlir::Identifier> { |
| static mlir::Identifier getEmptyKey() { |
| auto pointer = llvm::DenseMapInfo<const void *>::getEmptyKey(); |
| return mlir::Identifier::getFromOpaquePointer(pointer); |
| } |
| static mlir::Identifier getTombstoneKey() { |
| auto pointer = llvm::DenseMapInfo<const void *>::getTombstoneKey(); |
| return mlir::Identifier::getFromOpaquePointer(pointer); |
| } |
| static unsigned getHashValue(mlir::Identifier val) { |
| return mlir::hash_value(val); |
| } |
| static bool isEqual(mlir::Identifier lhs, mlir::Identifier rhs) { |
| return lhs == rhs; |
| } |
| }; |
| |
| /// The pointer inside of an identifier comes from a StringMap, so its alignment |
| /// is always at least 4 and probably 8 (on 64-bit machines). Allow LLVM to |
| /// steal the low bits. |
| template <> |
| struct PointerLikeTypeTraits<mlir::Identifier> { |
| public: |
| static inline void *getAsVoidPointer(mlir::Identifier i) { |
| return const_cast<void *>(i.getAsOpaquePointer()); |
| } |
| static inline mlir::Identifier getFromVoidPointer(void *p) { |
| return mlir::Identifier::getFromOpaquePointer(p); |
| } |
| static constexpr int NumLowBitsAvailable = 2; |
| }; |
| |
| } // end namespace llvm |
| #endif |