From cad8c024a2d094d1a60bec27ab0fac56b3c9e82f Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Mon, 21 Oct 2024 20:41:59 +0200 Subject: [PATCH] Make the compose and join functions in the EdgeFunction implementations optional, if the IDETabulkationProblem impl provides extend and combine --- .../phasar/DataFlow/IfdsIde/EdgeFunction.h | 74 +++++++++++++------ .../Problems/IDEInstInteractionAnalysis.h | 22 ------ include/phasar/Utils/ErrorFwd.h | 22 ++++++ lib/Utils/ErrorFwd.cpp | 26 +++++++ 4 files changed, 101 insertions(+), 43 deletions(-) create mode 100644 include/phasar/Utils/ErrorFwd.h create mode 100644 lib/Utils/ErrorFwd.cpp diff --git a/include/phasar/DataFlow/IfdsIde/EdgeFunction.h b/include/phasar/DataFlow/IfdsIde/EdgeFunction.h index ee7ee4b92..57bc1941e 100644 --- a/include/phasar/DataFlow/IfdsIde/EdgeFunction.h +++ b/include/phasar/DataFlow/IfdsIde/EdgeFunction.h @@ -12,6 +12,7 @@ #include "phasar/DataFlow/IfdsIde/EdgeFunctionSingletonCache.h" #include "phasar/Utils/ByRef.h" +#include "phasar/Utils/ErrorFwd.h" #include "phasar/Utils/TypeTraits.h" #include "llvm/ADT/DenseMapInfo.h" @@ -41,28 +42,48 @@ template struct IsEdgeFunction : std::false_type {}; template struct IsEdgeFunction< - T, std::void_t< - typename T::l_t, - decltype(std::declval().computeTarget( - std::declval())), - decltype(T::compose(std::declval>(), - std::declval>())), - decltype(T::join(std::declval>(), - std::declval>()))>> + T, std::void_t().computeTarget( + std::declval()))>> : std::true_type {}; + +template struct HasEFCompose : std::false_type {}; +template +struct HasEFCompose>(), + std::declval>()))>> : std::true_type {}; +template struct HasEFJoin : std::false_type {}; +template +struct HasEFJoin>(), + std::declval>()))>> + : std::true_type {}; } // namespace detail template static constexpr bool IsEdgeFunction = detail::IsEdgeFunction::value; +template +static constexpr bool HasEFCompose = detail::HasEFCompose::value; +template +static constexpr bool HasEFJoin = detail::HasEFJoin::value; #else // clang-format off template -concept IsEdgeFunction = requires(const T &EF, const EdgeFunction& TEEF, EdgeFunctionRef CEF, typename T::l_t Src) { +concept IsEdgeFunction = requires(const T &EF, typename T::l_t Src) { typename T::l_t; {EF.computeTarget(Src)} -> std::convertible_to; - {T::compose(CEF, TEEF)} -> std::same_as>; - {T::join(CEF, TEEF)} -> std::same_as>; +}; + +template +concept HasEFCompose = requires(EdgeFunctionRef EFRef, + const EdgeFunction &EF) { + { T::compose(EFRef, EF) } -> std::convertible_to>; +}; +template +concept HasEFJoin = requires(EdgeFunctionRef EFRef, + const EdgeFunction &EF) { + { T::join(EFRef, EF) } -> std::convertible_to>; }; // clang-format on @@ -700,17 +721,28 @@ class [[clang::trivial_abi]] EdgeFunction final : EdgeFunctionBase { return getPtr(EF)->computeTarget(Source); }, [](const void *EF, const EdgeFunction &SecondEF, - AllocationPolicy Policy) { - return ConcreteEF::compose( - EdgeFunctionRef( - EF, Policy == AllocationPolicy::CustomHeapAllocated), - SecondEF); + AllocationPolicy Policy) -> EdgeFunction { + if constexpr (HasEFCompose) { + return ConcreteEF::compose( + EdgeFunctionRef( + EF, Policy == AllocationPolicy::CustomHeapAllocated), + SecondEF); + } else { + composeEFPureVirtualError(llvm::getTypeName(), + llvm::getTypeName()); + } }, - [](const void *EF, const EdgeFunction &OtherEF, AllocationPolicy Policy) { - return ConcreteEF::join( - EdgeFunctionRef( - EF, Policy == AllocationPolicy::CustomHeapAllocated), - OtherEF); + [](const void *EF, const EdgeFunction &OtherEF, + AllocationPolicy Policy) -> EdgeFunction { + if constexpr (HasEFJoin) { + return ConcreteEF::join( + EdgeFunctionRef( + EF, Policy == AllocationPolicy::CustomHeapAllocated), + OtherEF); + } else { + joinEFPureVirtualError(llvm::getTypeName(), + llvm::getTypeName()); + } }, [](const void *EF1, const void *EF2) noexcept { static_assert(IsEqualityComparable || diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h index b4410d1f9..0e12d451c 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h @@ -950,17 +950,6 @@ class IDEInstInteractionAnalysisT l_t computeTarget(ByConstRef /* Src */) const { return Replacement; } - static EdgeFunction - compose(EdgeFunctionRef /*This*/, - const EdgeFunction /*SecondFunction*/) { - llvm::report_fatal_error("Implemented in 'extend'"); - } - - static EdgeFunction join(EdgeFunctionRef /*This*/, - const EdgeFunction & /*OtherFunction*/) { - llvm::report_fatal_error("Implemented in 'combine'"); - } - bool operator==(const IIAAKillOrReplaceEF &Other) const noexcept { return Replacement == Other.Replacement; } @@ -1001,17 +990,6 @@ class IDEInstInteractionAnalysisT return IDEInstInteractionAnalysisT::joinImpl(Src, Data); } - static EdgeFunction - compose(EdgeFunctionRef /*This*/, - const EdgeFunction & /*SecondFunction*/) { - llvm::report_fatal_error("Implemented in 'extend'"); - } - - static EdgeFunction join(EdgeFunctionRef /*This*/, - const EdgeFunction & /*OtherFunction*/) { - llvm::report_fatal_error("Implemented in 'combine'"); - } - bool operator==(const IIAAAddLabelsEF &Other) const noexcept { return Data == Other.Data; } diff --git a/include/phasar/Utils/ErrorFwd.h b/include/phasar/Utils/ErrorFwd.h new file mode 100644 index 000000000..d6e93fd04 --- /dev/null +++ b/include/phasar/Utils/ErrorFwd.h @@ -0,0 +1,22 @@ +/****************************************************************************** + * Copyright (c) 2024 Fabian Schiebel. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Fabian Schiebel and others + *****************************************************************************/ + +#ifndef PHASAR_UTILS_ERRORFWD_H +#define PHASAR_UTILS_ERRORFWD_H + +#include "llvm/ADT/StringRef.h" + +namespace psr { +[[noreturn, gnu::cold]] void +composeEFPureVirtualError(llvm::StringRef ConcreteEF, llvm::StringRef L); +[[noreturn, gnu::cold]] void joinEFPureVirtualError(llvm::StringRef ConcreteEF, + llvm::StringRef L); +} // namespace psr + +#endif // PHASAR_UTILS_ERRORFWD_H diff --git a/lib/Utils/ErrorFwd.cpp b/lib/Utils/ErrorFwd.cpp new file mode 100644 index 000000000..3f8766bec --- /dev/null +++ b/lib/Utils/ErrorFwd.cpp @@ -0,0 +1,26 @@ +#include "phasar/Utils/ErrorFwd.h" + +#include "llvm/ADT/Twine.h" +#include "llvm/Support/ErrorHandling.h" + +void psr::composeEFPureVirtualError(llvm::StringRef ConcreteEF, + llvm::StringRef L) { + llvm::report_fatal_error( + "EdgeFunction composition is not implemented for " + ConcreteEF + + "; Either implement static EdgeFunction<" + L + + "> compose(const EdgeFunctionRef<" + ConcreteEF + + ">, const EdgeFunction<" + L + ">&) in " + ConcreteEF + + ", or override EdgeFunction<" + L + "> extend(const EdgeFunction<" + L + + ">&, const EdgeFunction<" + L + ">&) in your IDETabulationProblem"); +} + +void psr::joinEFPureVirtualError(llvm::StringRef ConcreteEF, + llvm::StringRef L) { + llvm::report_fatal_error( + "EdgeFunction join is not implemented for " + ConcreteEF + + "; Either implement static EdgeFunction<" + L + + "> join(const EdgeFunctionRef<" + ConcreteEF + ">, const EdgeFunction<" + + L + ">&) in " + ConcreteEF + ", or override EdgeFunction<" + L + + "> combine(const EdgeFunction<" + L + ">&, const EdgeFunction<" + L + + ">&) in your IDETabulationProblem"); +}