#pragma once // // This file is distributed under the MIT License. See LICENSE.md for details. // #include "revng/Model/Binary.h" #include "revng/Model/Register.h" #include "revng/Model/Type.h" namespace abi { using RegisterState = model::RegisterState::Values; using RegisterStateMap = std::map>; template class ABI { public: static std::optional toRaw(model::Binary &TheBinary, const model::CABIFunctionType &Original) { return {}; } static std::optional toCABI(model::Binary &TheBinary, const model::RawFunctionType &Explicit) { return {}; } static model::TypePath defaultPrototype(model::Binary &TheBinary) { model::TypePath Void = TheBinary.getPrimitiveType(model::PrimitiveTypeKind::Void, 0); return TheBinary.recordNewType(model::makeType()); } void applyDeductions(RegisterStateMap &Prototype) { return; } }; // TODO: make this as much reusable as possible // TODO: test template<> class ABI { private: static constexpr std::array ArgumentRegisters = { model::Register::rdi_x86_64, model::Register::rsi_x86_64, model::Register::rdx_x86_64, model::Register::rcx_x86_64, model::Register::r8_x86_64, model::Register::r9_x86_64 }; static constexpr std::array ReturnValueRegisters = { model::Register::rax_x86_64, model::Register::rdx_x86_64 }; static constexpr std::array CalleeSavedRegisters = { model::Register::rbx_x86_64, model::Register::rbp_x86_64, model::Register::r12_x86_64, model::Register::r13_x86_64, model::Register::r14_x86_64, model::Register::r15_x86_64 }; private: struct AnalysisResult { bool IsValid; uint64_t Arguments; uint64_t ReturnValues; }; static AnalysisResult analyze(model::Binary &TheBinary, const model::RawFunctionType &Explicit); public: static std::optional toRaw(model::Binary &TheBinary, const model::CABIFunctionType &Original); static bool isCompatible(model::Binary &TheBinary, const model::RawFunctionType &Explicit); static std::optional toCABI(model::Binary &TheBinary, const model::RawFunctionType &Explicit); static model::TypePath defaultPrototype(model::Binary &TheBinary); void applyDeductions(RegisterStateMap &Prototype); }; template auto polyswitch(T Value, const auto &F) { constexpr T Current = static_cast(Index); if constexpr (Index < static_cast(T::Count)) { if (Current == Value) { return F.template operator()(); } else { return polyswitch(Value, F); } } else { revng_abort(); return F.template operator()(); } } inline std::optional getRawFunctionType(model::Binary &TheBinary, const model::CABIFunctionType *CABI) { revng_assert(CABI != nullptr); return polyswitch(CABI->ABI, [&]() { return ABI::toRaw(TheBinary, *CABI); }); } inline std::optional getRawFunctionType(model::Binary &TheBinary, const model::Type *T) { revng_assert(T != nullptr); using namespace llvm; if (auto *Raw = dyn_cast(T)) { return *Raw; } else if (auto *CABI = dyn_cast(T)) { return getRawFunctionType(TheBinary, CABI); } else { revng_abort("getRawFunctionType with non-function type"); } } inline model::RawFunctionType getRawFunctionTypeOrDefault(model::Binary &TheBinary, const model::Type *T) { revng_assert(T != nullptr); using namespace llvm; if (auto *Raw = dyn_cast(T)) { return *Raw; } else if (auto *CABI = dyn_cast(T)) { auto MaybeResult = getRawFunctionType(TheBinary, CABI); if (MaybeResult) { return *MaybeResult; } else { auto GetDefaultPrototype = [&]() { return ABI::defaultPrototype(TheBinary); }; model::TypePath Result = polyswitch(CABI->ABI, GetDefaultPrototype); return *cast(Result.get()); } } else { revng_abort("getRawFunctionType with non-function type"); } } } // namespace abi