// // This file is distributed under the MIT License. See LICENSE.md for details. // #include "revng/ADT/RecursiveCoroutine.h" #include "revng/Model/Binary.h" #include "revng/Model/CommonTypeMethods.h" #include "revng/Model/VerifyHelper.h" template using Common = model::CommonTypeMethods; // // Size Helpers // template std::optional Common::size() const { model::VerifyHelper VH; return size(VH); } template RecursiveCoroutine> Common::size(model::VerifyHelper &VH) const { std::optional MaybeSize = rc_recur get().trySize(VH); revng_check(MaybeSize.has_value()); if (MaybeSize.value() == 0) rc_return std::nullopt; else rc_return MaybeSize; } // // Other Helpers // template model::TypeDefinition *Common::getPrototype() { model::Type *U = skipTypedefs(); if (U && U->isConst()) return nullptr; if (auto *Definition = U ? U->tryGetAsDefinition() : tryGetAsDefinition()) { if (llvm::isa(Definition) || llvm::isa(Definition)) { return Definition; } } return nullptr; } template const model::TypeDefinition *Common::getPrototype() const { const model::Type *U = skipTypedefs(); if (U && U->isConst()) return nullptr; if (auto *Definition = U ? U->tryGetAsDefinition() : tryGetAsDefinition()) { if (llvm::isa(Definition) || llvm::isa(Definition)) { return Definition; } } return nullptr; } template model::RawFunctionDefinition *Common::getRawFunction() { model::Type *U = skipTypedefs(); if (U && U->isConst()) return nullptr; if (auto *Definition = U ? U->tryGetAsDefinition() : tryGetAsDefinition()) if (auto *RFD = llvm::dyn_cast(Definition)) return RFD; return nullptr; } template const model::RawFunctionDefinition *Common::getRawFunction() const { const model::Type *U = skipTypedefs(); if (U && U->isConst()) return nullptr; if (auto *Definition = U ? U->tryGetAsDefinition() : tryGetAsDefinition()) if (auto *RFD = llvm::dyn_cast(Definition)) return RFD; return nullptr; } template model::CABIFunctionDefinition *Common::getCABIFunction() { model::Type *U = skipTypedefs(); if (U && U->isConst()) return nullptr; if (auto *Definition = U ? U->tryGetAsDefinition() : tryGetAsDefinition()) if (auto *CFD = llvm::dyn_cast(Definition)) return CFD; return nullptr; } template const model::CABIFunctionDefinition *Common::getCABIFunction() const { const model::Type *U = skipTypedefs(); if (U && U->isConst()) return nullptr; if (auto *Definition = U ? U->tryGetAsDefinition() : tryGetAsDefinition()) if (auto *CFD = llvm::dyn_cast(Definition)) return CFD; return nullptr; } template model::StructDefinition *Common::getStruct() { model::Type *U = skipConstAndTypedefs(); if (auto *Definition = U ? U->tryGetAsDefinition() : tryGetAsDefinition()) if (auto *Cast = llvm::dyn_cast(Definition)) return Cast; return nullptr; } template const model::StructDefinition *Common::getStruct() const { const model::Type *U = skipConstAndTypedefs(); if (auto *Definition = U ? U->tryGetAsDefinition() : tryGetAsDefinition()) if (auto *Cast = llvm::dyn_cast(Definition)) return Cast; return nullptr; } template model::UnionDefinition *Common::getUnion() { model::Type *U = skipConstAndTypedefs(); if (auto *Definition = U ? U->tryGetAsDefinition() : tryGetAsDefinition()) if (auto *Cast = llvm::dyn_cast(Definition)) return Cast; return nullptr; } template const model::UnionDefinition *Common::getUnion() const { const model::Type *U = skipConstAndTypedefs(); if (auto *Definition = U ? U->tryGetAsDefinition() : tryGetAsDefinition()) if (auto *Cast = llvm::dyn_cast(Definition)) return Cast; return nullptr; } template model::EnumDefinition *Common::getEnum() { model::Type *U = skipConstAndTypedefs(); if (auto *Definition = U ? U->tryGetAsDefinition() : tryGetAsDefinition()) if (auto *Cast = llvm::dyn_cast(Definition)) return Cast; return nullptr; } template const model::EnumDefinition *Common::getEnum() const { const model::Type *U = skipConstAndTypedefs(); if (auto *Definition = U ? U->tryGetAsDefinition() : tryGetAsDefinition()) if (auto *Cast = llvm::dyn_cast(Definition)) return Cast; return nullptr; } template model::PrimitiveType *Common::getPrimitive() { model::Type *Unwrapped = skipConstAndTypedefs(); if constexpr (std::is_same_v) if (Unwrapped == nullptr) return nullptr; if (auto *Primitive = llvm::dyn_cast(Unwrapped)) return Primitive; return nullptr; } template const model::PrimitiveType *Common::getPrimitive() const { const model::Type *Unwrapped = skipConstAndTypedefs(); if constexpr (std::is_same_v) if (Unwrapped == nullptr) return nullptr; if (auto *Primitive = llvm::dyn_cast(Unwrapped)) return Primitive; return nullptr; } template model::ArrayType *Common::getArray() { model::Type *Unwrapped = skipConstAndTypedefs(); if constexpr (std::is_same_v) if (Unwrapped == nullptr) return nullptr; if (auto *Array = llvm::dyn_cast(Unwrapped)) return Array; return nullptr; } template const model::ArrayType *Common::getArray() const { const model::Type *Unwrapped = skipConstAndTypedefs(); if constexpr (std::is_same_v) if (Unwrapped == nullptr) return nullptr; if (auto *Array = llvm::dyn_cast(Unwrapped)) return Array; return nullptr; } template model::PointerType *Common::getPointer() { model::Type *Unwrapped = skipConstAndTypedefs(); if constexpr (std::is_same_v) if (Unwrapped == nullptr) return nullptr; if (auto *Pointer = llvm::dyn_cast(Unwrapped)) return Pointer; return nullptr; } template const model::PointerType *Common::getPointer() const { const model::Type *Unwrapped = skipConstAndTypedefs(); if constexpr (std::is_same_v) if (Unwrapped == nullptr) return nullptr; if (auto *Pointer = llvm::dyn_cast(Unwrapped)) return Pointer; return nullptr; } template bool Common::isPrimitive(model::PrimitiveKind::Values Kind) const { if (const model::PrimitiveType *Primitive = getPrimitive()) return Primitive->PrimitiveKind() == Kind; return false; } template bool Common::isScalar() const { const model::Type *Unwrapped = skipConstAndTypedefs(); if constexpr (std::same_as) { if (Unwrapped == nullptr) { revng_assert(get().isObject()); return llvm::isa(get()); } } revng_assert(Unwrapped->isObject()); if (auto *Primitive = llvm::dyn_cast(Unwrapped)) { return true; } else if (auto *D = llvm::dyn_cast(Unwrapped)) { return llvm::isa(D->unwrap()); } else { return llvm::isa(*Unwrapped); } } template bool Common::isConst() const { if (auto *Unwrapped = skipTypedefs()) return Unwrapped->IsConst(); // `skipTypedefs` can only fail if it's called on a non-typedef // `TypeDefinition` and those can never be `const`. return false; } template model::TypeDefinition *Common::tryGetAsDefinition() { if constexpr (std::is_same_v) { return &get(); } else { if (auto *Def = llvm::dyn_cast(&get())) return Def->Definition().get(); return nullptr; } } template const model::TypeDefinition *Common::tryGetAsDefinition() const { if constexpr (std::is_same_v) { return &get(); } else { if (auto *Def = llvm::dyn_cast(&get())) return Def->Definition().getConst(); return nullptr; } } using TypedefD = model::TypedefDefinition; template static RecursiveCoroutine> skipTypedefsImpl(T &&V) { if constexpr (std::is_same_v, model::TypeDefinition>) { if (auto *Typedef = llvm::dyn_cast(&V)) rc_return rc_recur skipTypedefsImpl(*Typedef->UnderlyingType()); rc_return nullptr; } else if constexpr (std::is_same_v, model::Type>) { if (auto *Def = llvm::dyn_cast(&V)) if (!Def->IsConst()) if (auto *Typedef = llvm::dyn_cast(&Def->unwrap())) rc_return rc_recur skipTypedefsImpl(*Typedef->UnderlyingType()); rc_return &V; } else { static_assert(type_always_false_v); } } template model::Type *Common::skipTypedefs() { return skipTypedefsImpl(get()); } template const model::Type *Common::skipTypedefs() const { return skipTypedefsImpl(get()); } template static RecursiveCoroutine> skipConstAndTypedefsImpl(T &&V) { if constexpr (std::is_same_v, model::TypeDefinition>) { if (auto *Typedef = llvm::dyn_cast(&V)) rc_return rc_recur skipConstAndTypedefsImpl(*Typedef->UnderlyingType()); rc_return nullptr; } else if constexpr (std::is_same_v, model::Type>) { if (auto *Def = llvm::dyn_cast(&V)) if (auto *Typedef = llvm::dyn_cast(&Def->unwrap())) rc_return rc_recur skipConstAndTypedefsImpl(*Typedef->UnderlyingType()); rc_return &V; } else { static_assert(type_always_false_v); } } template model::Type *Common::skipConstAndTypedefs() { return skipConstAndTypedefsImpl(get()); } template const model::Type *Common::skipConstAndTypedefs() const { return skipConstAndTypedefsImpl(get()); } // Force instantiation for the cases we care about template class model::CommonTypeMethods; template class model::CommonTypeMethods;