blob: c966ba4ecd57b3c057176872db3ec266d8f89ab4 [file] [log] [blame]
//===- TypeID.h - TypeID RTTI 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
//
//===----------------------------------------------------------------------===//
//
// This file contains a definition of the TypeID class. This provides a non
// RTTI mechanism for producing unique type IDs in LLVM.
//
//===----------------------------------------------------------------------===//
#ifndef MLIR_SUPPORT_TYPEID_H
#define MLIR_SUPPORT_TYPEID_H
#include "mlir/Support/LLVM.h"
#include "llvm/ADT/DenseMapInfo.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/Support/PointerLikeTypeTraits.h"
namespace mlir {
namespace detail {
struct TypeIDExported;
} // namespace detail
/// This class provides an efficient unique identifier for a specific C++ type.
/// This allows for a C++ type to be compared, hashed, and stored in an opaque
/// context. This class is similar in some ways to std::type_index, but can be
/// used for any type. For example, this class could be used to implement LLVM
/// style isa/dyn_cast functionality for a type hierarchy:
///
/// struct Base {
/// Base(TypeID typeID) : typeID(typeID) {}
/// TypeID typeID;
/// };
///
/// struct DerivedA : public Base {
/// DerivedA() : Base(TypeID::get<DerivedA>()) {}
///
/// static bool classof(const Base *base) {
/// return base->typeID == TypeID::get<DerivedA>();
/// }
/// };
///
/// void foo(Base *base) {
/// if (DerivedA *a = llvm::dyn_cast<DerivedA>(base))
/// ...
/// }
///
class TypeID {
/// This class represents the storage of a type info object.
/// Note: We specify an explicit alignment here to allow use with
/// PointerIntPair and other utilities/data structures that require a known
/// pointer alignment.
struct alignas(8) Storage {};
public:
TypeID() : TypeID(get<void>()) {}
/// Comparison operations.
inline bool operator==(const TypeID &other) const {
return storage == other.storage;
}
inline bool operator!=(const TypeID &other) const {
return !(*this == other);
}
/// Construct a type info object for the given type T.
template <typename T>
static TypeID get();
template <template <typename> class Trait>
static TypeID get();
/// Methods for supporting PointerLikeTypeTraits.
const void *getAsOpaquePointer() const {
return static_cast<const void *>(storage);
}
static TypeID getFromOpaquePointer(const void *pointer) {
return TypeID(reinterpret_cast<const Storage *>(pointer));
}
/// Enable hashing TypeID.
friend ::llvm::hash_code hash_value(TypeID id);
private:
TypeID(const Storage *storage) : storage(storage) {}
/// The storage of this type info object.
const Storage *storage;
// See TypeIDExported below for an explanation of the trampoline behavior.
friend struct detail::TypeIDExported;
};
/// Enable hashing TypeID.
inline ::llvm::hash_code hash_value(TypeID id) {
return DenseMapInfo<const TypeID::Storage *>::getHashValue(id.storage);
}
namespace detail {
/// The static local instance of each get method must be emitted with
/// "default" (public) visibility across all shared libraries, regardless of
/// whether they are compiled with hidden visibility or not. The only reliable
/// way to make this happen is to set the visibility attribute at the
/// containing namespace/struct scope. We don't do this on the TypeID (internal
/// API) class in order to reduce the scope of what gets exported with
/// public visibility. Instead, the get() methods on TypeID trampoline
/// through those on this detail class with specific visibility controls
/// applied, making visibility declarations on the internal TypeID class not
/// required (all visibility relevant pieces are here).
/// TODO: This currently won't work when using DLLs as it requires properly
/// attaching dllimport and dllexport. Fix this when that information is
/// available within LLVM.
struct LLVM_EXTERNAL_VISIBILITY TypeIDExported {
template <typename T>
static TypeID get() {
static TypeID::Storage instance;
return TypeID(&instance);
}
template <template <typename> class Trait>
static TypeID get() {
static TypeID::Storage instance;
return TypeID(&instance);
}
};
} // namespace detail
template <typename T>
TypeID TypeID::get() {
return detail::TypeIDExported::get<T>();
}
template <template <typename> class Trait>
TypeID TypeID::get() {
return detail::TypeIDExported::get<Trait>();
}
} // end namespace mlir
// Declare/define an explicit specialization for TypeID: this forces the
// compiler to emit a strong definition for a class and controls which
// translation unit and shared object will actually have it.
// This can be useful to turn to a link-time failure what would be in other
// circumstances a hard-to-catch runtime bug when a TypeID is hidden in two
// different shared libraries and instances of the same class only gets the same
// TypeID inside a given DSO.
#define DECLARE_EXPLICIT_TYPE_ID(CLASS_NAME) \
namespace mlir { \
namespace detail { \
template <> \
LLVM_EXTERNAL_VISIBILITY TypeID TypeIDExported::get<CLASS_NAME>(); \
} \
}
#define DEFINE_EXPLICIT_TYPE_ID(CLASS_NAME) \
namespace mlir { \
namespace detail { \
template <> \
LLVM_EXTERNAL_VISIBILITY TypeID TypeIDExported::get<CLASS_NAME>() { \
static TypeID::Storage instance; \
return TypeID(&instance); \
} \
} \
}
namespace llvm {
template <> struct DenseMapInfo<mlir::TypeID> {
static inline mlir::TypeID getEmptyKey() {
void *pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
return mlir::TypeID::getFromOpaquePointer(pointer);
}
static inline mlir::TypeID getTombstoneKey() {
void *pointer = llvm::DenseMapInfo<void *>::getTombstoneKey();
return mlir::TypeID::getFromOpaquePointer(pointer);
}
static unsigned getHashValue(mlir::TypeID val) {
return mlir::hash_value(val);
}
static bool isEqual(mlir::TypeID lhs, mlir::TypeID rhs) { return lhs == rhs; }
};
/// We align TypeID::Storage by 8, so allow LLVM to steal the low bits.
template <> struct PointerLikeTypeTraits<mlir::TypeID> {
static inline void *getAsVoidPointer(mlir::TypeID info) {
return const_cast<void *>(info.getAsOpaquePointer());
}
static inline mlir::TypeID getFromVoidPointer(void *ptr) {
return mlir::TypeID::getFromOpaquePointer(ptr);
}
static constexpr int NumLowBitsAvailable = 3;
};
} // end namespace llvm
#endif // MLIR_SUPPORT_TYPEID_H