Skip to content

Instantly share code, notes, and snippets.

@bethebunny
Created February 12, 2025 17:49
#ifndef MLIR_USE_FALLBACK_TYPE_IDS
#define MLIR_USE_FALLBACK_TYPE_IDS false
#endif
template <typename T>
struct is_fully_resolved_t {
/// Trait to check if `U` is fully resolved. We use this to verify that `T` is
/// fully resolved when trying to resolve a TypeID. We don't technically need
/// to have the full definition of `T` for the fallback, but it does help
/// prevent situations where a forward declared type uses this fallback even
/// though there is a strong definition for the TypeID in the location where
/// `T` is defined.
template <typename U>
using is_fully_resolved_trait = decltype(sizeof(U));
template <typename U>
using is_fully_resolved = llvm::is_detected<is_fully_resolved_trait, U>;
using value = is_fully_resolved<T>;
};
template <typename T>
static bool is_fully_resolved() {
return is_fully_resolved_t<T>::value;
}
/// This class provides a resolver for getting the ID for a given class T. This
/// allows for the derived type to specialize its resolution behavior. The
/// default implementation uses the string name of the type to resolve the ID.
/// This provides a strong definition, but at the cost of performance (we need
/// to do an initial lookup) and is not usable by classes defined in anonymous
/// contexts.
///
/// TODO: The use of the type name is only necessary when building in the
/// presence of shared libraries. We could add a build flag that guarantees
/// "static"-like environments and switch this to a more optimal implementation
/// when that is enabled.
template <typename T, typename Enable = void>
class TypeIDResolver : public FallbackTypeIDResolver {
public:
static TypeID resolveTypeID() {
static_assert(is_fully_resolved<T>(),
"TypeID::get<> requires the complete definition of `T`");
static TypeID id = registerImplicitTypeID(llvm::getTypeName<T>());
return id;
}
};
/// This class provides a resolver for getting the ID for a given class T, when
/// the class provides a `static TypeID resolveTypeID()` method. This allows for
/// simplifying situations when the class can resolve the ID itself.
template <typename T>
class TypeIDResolver<
T, std::enable_if_t<InlineTypeIDResolver::has_resolve_typeid<T>::value>> {
public:
static TypeID resolveTypeID() {
return InlineTypeIDResolver::resolveTypeID<T>();
}
};
/// If MLIR_USE_FALLBACK_TYPE_IDS is enabled, use fallback string TypeIDs
/// for any types without inline type IDs defined.
template <typename T>
class TypeIDResolver<
T, std::enable_if_t<
MLIR_USE_FALLBACK_TYPE_IDS &&
!detail::InlineTypeIDResolver::has_resolve_typeid<T>::value>>
: public FallbackTypeIDResolver {
public:
static TypeID resolveTypeID() {
static_assert(is_fully_resolved<T>(),
"TypeID::get<> requires the complete definition of `T`");
static TypeID id = registerImplicitTypeID(llvm::getTypeName<T>());
return id;
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment