From 2a971245b229151a9bf2dfb913d82318575e360d Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Tue, 20 Oct 2026 20:37:42 +0200 Subject: [PATCH 1/4] Make phasar compile with LLVM 23 (new DenseMap impl makes problems!) --- .../DefaultEdgeFunctionSingletonCache.h | 6 ++-- .../phasar/DataFlow/IfdsIde/EdgeFunction.h | 7 +++- .../IfdsIde/Solver/IterativeIDESolver.h | 12 ++++--- .../IfdsIde/Solver/IterativeIDESolverBase.h | 6 ++++ .../ControlFlow/VTA/TypeAssignmentGraph.h | 3 +- .../AbstractMemoryLocation.h | 2 ++ .../Problems/IDEFeatureTaintAnalysis.h | 28 +++++++++------ .../Problems/IDEInstInteractionAnalysis.h | 4 +++ .../Pointer/CachedLLVMAliasIterator.h | 2 ++ .../Pointer/LLVMPointerAssignmentGraph.h | 2 ++ include/phasar/Utils/Compressor.h | 4 ++- include/phasar/Utils/TableWrappers.h | 7 ++++ include/phasar/Utils/TypeTraits.h | 2 ++ .../IfdsIde/CFLFieldSensIFDSProblem.cpp | 35 +++++++++++++++++++ lib/PhasarLLVM/Pointer/AndersenOTFAA.cpp | 8 +++++ .../external/llvm/AliasAnalysisSummary.h | 2 ++ .../external/llvm/CFLAndersAliasAnalysis.cpp | 4 +++ lib/Pointer/PointsToInfo.cpp | 3 ++ test/llvm_test_code/CMakeLists.txt | 11 +++--- 19 files changed, 125 insertions(+), 23 deletions(-) diff --git a/include/phasar/DataFlow/IfdsIde/DefaultEdgeFunctionSingletonCache.h b/include/phasar/DataFlow/IfdsIde/DefaultEdgeFunctionSingletonCache.h index bcd13661c6..d195930db3 100644 --- a/include/phasar/DataFlow/IfdsIde/DefaultEdgeFunctionSingletonCache.h +++ b/include/phasar/DataFlow/IfdsIde/DefaultEdgeFunctionSingletonCache.h @@ -68,6 +68,7 @@ class DefaultEdgeFunctionSingletonCacheImpl if (LHS == RHS) { return true; } +#if LLVM_VERSION_MAJOR < 23 const auto *Empty = llvm::DenseMapInfo::getEmptyKey(); const auto *Tombstone = @@ -76,15 +77,16 @@ class DefaultEdgeFunctionSingletonCacheImpl RHS == Tombstone) { return false; } - +#endif return *LHS == *RHS; } static auto getHashValue(const EdgeFunctionTy *EF) noexcept { +#if LLVM_VERSION_MAJOR < 23 assert(EF != llvm::DenseMapInfo::getEmptyKey()); assert(EF != llvm::DenseMapInfo::getTombstoneKey()); - +#endif return hash_value(*EF); } }; diff --git a/include/phasar/DataFlow/IfdsIde/EdgeFunction.h b/include/phasar/DataFlow/IfdsIde/EdgeFunction.h index 1f46902b85..578f3e2e8a 100644 --- a/include/phasar/DataFlow/IfdsIde/EdgeFunction.h +++ b/include/phasar/DataFlow/IfdsIde/EdgeFunction.h @@ -628,6 +628,7 @@ class PSR_TRIVIAL_ABI PSR_OWNER() EdgeFunction final : EdgeFunctionBase { return EF.getHashCode(); } +#if LLVM_VERSION_MAJOR < 23 static EdgeFunction getEmptyKey() noexcept { return EdgeFunction(nullptr, {llvm::DenseMapInfo::getEmptyKey(), @@ -639,6 +640,7 @@ class PSR_TRIVIAL_ABI PSR_OWNER() EdgeFunction final : EdgeFunctionBase { {llvm::DenseMapInfo::getTombstoneKey(), AllocationPolicy::SmallObjectOptimized}); } +#endif private: struct VTable { @@ -793,17 +795,20 @@ class PSR_TRIVIAL_ABI PSR_OWNER() EdgeFunction final : EdgeFunctionBase { namespace llvm { template struct DenseMapInfo> { +#if LLVM_VERSION_MAJOR < 23 static auto getEmptyKey() noexcept { return psr::EdgeFunction::getEmptyKey(); } static auto getTombstoneKey() noexcept { return psr::EdgeFunction::getTombstoneKey(); } +#endif static auto getHashValue(const psr::EdgeFunction &EF) noexcept { return EF.getHashCode(); } static auto isEqual(const psr::EdgeFunction &EF1, const psr::EdgeFunction &EF2) noexcept { +#if LLVM_VERSION_MAJOR < 23 if (EF1.referenceEquals(EF2)) { return true; } @@ -813,7 +818,7 @@ template struct DenseMapInfo> { EF1.referenceEquals(Tombstone) || EF2.referenceEquals(Tombstone)) { return false; } - +#endif return EF1 == EF2; } }; diff --git a/include/phasar/DataFlow/IfdsIde/Solver/IterativeIDESolver.h b/include/phasar/DataFlow/IfdsIde/Solver/IterativeIDESolver.h index 590b4ff686..c35ed663ef 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/IterativeIDESolver.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/IterativeIDESolver.h @@ -199,9 +199,7 @@ class IterativeIDESolver this->base_results_t::ValTab.emplace_back().reserve(16); } if constexpr (EnableJumpFunctionGC != JumpFunctionGCMode::Disabled) { - RefCountPerFunction = llvm::OwningArrayRef(NumFuns); - std::uninitialized_fill_n(RefCountPerFunction.data(), - RefCountPerFunction.size(), 0); + RefCountPerFunction.resize(NumFuns, 0); CandidateFunctionsForGC.resize(NumFuns); } @@ -1283,6 +1281,11 @@ class IterativeIDESolver } void cleanupInterJobsFor(unsigned FunId) { +#if LLVM_VERSION_MAJOR >= 23 + SourceFactAndFuncToInterJob.eraseIf([FunId](const auto &Cell) { + return splitId(Cell.first).second == FunId; + }); +#else auto Cells = SourceFactAndFuncToInterJob.cells(); for (auto Iter = Cells.begin(), End = Cells.end(); Iter != End;) { auto It = Iter++; @@ -1291,6 +1294,7 @@ class IterativeIDESolver SourceFactAndFuncToInterJob.erase(It); } } +#endif } void collectFunction(unsigned FunId) { @@ -1377,7 +1381,7 @@ class IterativeIDESolver EmptyType> EndSummaryTab; - llvm::OwningArrayRef RefCountPerFunction{}; + llvm::SmallVector RefCountPerFunction{}; llvm::BitVector CandidateFunctionsForGC{}; flow_edge_function_cache_t FECache{Problem}; diff --git a/include/phasar/DataFlow/IfdsIde/Solver/IterativeIDESolverBase.h b/include/phasar/DataFlow/IfdsIde/Solver/IterativeIDESolverBase.h index 07f427aed4..5bd7e6e1dd 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/IterativeIDESolverBase.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/IterativeIDESolverBase.h @@ -90,16 +90,20 @@ class IterativeIDESolverBase { }; struct InterPropagationJobRefDSI { +#if LLVM_VERSION_MAJOR < 23 static InterPropagationJobRef getEmptyKey() noexcept { return {llvm::DenseMapInfo::getEmptyKey()}; } static InterPropagationJobRef getTombstoneKey() noexcept { return {llvm::DenseMapInfo::getTombstoneKey()}; } +#endif static auto getHashValue(InterPropagationJobRef Job) noexcept { assert(Job.JobPtr != nullptr); +#if LLVM_VERSION_MAJOR < 23 assert(Job.JobPtr != getEmptyKey().JobPtr); assert(Job.JobPtr != getTombstoneKey().JobPtr); +#endif return Job.JobPtr->getHashCode(); } static bool isEqual(InterPropagationJobRef LHS, @@ -107,12 +111,14 @@ class IterativeIDESolverBase { if (LHS.JobPtr == RHS.JobPtr) { return true; } +#if LLVM_VERSION_MAJOR < 23 if (LHS.JobPtr == getEmptyKey().JobPtr || LHS.JobPtr == getTombstoneKey().JobPtr || RHS.JobPtr == getEmptyKey().JobPtr || RHS.JobPtr == getTombstoneKey().JobPtr) { return false; } +#endif assert(LHS.JobPtr != nullptr); assert(RHS.JobPtr != nullptr); diff --git a/include/phasar/PhasarLLVM/ControlFlow/VTA/TypeAssignmentGraph.h b/include/phasar/PhasarLLVM/ControlFlow/VTA/TypeAssignmentGraph.h index 0e4db14a17..fca4fe82d3 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/VTA/TypeAssignmentGraph.h +++ b/include/phasar/PhasarLLVM/ControlFlow/VTA/TypeAssignmentGraph.h @@ -81,7 +81,7 @@ template <> struct DenseMapInfo { using Variable = psr::vta::Variable; using Field = psr::vta::Field; using Return = psr::vta::Return; - +#if LLVM_VERSION_MAJOR < 23 inline static TAGNode getEmptyKey() noexcept { return {Variable{llvm::DenseMapInfo::getEmptyKey()}}; } @@ -89,6 +89,7 @@ template <> struct DenseMapInfo { return { Variable{llvm::DenseMapInfo::getTombstoneKey()}}; } +#endif inline static bool isEqual(TAGNode L, TAGNode R) noexcept { return L == R; } inline static auto getHashValue(TAGNode TN) noexcept { if (const auto *Var = std::get_if(&TN.Label)) { diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocation.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocation.h index ceec4e404c..8b72b5373d 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocation.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocation.h @@ -209,6 +209,7 @@ llvm::hash_code hash_value(psr::AbstractMemoryLocation Val); namespace llvm { template <> struct DenseMapInfo { +#if LLVM_VERSION_MAJOR < 23 static inline psr::AbstractMemoryLocation getEmptyKey() { return { DenseMapInfo::getEmptyKey()}; @@ -217,6 +218,7 @@ template <> struct DenseMapInfo { return {DenseMapInfo< psr::detail::AbstractMemoryLocationImpl *>::getTombstoneKey()}; } +#endif static unsigned getHashValue(psr::AbstractMemoryLocation Val) { return hash_value(Val); } diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEFeatureTaintAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEFeatureTaintAnalysis.h index b56095e03d..ce33c553d1 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEFeatureTaintAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEFeatureTaintAnalysis.h @@ -61,7 +61,9 @@ struct IDEFeatureTaintEdgeFact { : Taints(Taints) {} IDEFeatureTaintEdgeFact(uintptr_t Taints) noexcept : Taints(fromBits(Taints)) {} - explicit IDEFeatureTaintEdgeFact() noexcept { Taints.invalid(); } + explicit IDEFeatureTaintEdgeFact() noexcept { + // Taints.invalid(); + } void unionWith(uintptr_t Facts) { size_t RequiredSize = llvm::bit_width(Facts); @@ -72,26 +74,32 @@ struct IDEFeatureTaintEdgeFact { sizeof(Facts) / sizeof(uint32_t)); } void unionWith(const IDEFeatureTaintEdgeFact &Facts) { - if (Facts.isTop()) { - return; - } + // if (Facts.isTop()) { + // return; + // } Taints |= Facts.Taints; } /// Checks whether this set contains no facts. /// Note: Top also counts as empty - [[nodiscard]] bool empty() const noexcept { return isTop() || Taints.none(); } + [[nodiscard]] bool empty() const noexcept { + return // isTop() || + Taints.none(); + } /// Returns the number of facts in this set. /// Note: Top counts as empty [[nodiscard]] size_t size() const noexcept { - if (isTop()) { - return 0; - } + // if (isTop()) { + // return 0; + // } return Taints.count(); } [[nodiscard]] bool isBottom() const noexcept { return Taints.empty(); } - [[nodiscard]] bool isTop() const noexcept { return Taints.isInvalid(); } + [[nodiscard]] bool isTop() const noexcept { + return // Taints.isInvalid(); + false; + } [[nodiscard]] friend llvm::hash_code hash_value(const IDEFeatureTaintEdgeFact &BV) noexcept { @@ -168,7 +176,7 @@ struct IDEFeatureTaintEdgeFact { template <> struct JoinLatticeTraits { static IDEFeatureTaintEdgeFact top() { - IDEFeatureTaintEdgeFact Ret{}; + IDEFeatureTaintEdgeFact Ret{0}; return Ret; } static IDEFeatureTaintEdgeFact bottom() { diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h index 8ca5d6955f..1f651c003e 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h @@ -1206,6 +1206,7 @@ using IDEInstInteractionAnalysis = IDEInstInteractionAnalysisT<>; // Compatibility with llvm::DenseMap/DenseSet: namespace llvm { template <> struct DenseMapInfo { +#if LLVM_VERSION_MAJOR < 23 static psr::IDEIIAFlowFact getEmptyKey() { return psr::IDEIIAFlowFact( DenseMapInfo::getEmptyKey()); @@ -1214,8 +1215,10 @@ template <> struct DenseMapInfo { return psr::IDEIIAFlowFact( DenseMapInfo::getTombstoneKey()); } +#endif static bool isEqual(const psr::IDEIIAFlowFact &L, const psr::IDEIIAFlowFact &R) { +#if LLVM_VERSION_MAJOR < 23 const auto *Empty = DenseMapInfo::getEmptyKey(); const auto *TS = DenseMapInfo::getTombstoneKey(); if (L.getBase() == Empty) { @@ -1227,6 +1230,7 @@ template <> struct DenseMapInfo { if (R.getBase() == Empty || R.getBase() == TS) { return false; } +#endif return L == R; } static unsigned getHashValue(const psr::IDEIIAFlowFact &FF) { diff --git a/include/phasar/PhasarLLVM/Pointer/CachedLLVMAliasIterator.h b/include/phasar/PhasarLLVM/Pointer/CachedLLVMAliasIterator.h index cd771e0087..6f1e8d9731 100644 --- a/include/phasar/PhasarLLVM/Pointer/CachedLLVMAliasIterator.h +++ b/include/phasar/PhasarLLVM/Pointer/CachedLLVMAliasIterator.h @@ -103,12 +103,14 @@ class CachedLLVMAliasIterator }; struct ReachableAllocationSitesKeyDMI { +#if LLVM_VERSION_MAJOR < 23 static ReachableAllocationSitesKey getEmptyKey() noexcept { return {{}, llvm::DenseMapInfo::getEmptyKey()}; } static ReachableAllocationSitesKey getTombstoneKey() noexcept { return {{}, llvm::DenseMapInfo::getTombstoneKey()}; } +#endif static auto getHashValue(ReachableAllocationSitesKey Key) noexcept { return llvm::hash_combine(Key.FunAndIntraProcOnly.getOpaqueValue(), Key.Value); diff --git a/include/phasar/PhasarLLVM/Pointer/LLVMPointerAssignmentGraph.h b/include/phasar/PhasarLLVM/Pointer/LLVMPointerAssignmentGraph.h index 3679bb6cb7..2949297ea6 100644 --- a/include/phasar/PhasarLLVM/Pointer/LLVMPointerAssignmentGraph.h +++ b/include/phasar/PhasarLLVM/Pointer/LLVMPointerAssignmentGraph.h @@ -178,12 +178,14 @@ template <> struct PointerLikeTypeTraits { }; template <> struct DenseMapInfo { +#if LLVM_VERSION_MAJOR < 23 static psr::PAGVariable getEmptyKey() noexcept { return DenseMapInfo::getEmptyKey(); } static psr::PAGVariable getTombstoneKey() noexcept { return DenseMapInfo::getTombstoneKey(); } +#endif static hash_code getHashValue(psr::PAGVariable V) noexcept { return hash_value(V); } diff --git a/include/phasar/Utils/Compressor.h b/include/phasar/Utils/Compressor.h index 2a2eb6ea3d..574320f922 100644 --- a/include/phasar/Utils/Compressor.h +++ b/include/phasar/Utils/Compressor.h @@ -150,7 +150,7 @@ class Compressor { if (auto It = ToInt.find(&Elem); It != ToInt.end()) { return {It->second, false}; } - auto Ret = Id(FromInt.size()); + auto Ret = IdT(FromInt.size()); auto *Ins = &FromInt.emplace_back(Elem); ToInt[Ins] = Ret; return {Ret, true}; @@ -235,10 +235,12 @@ class Compressor { if (LHS == RHS) { return true; } +#if LLVM_VERSION_MAJOR < 23 if (LHS == DSI::getEmptyKey() || LHS == DSI::getTombstoneKey() || RHS == DSI::getEmptyKey() || RHS == DSI::getTombstoneKey()) { return false; } +#endif if constexpr (has_llvm_dense_map_info) { return llvm::DenseMapInfo::isEqual(*LHS, *RHS); } else { diff --git a/include/phasar/Utils/TableWrappers.h b/include/phasar/Utils/TableWrappers.h index 860e8dd822..0a73f39ca2 100644 --- a/include/phasar/Utils/TableWrappers.h +++ b/include/phasar/Utils/TableWrappers.h @@ -456,6 +456,13 @@ template class DenseTable1d { using iterator = typename llvm::DenseMap::iterator; using const_iterator = typename llvm::DenseMap::const_iterator; +#if LLVM_VERSION_MAJOR >= 23 + /// Erases all cells for which P(Cell) returns true. + template void eraseIf(Pred P) { + Map.remove_if(std::move(P)); + } +#endif + DenseTable1d() noexcept = default; /// Dummy ctor for compatibility with UnorderedTable1d template diff --git a/include/phasar/Utils/TypeTraits.h b/include/phasar/Utils/TypeTraits.h index c52ebe174f..85d6ef99ed 100644 --- a/include/phasar/Utils/TypeTraits.h +++ b/include/phasar/Utils/TypeTraits.h @@ -212,8 +212,10 @@ concept has_isInteresting_v = requires( template constexpr bool has_llvm_dense_map_info = requires(const T &Val) { +#if LLVM_VERSION_MAJOR < 23 { llvm::DenseMapInfo::getEmptyKey() } -> std::same_as; { llvm::DenseMapInfo::getTombstoneKey() } -> std::same_as; +#endif { llvm::DenseMapInfo::getHashValue(Val) } -> std::convertible_to; { llvm::DenseMapInfo::isEqual(Val, Val) } -> std::convertible_to; }; diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/CFLFieldSensIFDSProblem.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/CFLFieldSensIFDSProblem.cpp index 00c9854977..1e172c0293 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/CFLFieldSensIFDSProblem.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/CFLFieldSensIFDSProblem.cpp @@ -667,6 +667,18 @@ static void klimitPaths(auto &Paths, FieldStringManager &Mgr) { ToInsert.reserve(Paths.size()); // retained across .clear() calls below // Merge stores +#if LLVM_VERSION_MAJOR >= 23 + Paths.remove_if([&](const AccessPath &AP) { + if (AP.Stores == FieldStringNodeId::None) { + return false; + } + AccessPath Approx = AP; + auto StoresHead = Mgr[Approx.Stores]; + Approx.Stores = Mgr.prepend(AccessPath::TopOffset, StoresHead.Next); + ToInsert[Approx].push_back(AP); + return true; + }); +#else for (auto IIt = Paths.begin(), End = Paths.end(); IIt != End;) { auto It = IIt++; if (It->Stores != FieldStringNodeId::None) { @@ -677,6 +689,7 @@ static void klimitPaths(auto &Paths, FieldStringManager &Mgr) { Paths.erase(It); } } +#endif for (auto &&[Approx, OrigPaths] : ToInsert) { if (OrigPaths.size() > 2) { Paths.insert(Approx); @@ -703,6 +716,18 @@ static void klimitPaths(auto &Paths, FieldStringManager &Mgr) { // Merge loads ToInsert.clear(); +#if LLVM_VERSION_MAJOR >= 23 + Paths.remove_if([&](const AccessPath &AP) { + if (AP.Loads == FieldStringNodeId::None) { + return false; + } + AccessPath Approx = AP; + auto LoadsHead = Mgr[Approx.Loads]; + Approx.Loads = Mgr.prepend(AccessPath::TopOffset, LoadsHead.Next); + ToInsert[Approx].push_back(AP); + return true; + }); +#else for (auto IIt = Paths.begin(), End = Paths.end(); IIt != End;) { auto It = IIt++; if (It->Loads != FieldStringNodeId::None) { @@ -713,6 +738,7 @@ static void klimitPaths(auto &Paths, FieldStringManager &Mgr) { Paths.erase(It); } } +#endif for (auto &&[Approx, OrigPaths] : ToInsert) { if (OrigPaths.size() > 2) { Paths.insert(Approx); @@ -723,6 +749,14 @@ static void klimitPaths(auto &Paths, FieldStringManager &Mgr) { // Merge Kills ToInsert.clear(); +#if LLVM_VERSION_MAJOR >= 23 + Paths.remove_if([&](const AccessPath &AP) { + AccessPath Approx = AP; + Approx.Kills = {}; + ToInsert[Approx].push_back(AP); + return true; + }); +#else for (auto IIt = Paths.begin(), End = Paths.end(); IIt != End;) { auto It = IIt++; @@ -731,6 +765,7 @@ static void klimitPaths(auto &Paths, FieldStringManager &Mgr) { ToInsert[Approx].push_back(*It); Paths.erase(It); } +#endif for (auto &&[Approx, OrigPaths] : ToInsert) { if (OrigPaths.size() > 2) { auto KillSet = Mgr.kills(OrigPaths.front().Kills); diff --git a/lib/PhasarLLVM/Pointer/AndersenOTFAA.cpp b/lib/PhasarLLVM/Pointer/AndersenOTFAA.cpp index bf13e57ba5..8d55cf83d1 100644 --- a/lib/PhasarLLVM/Pointer/AndersenOTFAA.cpp +++ b/lib/PhasarLLVM/Pointer/AndersenOTFAA.cpp @@ -131,23 +131,27 @@ struct FieldWriteKey { namespace llvm { template <> struct DenseMapInfo { +#if LLVM_VERSION_MAJOR < 23 static AndersenVar getEmptyKey() noexcept { return {DenseMapInfo::getEmptyKey(), false}; } static AndersenVar getTombstoneKey() noexcept { return {DenseMapInfo::getTombstoneKey(), false}; } +#endif static unsigned getHashValue(AndersenVar V) noexcept { return hash_value(V); } static bool isEqual(AndersenVar A, AndersenVar B) noexcept { return A == B; } }; template <> struct DenseMapInfo { +#if LLVM_VERSION_MAJOR < 23 static ContextualVar getEmptyKey() noexcept { return {DenseMapInfo::getEmptyKey(), {}}; } static ContextualVar getTombstoneKey() noexcept { return {DenseMapInfo::getTombstoneKey(), {}}; } +#endif static unsigned getHashValue(ContextualVar V) noexcept { return hash_value(V); } @@ -157,23 +161,27 @@ template <> struct DenseMapInfo { }; template <> struct DenseMapInfo { +#if LLVM_VERSION_MAJOR < 23 static ObjectKey getEmptyKey() noexcept { return {DenseMapInfo::getEmptyKey(), {}}; } static ObjectKey getTombstoneKey() noexcept { return {DenseMapInfo::getTombstoneKey(), {}}; } +#endif static unsigned getHashValue(ObjectKey K) noexcept { return hash_value(K); } static bool isEqual(ObjectKey A, ObjectKey B) noexcept { return A == B; } }; template <> struct DenseMapInfo { +#if LLVM_VERSION_MAJOR < 23 static FieldWriteKey getEmptyKey() noexcept { return {DenseMapInfo::getEmptyKey(), {}}; } static FieldWriteKey getTombstoneKey() noexcept { return {DenseMapInfo::getTombstoneKey(), {}}; } +#endif static unsigned getHashValue(const FieldWriteKey &K) noexcept { auto H1 = llvm::hash_combine_range(K.Indices.begin(), K.Indices.end()); return llvm::hash_combine(H1, hash_value(K.Obj)); diff --git a/lib/PhasarLLVM/Pointer/external/llvm/AliasAnalysisSummary.h b/lib/PhasarLLVM/Pointer/external/llvm/AliasAnalysisSummary.h index 5f5ea0516e..e2f93cfcd3 100644 --- a/lib/PhasarLLVM/Pointer/external/llvm/AliasAnalysisSummary.h +++ b/lib/PhasarLLVM/Pointer/external/llvm/AliasAnalysisSummary.h @@ -247,6 +247,7 @@ instantiateExternalAttribute(ExternalAttribute EAttr, CallBase &Call); } // namespace cflaa template <> struct DenseMapInfo { +#if LLVM_VERSION_MAJOR < 23 static inline cflaa::InstantiatedValue getEmptyKey() { return cflaa::InstantiatedValue{DenseMapInfo::getEmptyKey(), DenseMapInfo::getEmptyKey()}; @@ -255,6 +256,7 @@ template <> struct DenseMapInfo { return cflaa::InstantiatedValue{DenseMapInfo::getTombstoneKey(), DenseMapInfo::getTombstoneKey()}; } +#endif static unsigned getHashValue(const cflaa::InstantiatedValue &IV) { return DenseMapInfo>::getHashValue( std::make_pair(IV.Val, IV.DerefLevel)); diff --git a/lib/PhasarLLVM/Pointer/external/llvm/CFLAndersAliasAnalysis.cpp b/lib/PhasarLLVM/Pointer/external/llvm/CFLAndersAliasAnalysis.cpp index 36796b40e6..4d1886b558 100644 --- a/lib/PhasarLLVM/Pointer/external/llvm/CFLAndersAliasAnalysis.cpp +++ b/lib/PhasarLLVM/Pointer/external/llvm/CFLAndersAliasAnalysis.cpp @@ -274,6 +274,7 @@ namespace llvm { // Specialize DenseMapInfo for OffsetValue. template <> struct DenseMapInfo { +#if LLVM_VERSION_MAJOR < 23 static OffsetValue getEmptyKey() { return OffsetValue{DenseMapInfo::getEmptyKey(), DenseMapInfo::getEmptyKey()}; @@ -283,6 +284,7 @@ template <> struct DenseMapInfo { return OffsetValue{DenseMapInfo::getTombstoneKey(), DenseMapInfo::getEmptyKey()}; } +#endif static unsigned getHashValue(const OffsetValue &OVal) { return DenseMapInfo>::getHashValue( @@ -296,6 +298,7 @@ template <> struct DenseMapInfo { // Specialize DenseMapInfo for OffsetInstantiatedValue. template <> struct DenseMapInfo { +#if LLVM_VERSION_MAJOR < 23 static OffsetInstantiatedValue getEmptyKey() { return OffsetInstantiatedValue{ DenseMapInfo::getEmptyKey(), @@ -307,6 +310,7 @@ template <> struct DenseMapInfo { DenseMapInfo::getTombstoneKey(), DenseMapInfo::getEmptyKey()}; } +#endif static unsigned getHashValue(const OffsetInstantiatedValue &OVal) { return DenseMapInfo>::getHashValue( diff --git a/lib/Pointer/PointsToInfo.cpp b/lib/Pointer/PointsToInfo.cpp index ed3ca3b485..8164a9a6f8 100644 --- a/lib/Pointer/PointsToInfo.cpp +++ b/lib/Pointer/PointsToInfo.cpp @@ -72,12 +72,15 @@ struct DummyFieldSensitiveAbstractObject { }; struct DFSAODenseMapInfo { using o_t = DummyFieldSensitiveAbstractObject; + +#if LLVM_VERSION_MAJOR < 23 static o_t getEmptyKey() noexcept { return {llvm::DenseMapInfo::getEmptyKey(), {}}; } static o_t getTombstoneKey() noexcept { return {llvm::DenseMapInfo::getTombstoneKey(), {}}; } +#endif static auto getHashValue(ByConstRef Obj) noexcept { return llvm::hash_combine(Obj.V, Obj.AccessPath[0], Obj.AccessPath[1], Obj.AccessPath[2]); diff --git a/test/llvm_test_code/CMakeLists.txt b/test/llvm_test_code/CMakeLists.txt index 37805d4293..a12498dd75 100644 --- a/test/llvm_test_code/CMakeLists.txt +++ b/test/llvm_test_code/CMakeLists.txt @@ -1,16 +1,17 @@ add_custom_target(LLFileGeneration ALL) subdirlist(subdirs ${CMAKE_CURRENT_SOURCE_DIR}) + foreach(subdir ${subdirs}) add_subdirectory(${subdir}) endforeach(subdir) - -if (PHASAR_ENABLE_INTEGRATIONTESTS) +if(PHASAR_ENABLE_INTEGRATIONTESTS) include(AddLLVM) + message(STATUS "LIT find hints: ${LLVM_TOOLS_BINARY_DIR}; ${LLVM_INSTALL_PREFIX}/build/utils/lit") find_program(LLVM_EXTERNAL_LIT_DEFAULT - NAMES lit-22 lit-21 lit-20 lit-16 llvm-lit lit lit.py + NAMES lit-23 lit-22 lit-21 lit-20 lit-16 llvm-lit lit lit.py HINTS "${LLVM_TOOLS_BINARY_DIR}" "${LLVM_INSTALL_PREFIX}/build/utils/lit" REQUIRED ) @@ -23,7 +24,7 @@ if (PHASAR_ENABLE_INTEGRATIONTESTS) get_filename_component(PSR_LIT_REALPATH ${LLVM_EXTERNAL_LIT} REALPATH) get_filename_component(PSR_LIT_DIR ${PSR_LIT_REALPATH} DIRECTORY) find_program(PSR_FILECHECK - NAMES FileCheck-22 FileCheck-21 FileCheck-20 FileCheck + NAMES FileCheck-23 FileCheck-22 FileCheck-21 FileCheck-20 FileCheck HINTS "${PSR_LIT_DIR}" "${LLVM_TOOLS_BINARY_DIR}" REQUIRED ) @@ -35,6 +36,7 @@ if (PHASAR_ENABLE_INTEGRATIONTESTS) if(NOT clang OR NOT clangcpp) message(FATAL_ERROR "Require clang and clang++") endif() + get_filename_component(PSR_CLANG_REALPATH ${clang} REALPATH) get_filename_component(PSR_CLANGPP_REALPATH ${clangcpp} REALPATH) @@ -45,6 +47,7 @@ if (PHASAR_ENABLE_INTEGRATIONTESTS) ) add_lit_testsuite(check-phasar-cli "Running the phasar-cli lit test suite" + # Note: Currently, we only have LIT-tests for taint_analysis and xtaint ${CMAKE_CURRENT_BINARY_DIR}/taint_analysis ${CMAKE_CURRENT_BINARY_DIR}/xtaint From c0a41f3a7d9531f4598dbd0740d2bf06705d0dcf Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Sun, 25 Oct 2026 17:36:29 +0100 Subject: [PATCH 2/4] Fix LLVM23 warnings + minor --- .clang-tidy | 1 + CMakeLists.txt | 161 ++++++++++-------- .../IfdsIde/Solver/DFISolverResults.h | 4 +- .../Problems/IDEInstInteractionAnalysis.h | 4 + .../PhasarLLVM/DataFlow/MonoIfds/AliasCache.h | 8 +- .../PathSensitivity/LLVMPathConstraints.h | 13 +- .../phasar/PhasarLLVM/Utils/LLVMShorthands.h | 48 ++++++ lib/DataFlow/PathSensitivity/CMakeLists.txt | 1 + .../ControlFlow/LLVMBasedBackwardCFG.cpp | 35 ++-- lib/PhasarLLVM/ControlFlow/LLVMBasedCFG.cpp | 17 +- .../IfdsIde/CFLFieldSensIFDSProblem.cpp | 4 +- .../DataFlow/PathSensitivity/CMakeLists.txt | 2 +- .../PathSensitivity/LLVMPathConstraints.cpp | 24 ++- .../Passes/GeneralStatisticsAnalysis.cpp | 4 + lib/PhasarLLVM/Utils/LLVMShorthands.cpp | 12 +- test/llvm_test_code/lit.cfg.py | 2 +- tools/hello-modules-tool/hello_modules.cpp | 2 +- 17 files changed, 234 insertions(+), 108 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index d7b7d2d702..370177e037 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -33,6 +33,7 @@ Checks: '-*, -cppcoreguidelines-macro-usage, -cppcoreguidelines-avoid-do-while, -cppcoreguidelines-avoid-c-arrays, + -cppcoreguidelines-pro-bounds-avoid-unchecked-container-access, bugprone-*, -bugprone-easily-swappable-parameters, modernize-*, diff --git a/CMakeLists.txt b/CMakeLists.txt index f02b3cc2e7..e1cb8c0ac8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required (VERSION 3.23...4.2) # 3.23+ needed by FILE_SET (https://cmake.org/cmake/help/latest/command/target_sources.html#file-sets) +cmake_minimum_required(VERSION 3.23...4.2) # 3.23+ needed by FILE_SET (https://cmake.org/cmake/help/latest/command/target_sources.html#file-sets) # Avoid IPO/LTO Warnings: cmake_policy(SET CMP0069 NEW) @@ -17,21 +17,22 @@ cmake_policy(SET CMP0063 NEW) set(CMAKE_POLICY_DEFAULT_CMP0063 NEW) # Check if we build within the llvm source tree -if (DEFINED LLVM_MAIN_SRC_DIR) +if(DEFINED LLVM_MAIN_SRC_DIR) set(PHASAR_IN_TREE 1) endif() set(PHASAR_VERSION 2604) -if (NOT PHASAR_IN_TREE) - project (phasar + +if(NOT PHASAR_IN_TREE) + project(phasar LANGUAGES C CXX DESCRIPTION "A LLVM-based static analysis framework." VERSION ${PHASAR_VERSION} ) -endif () +endif() # NOTE: When we require cmake >= 3.21, we can use PROJECT_IS_TOP_LEVEL instead -if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) +if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) set(PHASAR_BUILD_OPTIONAL_TARGETS_DEFAULT ON) else() set(PHASAR_BUILD_OPTIONAL_TARGETS_DEFAULT OFF) @@ -52,10 +53,10 @@ set(PHASAR_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PHASAR_SRC_DIR}/cmake") include("phasar_macros") -if (NOT CMAKE_BUILD_TYPE AND NOT GENERATOR_IS_MULTI_CONFIG AND NOT PHASAR_IN_TREE) +if(NOT CMAKE_BUILD_TYPE AND NOT GENERATOR_IS_MULTI_CONFIG AND NOT PHASAR_IN_TREE) message(STATUS "No CMAKE_BUILD_TYPE specified, setting it to Debug") set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Build mode ('Debug' or 'Release', default is 'Debug')" FORCE) -endif () +endif() if(GENERATOR_IS_MULTI_CONFIG) message(STATUS "Selected multi-config Build") @@ -69,7 +70,6 @@ set(RELEASE_CONFIGURATIONS RELWITHDEBINFO RELEASE CACHE INTERNAL "" FORCE) # TODO: Once available, we may want to use -fextend-lifetimes on Debug- and RelWithDebInfo builds to improve debugging experience # https://reviews.llvm.org/D157613 - string(APPEND CMAKE_CXX_FLAGS " -MP -fstack-protector-strong -ffunction-sections -fdata-sections -pipe") string(APPEND CMAKE_CXX_FLAGS_DEBUG " -fno-omit-frame-pointer") string(APPEND CMAKE_C_FLAGS_DEBUG " -fno-omit-frame-pointer") @@ -84,7 +84,7 @@ option(PHASAR_BUILD_MODULES "Build C++20 modules for phasar" OFF) include(CheckCXXCompilerFlag) # Handle memory issues with linking -if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU") +if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU") string(APPEND CMAKE_CXX_FLAGS_DEBUG " -gsplit-dwarf") string(APPEND CMAKE_CXX_FLAGS_RELWITHDEBINFO " -gsplit-dwarf") set(LINKER_FLAGS_SAVE ${CMAKE_EXE_LINKER_FLAGS}) @@ -105,11 +105,10 @@ endif() # march=native # NOTE: Use gcc -march=native -Q --help=target | grep -- '-march=' | cut -f3 -# to check the architecture detected by match=native +# to check the architecture detected by match=native # set(PHASAR_TARGET_ARCH "" CACHE STRING "Optimize the build for the given target architecture, e.g. -march=native. Most useful in Release builds. Disabled by default") - -if (DEFINED PHASAR_TARGET_ARCH) - if (NOT CMAKE_BUILD_TYPE STREQUAL "Release" AND NOT GENERATOR_IS_MULTI_CONFIG) +if(DEFINED PHASAR_TARGET_ARCH) + if(NOT CMAKE_BUILD_TYPE STREQUAL "Release" AND NOT GENERATOR_IS_MULTI_CONFIG) message(WARNING "The PHASAR_TARGET_ARCH flag will be ignored in non-Release build type ${CMAKE_BUILD_TYPE}") else() set(PHASAR_TARGET_ARCH_INTERNAL "${PHASAR_TARGET_ARCH}") @@ -118,9 +117,10 @@ elseif("${CMAKE_BUILD_TYPE}" STREQUAL "Release") set(PHASAR_TARGET_ARCH_INTERNAL "native") endif() -if (NOT "${PHASAR_TARGET_ARCH_INTERNAL}" STREQUAL "") +if(NOT "${PHASAR_TARGET_ARCH_INTERNAL}" STREQUAL "") check_cxx_compiler_flag("-march=${PHASAR_TARGET_ARCH_INTERNAL}" MARCH_SUPPORTED) - if (MARCH_SUPPORTED) + + if(MARCH_SUPPORTED) message(STATUS "Target architecture '${PHASAR_TARGET_ARCH_INTERNAL}' enabled") string(APPEND CMAKE_CXX_FLAGS_RELEASE " -march=${PHASAR_TARGET_ARCH_INTERNAL}") string(APPEND CMAKE_C_FLAGS_RELEASE " -march=${PHASAR_TARGET_ARCH_INTERNAL}") @@ -130,7 +130,7 @@ if (NOT "${PHASAR_TARGET_ARCH_INTERNAL}" STREQUAL "") endif() # Sanitizers -if (PHASAR_ENABLE_SANITIZERS) +if(PHASAR_ENABLE_SANITIZERS) message(STATUS "Selected ${CMAKE_BUILD_TYPE} Build with Sanitizers") if(MSVC) @@ -144,8 +144,9 @@ endif() # LTO option(PHASAR_ALLOW_LTO_IN_RELEASE_BUILD "Use link-time-optimization (LTO) in Release builds, if possible (default is ON)" ON) + if(PHASAR_ALLOW_LTO_IN_RELEASE_BUILD) - if (GENERATOR_IS_MULTI_CONFIG OR CMAKE_BUILD_TYPE STREQUAL "Release") + if(GENERATOR_IS_MULTI_CONFIG OR CMAKE_BUILD_TYPE STREQUAL "Release") include(CheckIPOSupported) check_ipo_supported(RESULT LTO_SUPPORTED OUTPUT LTO_SUPPORT_ERROR) @@ -176,27 +177,29 @@ option(PHASAR_DEBUG_LIBDEPS "Debug internal library dependencies (private linkag option(PHASAR_BUILD_TOOLS "Build PhASAR-based tools (default is ON)" ${PHASAR_BUILD_OPTIONAL_TARGETS_DEFAULT}) option(PHASAR_USE_CONAN "Using Conan for dependencies instead of submodules." OFF) -#option(BUILD_SHARED_LIBS "Build shared libraries (default is ON)" ON) +# option(BUILD_SHARED_LIBS "Build shared libraries (default is ON)" ON) option(PHASAR_BUILD_DYNLIB "Build one fat shared library. Requires BUILD_SHARED_LIBS to be turned OFF (default is OFF)" OFF) if(PHASAR_BUILD_DYNLIB AND BUILD_SHARED_LIBS) message(FATAL_ERROR "PHASAR_BUILD_DYNLIB is incompatible with BUILD_SHARED_LIBS") endif() -if (PHASAR_DEBUG_LIBDEPS) - if (NOT BUILD_SHARED_LIBS) +if(PHASAR_DEBUG_LIBDEPS) + if(NOT BUILD_SHARED_LIBS) set(BUILD_SHARED_LIBS ON) message("PHASAR_DEBUG_LIBDEPS only works for shared libraries, so set BUILD_SHARED_LIBS=ON") endif() - if (PHASAR_ENABLE_SANITIZERS) + + if(PHASAR_ENABLE_SANITIZERS) message(FATAL_ERROR "PHASAR_DEBUG_LIBDEPS is incompatible with ASAN (see https://clang.llvm.org/docs/AddressSanitizer.html#usage)") endif() -endif () +endif() option(PHASAR_ENABLE_PIC "Build Position-Independed Code" ON) -if (PHASAR_ENABLE_PIC) + +if(PHASAR_ENABLE_PIC) set(CMAKE_POSITION_INDEPENDENT_CODE ON) -endif (PHASAR_ENABLE_PIC) +endif(PHASAR_ENABLE_PIC) # PAMM set(PHASAR_ENABLE_PAMM "Off" CACHE STRING "Enable the performance measurement mechanism ('Off', 'Core' or 'Full', default is 'Off')") @@ -216,15 +219,15 @@ endif() # Logger option(PHASAR_ENABLE_DYNAMIC_LOG "Makes it possible to switch the logger on and off at runtime; otherwise, it is turned off at compile-time (default is ON)" ON) -if (PHASAR_ENABLE_DYNAMIC_LOG) +if(PHASAR_ENABLE_DYNAMIC_LOG) message(STATUS "Dynamic log enabled") set(DYNAMIC_LOG ON) else() message(STATUS "Dynamic log disabled") endif() -if (PHASAR_USE_CONAN) -elseif (NOT PHASAR_IN_TREE) +if(PHASAR_USE_CONAN) +elseif(NOT PHASAR_IN_TREE) # Export set set(PHASAR_DEPS_EXPORT_SET PhasarDepsExports) else() @@ -240,9 +243,9 @@ set(PHASAR_DEPS_INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/phasar/deps) include(CheckIncludeFileCXX) check_include_file_cxx(filesystem HAS_FILESYSTEM_HEADER) -if (NOT HAS_FILESYSTEM_HEADER) +if(NOT HAS_FILESYSTEM_HEADER) # If no file system exists, link a filesystem explicitly - if (LLVM_ENABLE_LIBCXX) + if(LLVM_ENABLE_LIBCXX) set(PHASAR_STD_FILESYSTEM c++fs) else() set(PHASAR_STD_FILESYSTEM stdc++fs) @@ -251,13 +254,14 @@ endif() # Config set(PHASAR_CUSTOM_CONFIG_INSTALL_DIR "" CACHE STRING "If set, customizes the directory, where configuration files for PhASAR are installed (default is ${CMAKE_INSTALL_PREFIX}/.phasar-config)") -if ("${PHASAR_CUSTOM_CONFIG_INSTALL_DIR}" STREQUAL "") + +if("${PHASAR_CUSTOM_CONFIG_INSTALL_DIR}" STREQUAL "") set(PHASAR_CONFIG_INSTALL_DIR ".phasar-config/") else() set(PHASAR_CONFIG_INSTALL_DIR "${PHASAR_CUSTOM_CONFIG_INSTALL_DIR}") endif() -### Adding external libraries +# ## Adding external libraries # Threads find_package(Threads) @@ -275,7 +279,7 @@ find_package(TBB QUIET) # needed by GCC set(PHASAR_USE_TBB ${TBB_FOUND}) # Coverage -if (CODE_COVERAGE) +if(CODE_COVERAGE) set(CODE_COVERAGE_SCRIPT "${CMAKE_CURRENT_BINARY_DIR}/code-coverage.cmake") file(DOWNLOAD "https://raw.githubusercontent.com/StableCoder/cmake-scripts/refs/tags/25.08/code-coverage.cmake" "${CODE_COVERAGE_SCRIPT}" EXPECTED_HASH SHA256=cad4dd2bdf944f77627687e0298debc8341bfdeffaf949937f319c7c4ff3fdaf @@ -284,7 +288,7 @@ if (CODE_COVERAGE) ) message(STATUS "Download code-coverage.cmake: ${CODE_COVERAGE_SCRIPT_DOWNLOAD_STATUS}") - if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") + if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") string(REGEX MATCH "^[0-9]+" COMPILER_VERSION_MAJOR "${CMAKE_CXX_COMPILER_VERSION}") message(STATUS "Clang major version: ${COMPILER_VERSION_MAJOR}") set(LLVM_TOOL_VERSION_SUFFIX "-${COMPILER_VERSION_MAJOR}") @@ -299,7 +303,8 @@ if (CODE_COVERAGE) include("${CODE_COVERAGE_SCRIPT}") find_program(cxxfilt "c++filt" QUIET) - if (cxxfilt) + + if(cxxfilt) set(DEMANGLER_OPTIONS LLVM_COV_HTML_OPTIONS "-Xdemangler=${cxxfilt}") endif() @@ -308,15 +313,15 @@ if (CODE_COVERAGE) endif() # Googletest -if (NOT PHASAR_IN_TREE) +if(NOT PHASAR_IN_TREE) if(PHASAR_BUILD_UNITTESTS AND NOT TARGET gtest) include(FetchContent) set(INSTALL_GTEST OFF) FetchContent_Declare( - googletest - GIT_REPOSITORY https://github.com/google/googletest.git - GIT_TAG v1.17.0 + googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG v1.17.0 ) FetchContent_MakeAvailable(googletest) endif() @@ -325,7 +330,7 @@ else() set(GTEST_INCLUDE_DIR "${LLVM_MAIN_SRC_DIR}/utils/unittest/googletest/include") endif() -option(USE_LLVM_FAT_LIB "Link against libLLVM.so instead of the individual LLVM libraries if possible (default is OFF; always on if BUILD_SHARED_LIBS is ON)" OFF) +option(USE_LLVM_FAT_LIB "Link against libLLVM.so instead of the individual LLVM libraries if possible (default is OFF; always on if BUILD_SHARED_LIBS is ON)" OFF) # LLVM set(PHASAR_LLVM_VERSION 16 CACHE STRING "The LLVM major-version that PhASAR should use") @@ -334,8 +339,8 @@ include(add_llvm) add_llvm() # Roaring - find_package(roaring QUIET CONFIG) + if(NOT TARGET roaring::roaring) set(ENABLE_ROARING_TESTS OFF) add_subdirectory(external/CRoaring) @@ -344,11 +349,12 @@ endif() # SVF option(PHASAR_USE_SVF "Use SVF for more options in alias analysis (default is OFF)" OFF) + if(PHASAR_USE_SVF) find_package(SVF REQUIRED CONFIG) message(STATUS "Found SVF ${SVF_VERSION}") - if (NOT PHASAR_USE_Z3) + if(NOT PHASAR_USE_Z3) message(WARNING "SVF requires Z3. Set PHASAR_USE_Z3=ON") set(PHASAR_USE_Z3 ON) endif() @@ -356,10 +362,10 @@ endif() # Z3 Solver if(PHASAR_IN_TREE) - set (PHASAR_USE_Z3 OFF) + set(PHASAR_USE_Z3 OFF) else() if(PHASAR_USE_Z3) - if (TARGET z3::libz3) + if(TARGET z3::libz3) # When including SVF, it also tries to find z3, but in addition to LLVM's search it already creates a target: z3::libz3. # Reuse it here: if(NOT TARGET z3) @@ -373,7 +379,7 @@ else() set(CMAKE_CXX_FLAGS "${SAFE_CMAKE_CXX_FLAGS}") if(Z3_FOUND) - if (NOT TARGET z3) + if(NOT TARGET z3) add_library(z3 IMPORTED SHARED) set_target_properties(z3 PROPERTIES IMPORTED_LOCATION ${Z3_LIBRARIES} @@ -387,19 +393,21 @@ endif() # Clang option(BUILD_PHASAR_CLANG "Build the phasar_clang library (default is OFF)" OFF) + if(BUILD_PHASAR_CLANG) add_clang() endif() # Set up clang-tidy to run during PhASAR's compilation to indicate code smells -if (PHASAR_ENABLE_CLANG_TIDY_DURING_BUILD) +if(PHASAR_ENABLE_CLANG_TIDY_DURING_BUILD) message(STATUS "Enabled clang-tidy during build") set(CMAKE_CXX_CLANG_TIDY clang-tidy; -header-filter=include/phasar.*h$; + # -warnings-as-errors=*; ) -endif () +endif() # Library Dependency Dirs if(NOT PHASAR_IN_TREE) @@ -409,14 +417,14 @@ endif() # Warnings option(PHASAR_ENABLE_WARNINGS "Enable warnings" ${PHASAR_BUILD_OPTIONAL_TARGETS_DEFAULT}) -if (PHASAR_ENABLE_WARNINGS) - if (MSVC) + +if(PHASAR_ENABLE_WARNINGS) + if(MSVC) string(APPEND CMAKE_CXX_FLAGS " /W4") else() string(APPEND CMAKE_CXX_FLAGS " -Wall -Wextra -Wno-unused-parameter -Werror=return-type") endif() -endif (PHASAR_ENABLE_WARNINGS) - +endif(PHASAR_ENABLE_WARNINGS) # Headers add_library(phasar_interface INTERFACE) @@ -428,7 +436,8 @@ target_sources(phasar_interface INTERFACE BASE_DIRS "${PHASAR_SRC_DIR}/include" "${PHASAR_BINARY_DIR}/include" FILES ${PHASAR_PUBLIC_HEADERS} "${PHASAR_BINARY_DIR}/include/phasar/Config/phasar-config.h" ) -if (TARGET TBB::tbb) + +if(TARGET TBB::tbb) target_link_libraries(phasar_interface INTERFACE TBB::tbb) # needed by GCC endif() @@ -446,18 +455,20 @@ endif() # Swift tests option(BUILD_SWIFT_TESTS "Builds the Swift tests (Swift compiler has to be installed manually beforehand!)" OFF) -if (BUILD_SWIFT_TESTS) + +if(BUILD_SWIFT_TESTS) set(CMAKE_Swift_FLAGS_RELEASE "-g") set(CMAKE_Swift_FLAGS_RELWITHDEBINFO "-g") enable_language(Swift) endif(BUILD_SWIFT_TESTS) # Add Phasar unittests and build all IR test code -if (PHASAR_BUILD_UNITTESTS) +if(PHASAR_BUILD_UNITTESTS) message("Phasar unittests") enable_testing() add_subdirectory(unittests) + if(NOT PHASAR_BUILD_IR) message(WARNING "Set PHASAR_BUILD_IR=ON, because PHASAR_BUILD_UNITTESTS is ON") set(PHASAR_BUILD_IR ON) @@ -465,7 +476,7 @@ if (PHASAR_BUILD_UNITTESTS) endif() # Build all IR test code -if (PHASAR_BUILD_IR) +if(PHASAR_BUILD_IR) message("Building IR test code") add_subdirectory(test) endif() @@ -475,13 +486,13 @@ set(LIBRARY_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}" CACHE PATH "Install dir of lib # Install targets of phasar-cli, other executables, and libraries are to be # found in the individual subdirectories of tools/ - if(NOT PHASAR_IN_TREE) install(TARGETS phasar_interface EXPORT PhasarExports FILE_SET HEADERS DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} ) - if (NOT PHASAR_USE_CONAN) + + if(NOT PHASAR_USE_CONAN) # Install the export-set containing all the phasar targets install(EXPORT PhasarExports FILE PhasarExports.cmake @@ -507,11 +518,11 @@ install(DIRECTORY utils/ DESTINATION bin FILES_MATCHING PATTERN "CodeGen" EXCLUDE # CodeGen does not contain files to install - PATTERN "conan" EXCLUDE # Don't install conan utils + PATTERN "conan" EXCLUDE # Don't install conan utils PATTERN "phasar-*" PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ - GROUP_EXECUTE GROUP_READ - WORLD_EXECUTE WORLD_READ + GROUP_EXECUTE GROUP_READ + WORLD_EXECUTE WORLD_READ ) # Install the Phasar config files into CMAKE_INSTALL_PREFIX/.phasar-config/ @@ -519,8 +530,8 @@ install(DIRECTORY config/ DESTINATION ${PHASAR_CONFIG_INSTALL_DIR} PATTERN "config/*" PERMISSIONS OWNER_WRITE OWNER_READ - GROUP_WRITE GROUP_READ - WORLD_READ + GROUP_WRITE GROUP_READ + WORLD_READ ) include(CMakePackageConfigHelpers) @@ -537,14 +548,14 @@ write_basic_package_version_file( COMPATIBILITY SameMajorVersion ) -### Install Config and ConfigVersion files +# ## Install Config and ConfigVersion files install( FILES "${CMAKE_CURRENT_BINARY_DIR}/phasarConfig.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/phasarConfigVersion.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/phasarConfigVersion.cmake" DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/phasar" ) -if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR AND NOT TARGET uninstall) +if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR AND NOT TARGET uninstall) configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" @@ -562,22 +573,23 @@ endif() # the so libs must be added manually to the linker search path and the linker # config must be updated as follows: # -# $ export LD_LIBRARY_PATH=/lib:/usr/lib:/usr/local/lib:/home/philipp/Schreibtisch/tmp/lib -# $ sudo ldconfig +# $ export LD_LIBRARY_PATH=/lib:/usr/lib:/usr/local/lib:/home/philipp/Schreibtisch/tmp/lib +# $ sudo ldconfig # # Or even better: just link statically when trying to package Phasar <- this is no longer possible # Settings for building various packages using Cpack -# How to pack using the following settings? -# $ mkdir build -# $ cd build -# $ cmake -DBUILD_SHARED_LIBS=ON -DCMAKE_INSTALL_PREFIX=/usr/local .. -# $ cpack .. -# $ dpkg -i ./.deb or better: apt-get install ./.deb +# How to pack using the following settings? +# $ mkdir build +# $ cd build +# $ cmake -DBUILD_SHARED_LIBS=ON -DCMAKE_INSTALL_PREFIX=/usr/local .. +# $ cpack .. +# $ dpkg -i ./.deb or better: apt-get install ./.deb set(MAJOR_VERSION 1) set(MINOR_VERSION 0) set(PATCH_VERSION 0) -if (NOT PHASAR_IN_TREE) + +if(NOT PHASAR_IN_TREE) if(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake") include(InstallRequiredSystemLibraries) set(CPACK_SET_DESTDIR "on") @@ -593,6 +605,7 @@ if (NOT PHASAR_IN_TREE) set(CPACK_PACKAGE_VERSION_PATCH "${PATCH_VERSION}") set(CPACK_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}_${MAJOR_VERSION}.${MINOR_VERSION}.${CPACK_PACKAGE_VERSION_PATCH}") set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}_${MAJOR_VERSION}.${MINOR_VERSION}.${CPACK_PACKAGE_VERSION_PATCH}") + # package dependencies can be set-up here # better use autogenerated dependency information set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON) diff --git a/include/phasar/DataFlow/IfdsIde/Solver/DFISolverResults.h b/include/phasar/DataFlow/IfdsIde/Solver/DFISolverResults.h index 63a59080f3..48221ead42 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/DFISolverResults.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/DFISolverResults.h @@ -188,8 +188,8 @@ class [[gsl::Pointer]] DFISolverResults friend detail::DFISolverResultsBase, N, D>; public: - explicit DFISolverResults(const detail::DFIResultsData *Data - PSR_LIFETIME_CAPTURE_BY(this)) noexcept + explicit DFISolverResults( + const detail::DFIResultsData *Data PSR_LIFETIMEBOUND) noexcept : Data(Data) { assert(Data != nullptr); } diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h index 1f651c003e..5e6d358f75 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h @@ -273,8 +273,12 @@ class IDEInstInteractionAnalysisT // Handle indirect taints, i. e., propagate values that depend on branch // conditions whose operands are tainted. if constexpr (EnableIndirectTaints) { +#if LLVM_VERSION_MAJOR >= 23 + if (const auto *Br = llvm::dyn_cast(Curr)) { +#else if (const auto *Br = llvm::dyn_cast(Curr); Br && Br->isConditional()) { +#endif // If the branch is conditional and its condition is tainted, then we // need to propagates the instructions that are depending on this // branch, too. diff --git a/include/phasar/PhasarLLVM/DataFlow/MonoIfds/AliasCache.h b/include/phasar/PhasarLLVM/DataFlow/MonoIfds/AliasCache.h index 70fa8b49b3..e53277c8b2 100644 --- a/include/phasar/PhasarLLVM/DataFlow/MonoIfds/AliasCache.h +++ b/include/phasar/PhasarLLVM/DataFlow/MonoIfds/AliasCache.h @@ -34,12 +34,12 @@ class AliasCache { // Passed AI should already be FilteredAliasSet or similar explicit AliasCache( - LLVMAliasIteratorRef AI PSR_LIFETIME_CAPTURE_BY(this), + LLVMAliasIteratorRef AI PSR_LIFETIMEBOUND, llvm::function_ref SkipSeedsCallBack - PSR_LIFETIME_CAPTURE_BY(this), + PSR_LIFETIMEBOUND, const UsedGlobalsHolder::GlobalSet - *PermittedGlobals PSR_LIFETIME_CAPTURE_BY(this), - std::pmr::memory_resource *MRes PSR_LIFETIME_CAPTURE_BY(this)) + *PermittedGlobals PSR_LIFETIMEBOUND, + std::pmr::memory_resource *MRes PSR_LIFETIMEBOUND) : AI(AI), SkipSeedsCallBack(SkipSeedsCallBack), PermittedGlobals(&assertNotNull(PermittedGlobals)), Cache(&assertNotNull(MRes)) {} diff --git a/include/phasar/PhasarLLVM/DataFlow/PathSensitivity/LLVMPathConstraints.h b/include/phasar/PhasarLLVM/DataFlow/PathSensitivity/LLVMPathConstraints.h index 887f4f54bc..247fd05401 100644 --- a/include/phasar/PhasarLLVM/DataFlow/PathSensitivity/LLVMPathConstraints.h +++ b/include/phasar/PhasarLLVM/DataFlow/PathSensitivity/LLVMPathConstraints.h @@ -25,7 +25,11 @@ class AllocaInst; class LoadInst; class GetElementPtrInst; class PHINode; +#if LLVM_VERSION_MAJOR >= 23 +class CondBrInst; +#else class BranchInst; +#endif class CmpInst; class BinaryOperator; class CallBase; @@ -72,8 +76,13 @@ class LLVMPathConstraints { [[nodiscard]] ConstraintAndVariables handlePhiInstruction(const llvm::PHINode *Phi); - [[nodiscard]] ConstraintAndVariables - handleCondBrInst(const llvm::BranchInst *Br, const llvm::Instruction *Succ); + [[nodiscard]] ConstraintAndVariables handleCondBrInst( +#if LLVM_VERSION_MAJOR >= 23 + const llvm::CondBrInst *Br, +#else + const llvm::BranchInst *Br, +#endif + const llvm::Instruction *Succ); [[nodiscard]] ConstraintAndVariables handleCmpInst(const llvm::CmpInst *Cmp); diff --git a/include/phasar/PhasarLLVM/Utils/LLVMShorthands.h b/include/phasar/PhasarLLVM/Utils/LLVMShorthands.h index 453c0c2b00..ed68a12fd3 100644 --- a/include/phasar/PhasarLLVM/Utils/LLVMShorthands.h +++ b/include/phasar/PhasarLLVM/Utils/LLVMShorthands.h @@ -31,6 +31,7 @@ #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/GlobalObject.h" #include "llvm/IR/Instruction.h" +#include "llvm/IR/Instructions.h" #include "llvm/IR/Type.h" #include "llvm/Support/Casting.h" @@ -48,7 +49,12 @@ class ModuleSlotTracker; class Argument; class Instruction; class StoreInst; +#if LLVM_VERSION_MAJOR >= 23 +class CondBrInst; +class UncondBrInst; +#else class BranchInst; +#endif class Module; class CallInst; class AllocaInst; @@ -278,6 +284,20 @@ std::size_t computeModuleHash(const llvm::Module *M); */ [[nodiscard]] bool isGuardVariable(const llvm::Value *V); +#if LLVM_VERSION_MAJOR >= 23 +[[nodiscard]] constexpr bool +isStaticVariableLazyInitializationBranch(const llvm::UncondBrInst * /*Inst*/) { + return false; +} + +/** + * @brief True, iff V is the compiler-generated branch that leads to the lazy + * initialization of a function-local static variable. + */ +[[nodiscard]] bool +isStaticVariableLazyInitializationBranch(const llvm::CondBrInst *Inst); + +#else /** * @brief True, iff V is the compiler-generated branch that leads to the lazy * initialization of a function-local static variable. @@ -285,6 +305,8 @@ std::size_t computeModuleHash(const llvm::Module *M); [[nodiscard]] bool isStaticVariableLazyInitializationBranch(const llvm::BranchInst *Inst); +#endif + [[nodiscard]] inline bool definitelyContainsNoPointerFast(const llvm::Type *Ty) noexcept { return Ty->isIntOrIntVectorTy() || Ty->isFloatingPointTy() || @@ -475,6 +497,32 @@ getVaListTagOrNull(const llvm::Function &Fun); /// - \c Indices[1+] navigate recursively through ConstantAggregate. [[nodiscard]] const llvm::Function * walkConstInitPath(const llvm::Constant *Init, llvm::ArrayRef Indices); + +[[nodiscard]] inline bool +isUnconditionalBranch(const llvm::Instruction *Inst) noexcept { +#if LLVM_VERSION_MAJOR >= 23 + return llvm::isa_and_present(Inst); +#else + if (const auto *Br = llvm::dyn_cast_if_present(Inst)) { + return !Br->isConditional(); + } + return false; +#endif +} + +[[nodiscard]] inline const llvm::Value * +getBranchConditionOrNull(const llvm::Instruction *Inst) noexcept { +#if LLVM_VERSION_MAJOR >= 23 + if (const auto *CBr = llvm::dyn_cast_if_present(Inst)) { + return CBr->getCondition(); + } +#else + if (const auto *Br = llvm::dyn_cast_if_present(Inst)) { + return Br->getCondition(); + } +#endif + return nullptr; +} } // namespace psr #endif diff --git a/lib/DataFlow/PathSensitivity/CMakeLists.txt b/lib/DataFlow/PathSensitivity/CMakeLists.txt index 1c17410d19..3c6d28447d 100644 --- a/lib/DataFlow/PathSensitivity/CMakeLists.txt +++ b/lib/DataFlow/PathSensitivity/CMakeLists.txt @@ -5,6 +5,7 @@ add_phasar_library(phasar_dataflow_pathsensitivity LINK_PRIVATE nlohmann_json::nlohmann_json + z3 LLVM_LINK_COMPONENTS Support diff --git a/lib/PhasarLLVM/ControlFlow/LLVMBasedBackwardCFG.cpp b/lib/PhasarLLVM/ControlFlow/LLVMBasedBackwardCFG.cpp index 5e042a41d2..d9a8dbca31 100644 --- a/lib/PhasarLLVM/ControlFlow/LLVMBasedBackwardCFG.cpp +++ b/lib/PhasarLLVM/ControlFlow/LLVMBasedBackwardCFG.cpp @@ -12,6 +12,7 @@ #include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" #include "llvm/IR/Instructions.h" +#include "llvm/Support/Casting.h" namespace psr { @@ -47,7 +48,7 @@ auto LLVMBasedBackwardCFG::getPredsOfImpl(n_t Inst) const return this->base_t::getSuccsOfImpl(Inst); } -auto LLVMBasedBackwardCFG ::getSuccsOfImpl(n_t Inst) const +auto LLVMBasedBackwardCFG::getSuccsOfImpl(n_t Inst) const -> llvm::SmallVector { if (BackwardRetToFunction.count(Inst)) { return {}; @@ -63,7 +64,7 @@ auto LLVMBasedBackwardCFG ::getSuccsOfImpl(n_t Inst) const return Ret; } -auto LLVMBasedBackwardCFG ::getAllControlFlowEdgesImpl(f_t Fun) const +auto LLVMBasedBackwardCFG::getAllControlFlowEdgesImpl(f_t Fun) const -> std::vector> { std::vector> Edges; @@ -90,37 +91,49 @@ auto LLVMBasedBackwardCFG ::getAllControlFlowEdgesImpl(f_t Fun) const return Edges; } -auto LLVMBasedBackwardCFG ::getStartPointsOfImpl(f_t Fun) const +auto LLVMBasedBackwardCFG::getStartPointsOfImpl(f_t Fun) const -> llvm::SmallVector { return this->base_t::getExitPointsOfImpl(Fun); } -auto LLVMBasedBackwardCFG ::getExitPointsOfImpl(f_t Fun) const +auto LLVMBasedBackwardCFG::getExitPointsOfImpl(f_t Fun) const -> llvm::SmallVector { return BackwardRets.empty() ? this->base_t::getStartPointsOfImpl(Fun) : llvm::SmallVector{BackwardRets.lookup(Fun)}; } -bool LLVMBasedBackwardCFG ::isExitInstImpl(n_t Inst) const noexcept { +bool LLVMBasedBackwardCFG::isExitInstImpl(n_t Inst) const noexcept { return BackwardRetToFunction.empty() ? this->base_t::isStartPointImpl(Inst) : BackwardRetToFunction.count(Inst); } -bool LLVMBasedBackwardCFG ::isStartPointImpl(n_t Inst) const noexcept { +bool LLVMBasedBackwardCFG::isStartPointImpl(n_t Inst) const noexcept { return this->base_t::isExitInstImpl(Inst); } -bool LLVMBasedBackwardCFG ::isFallThroughSuccessorImpl( +bool LLVMBasedBackwardCFG::isFallThroughSuccessorImpl( n_t /*Inst*/, n_t /*Succ*/) const noexcept { assert(false && "FallThrough not valid in LLVM IR"); return false; } -bool LLVMBasedBackwardCFG ::isBranchTargetImpl(n_t Inst, - n_t Succ) const noexcept { - if (const auto *B = llvm::dyn_cast(Succ)) { +bool LLVMBasedBackwardCFG::isBranchTargetImpl(n_t Inst, + n_t Succ) const noexcept { +#if LLVM_VERSION_MAJOR >= 23 + if (const auto *Br = llvm::dyn_cast(Succ)) { + return Inst == &Br->getSuccessor()->front(); + } +#endif + + if (const auto *B = llvm::dyn_cast< +#if LLVM_VERSION_MAJOR >= 23 + llvm::CondBrInst +#else + llvm::BranchInst +#endif + >(Succ)) { for (const auto *BB : B->successors()) { - if (Inst == &(BB->front())) { + if (Inst == &BB->front()) { return true; } } diff --git a/lib/PhasarLLVM/ControlFlow/LLVMBasedCFG.cpp b/lib/PhasarLLVM/ControlFlow/LLVMBasedCFG.cpp index daa3806773..99a19757db 100644 --- a/lib/PhasarLLVM/ControlFlow/LLVMBasedCFG.cpp +++ b/lib/PhasarLLVM/ControlFlow/LLVMBasedCFG.cpp @@ -91,7 +91,13 @@ auto detail::LLVMBasedCFGImpl::getSuccsOfImpl(n_t I) const } #endif - if (const auto *Branch = llvm::dyn_cast(I); + if (const auto *Branch = llvm::dyn_cast< +#if LLVM_VERSION_MAJOR >= 23 + llvm::CondBrInst +#else + llvm::BranchInst +#endif + >(I); Branch && isStaticVariableLazyInitializationBranch(Branch)) { // Skip the "already initialized" case, such that the analysis is always // aware of the initialized value. @@ -214,12 +220,21 @@ template bool detail::LLVMBasedCFGImpl::isFallThroughSuccessorImpl( n_t Inst, n_t Succ) const noexcept { // assert(false && "FallThrough not valid in LLVM IR"); +#if LLVM_VERSION_MAJOR >= 23 + if (const auto *UB = llvm::dyn_cast(Inst)) { + return &UB->getSuccessor()->front() == Succ; + } + if (const auto *CB = llvm::dyn_cast(Inst)) { + return &CB->getSuccessor(1)->front() == Succ; + } +#else if (const auto *B = llvm::dyn_cast(Inst)) { if (B->isConditional()) { return &B->getSuccessor(1)->front() == Succ; } return &B->getSuccessor(0)->front() == Succ; } +#endif return false; } diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/CFLFieldSensIFDSProblem.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/CFLFieldSensIFDSProblem.cpp index 1e172c0293..e5f0855454 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/CFLFieldSensIFDSProblem.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/CFLFieldSensIFDSProblem.cpp @@ -811,8 +811,8 @@ getResultEF(llvm::PointerIntPair assert(Ptr.getPointer() == Ptr.getOpaqueValue() && "Zero-tag does not pollute the alignment bits"); return CFLFieldSensEdgeFunction{ - static_cast( - Ptr.getOpaqueValue())}; + static_cast(Ptr.getOpaqueValue()), + }; case AllBottomId: GetResultEFBot++; return AllBottom{}; diff --git a/lib/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt b/lib/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt index 877cd983a7..6d9444f1e6 100644 --- a/lib/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt +++ b/lib/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt @@ -19,7 +19,7 @@ endif() if(PHASAR_USE_Z3) - set(ADDITIONAL_LINK_LIBS ${Z3_LIBRARIES}) + set(ADDITIONAL_LINK_LIBS z3) endif() add_phasar_library(phasar_llvm_pathsensitivity diff --git a/lib/PhasarLLVM/DataFlow/PathSensitivity/LLVMPathConstraints.cpp b/lib/PhasarLLVM/DataFlow/PathSensitivity/LLVMPathConstraints.cpp index 233f73f037..23188aa07a 100644 --- a/lib/PhasarLLVM/DataFlow/PathSensitivity/LLVMPathConstraints.cpp +++ b/lib/PhasarLLVM/DataFlow/PathSensitivity/LLVMPathConstraints.cpp @@ -22,10 +22,17 @@ auto LLVMPathConstraints::internalGetConstraintAndVariablesFromEdge( const llvm::Instruction *From, const llvm::Instruction *To) -> std::optional { LLVMBasedCFG CF(IgnoreDebugInstructions); +#if LLVM_VERSION_MAJOR >= 23 + const auto *BI = llvm::dyn_cast(From); + if (!BI) { + return std::nullopt; + } +#else const auto *BI = llvm::dyn_cast(From); if (!BI || !BI->isConditional()) { return std::nullopt; } +#endif #if LLVM_VERSION_MAJOR <= 18 if (IgnoreDebugInstructions) { @@ -158,18 +165,21 @@ auto LLVMPathConstraints::handlePhiInstruction(const llvm::PHINode *Phi) return Z3Expr.try_emplace(Phi, CAV).first->second; } -auto LLVMPathConstraints::handleCondBrInst(const llvm::BranchInst *Br, - const llvm::Instruction *Succ) - -> ConstraintAndVariables { +auto LLVMPathConstraints::handleCondBrInst( +#if LLVM_VERSION_MAJOR >= 23 + const llvm::CondBrInst *Br, +#else + const llvm::BranchInst *Br, +#endif + const llvm::Instruction *Succ) -> ConstraintAndVariables { // llvm::outs() << "handleCondBrInst\n"; auto Search = Z3Expr.find(Br); if (Search != Z3Expr.end()) { return Search->second; } const auto *Cond = Br->getCondition(); - // yes, the true label is indeed operand 2 - const auto *IfTrue = llvm::dyn_cast(Br->getOperand(2)); - const auto *IfFalse = llvm::dyn_cast(Br->getOperand(1)); + const auto *IfTrue = Br->getSuccessor(0); + const auto *IfFalse = Br->getSuccessor(1); auto GetFirstInst = [IgnoreDebugInstructions{IgnoreDebugInstructions}]( const llvm::BasicBlock *BB) { @@ -178,6 +188,8 @@ auto LLVMPathConstraints::handleCondBrInst(const llvm::BranchInst *Br, if (IgnoreDebugInstructions && llvm::isa(Ret)) { Ret = Ret->getNextNonDebugInstruction(false); } +#else + (void)IgnoreDebugInstructions; #endif return Ret; }; diff --git a/lib/PhasarLLVM/Passes/GeneralStatisticsAnalysis.cpp b/lib/PhasarLLVM/Passes/GeneralStatisticsAnalysis.cpp index 614ecf62e8..66de315b42 100644 --- a/lib/PhasarLLVM/Passes/GeneralStatisticsAnalysis.cpp +++ b/lib/PhasarLLVM/Passes/GeneralStatisticsAnalysis.cpp @@ -112,7 +112,11 @@ GeneralStatisticsAnalysis::runOnModule(const llvm::Module &M) { if (llvm::isa(I)) { ++Stats.PhiNodes; } +#if LLVM_VERSION_MAJOR >= 23 + if (llvm::isa(I)) { +#else if (llvm::isa(I)) { +#endif ++Stats.Branches; } if (llvm::isa(I)) { diff --git a/lib/PhasarLLVM/Utils/LLVMShorthands.cpp b/lib/PhasarLLVM/Utils/LLVMShorthands.cpp index 8f39b45ec2..7c6b7b2607 100644 --- a/lib/PhasarLLVM/Utils/LLVMShorthands.cpp +++ b/lib/PhasarLLVM/Utils/LLVMShorthands.cpp @@ -586,12 +586,18 @@ bool psr::isAddressTakenArg(const llvm::Argument *Arg) noexcept { } bool psr::isStaticVariableLazyInitializationBranch( - const llvm::BranchInst *Inst) { - if (Inst->isUnconditional()) { +#if LLVM_VERSION_MAJOR >= 23 + const llvm::CondBrInst *Inst +#else + const llvm::BranchInst *Inst +#endif +) { + if (isUnconditionalBranch(Inst)) { return false; } - auto *Condition = Inst->getCondition(); + auto *Condition = getBranchConditionOrNull(Inst); + assert(Condition != nullptr); if (auto *Cmp = llvm::dyn_cast(Condition); Cmp && llvm::ICmpInst::isEquality(Cmp->getPredicate())) { diff --git a/test/llvm_test_code/lit.cfg.py b/test/llvm_test_code/lit.cfg.py index 3402097021..d696ccdbc8 100644 --- a/test/llvm_test_code/lit.cfg.py +++ b/test/llvm_test_code/lit.cfg.py @@ -2,7 +2,7 @@ import os config.name = "phasar-cli" -config.test_format = lit.formats.ShTest(True) +config.test_format = lit.formats.ShTest() config.suffixes = ['.c', '.cpp'] config.test_source_root = os.path.dirname(__file__) diff --git a/tools/hello-modules-tool/hello_modules.cpp b/tools/hello-modules-tool/hello_modules.cpp index 4de805db85..49e0f4918c 100644 --- a/tools/hello-modules-tool/hello_modules.cpp +++ b/tools/hello-modules-tool/hello_modules.cpp @@ -46,7 +46,7 @@ int main(int Argc, const char **Argv) { // IFDS template parametrization test llvm::outs() << "Testing IFDS:\n"; auto L = createAnalysisProblem(HA, EntryPoints); - IFDSSolver S(L, &HA.getICFG()); + IFDSSolver S(&L, &HA.getICFG()); auto IFDSResults = S.solve(); IFDSResults.dumpResults(HA.getICFG()); From cebdde1da4d939fe9f52f9a4910d07d8d5262458 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Mon, 2 Nov 2026 19:07:49 +0100 Subject: [PATCH 3/4] Update readme --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index ea2b1673f0..b182fd3715 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,9 @@ PhASAR supports C++20 modules as an experimental feature. ### LLVM Version PhASAR supports LLVM versions **between LLVM-16 and LLVM-22.1**, using LLVM-16 by default. + +**Support for LLVM-23 is experimental.** + We actively test PhASAR with LLVM-16 and LLVM-22.1, so if something does not work, try these versions instead. Specify the `PHASAR_LLVM_VERSION` cmake variable to change the LLVM version to use. From 84bd35d2057ed1784c106728d4c2cb87e2c54058 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Sat, 7 Nov 2026 13:22:01 +0100 Subject: [PATCH 4/4] pre-commit --- include/phasar/Utils/TableWrappers.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/include/phasar/Utils/TableWrappers.h b/include/phasar/Utils/TableWrappers.h index 0a73f39ca2..7dad6f9f43 100644 --- a/include/phasar/Utils/TableWrappers.h +++ b/include/phasar/Utils/TableWrappers.h @@ -458,9 +458,7 @@ template class DenseTable1d { #if LLVM_VERSION_MAJOR >= 23 /// Erases all cells for which P(Cell) returns true. - template void eraseIf(Pred P) { - Map.remove_if(std::move(P)); - } + template void eraseIf(Pred P) { Map.remove_if(std::move(P)); } #endif DenseTable1d() noexcept = default;