Skip to content

Commit 2b59751

Browse files
authored
Merge branch 'development' into f-ImprovePAMM
2 parents 77c0172 + 8a671bb commit 2b59751

54 files changed

Lines changed: 4761 additions & 430 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,6 @@
55
[submodule "external/json-schema-validator"]
66
path = external/json-schema-validator
77
url = https://github.com/pboettch/json-schema-validator.git
8+
[submodule "external/CRoaring"]
9+
path = external/CRoaring
10+
url = https://github.com/fabianbs96/CRoaring.git

CMakeLists.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,9 @@ set(RELEASE_CONFIGURATIONS RELWITHDEBINFO RELEASE CACHE INTERNAL "" FORCE)
7474

7575
string(APPEND CMAKE_CXX_FLAGS " -MP -fstack-protector-strong -ffunction-sections -fdata-sections -pipe")
7676
string(APPEND CMAKE_CXX_FLAGS_DEBUG " -fno-omit-frame-pointer")
77+
string(APPEND CMAKE_C_FLAGS_DEBUG " -fno-omit-frame-pointer")
7778
string(APPEND CMAKE_CXX_FLAGS_RELWITHDEBINFO " -fno-omit-frame-pointer")
79+
string(APPEND CMAKE_C_FLAGS_RELWITHDEBINFO " -fno-omit-frame-pointer")
7880
string(APPEND CMAKE_CXX_FLAGS_RELEASE "")
7981

8082
option(CMAKE_VISIBILITY_INLINES_HIDDEN "Hide inlined functions from the DSO table (default ON)" ON)
@@ -123,6 +125,7 @@ if (NOT "${PHASAR_TARGET_ARCH_INTERNAL}" STREQUAL "")
123125
if (MARCH_SUPPORTED)
124126
message(STATUS "Target architecture '${PHASAR_TARGET_ARCH_INTERNAL}' enabled")
125127
string(APPEND CMAKE_CXX_FLAGS_RELEASE " -march=${PHASAR_TARGET_ARCH_INTERNAL}")
128+
string(APPEND CMAKE_C_FLAGS_RELEASE " -march=${PHASAR_TARGET_ARCH_INTERNAL}")
126129
else()
127130
message(WARNING "Target architecture '${PHASAR_TARGET_ARCH_INTERNAL}' not supported. Fallback to generic build")
128131
endif()
@@ -327,6 +330,15 @@ set(PHASAR_LLVM_VERSION 16 CACHE STRING "The LLVM major-version that PhASAR shou
327330
include(add_llvm)
328331
add_llvm()
329332

333+
# Roaring
334+
335+
find_package(roaring QUIET CONFIG)
336+
if(NOT TARGET roaring::roaring)
337+
set(ENABLE_ROARING_TESTS OFF)
338+
add_subdirectory(external/CRoaring)
339+
set(PHASAR_PROVIDE_CROARING ON)
340+
endif()
341+
330342
# SVF
331343
option(PHASAR_USE_SVF "Use SVF for more options in alias analysis (default is OFF)" OFF)
332344
if(PHASAR_USE_SVF)

Config.cmake.in

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@ set(PHASAR_USE_LLVM_FAT_LIB @USE_LLVM_FAT_LIB@)
1515
set(PHASAR_BUILD_DYNLIB @PHASAR_BUILD_DYNLIB@)
1616
set(PHASAR_USE_Z3 @PHASAR_USE_Z3@)
1717
set(PHASAR_BUILD_MODULES @PHASAR_BUILD_MODULES@)
18+
set(PHASAR_PROVIDE_CROARING @PHASAR_PROVIDE_CROARING@)
19+
20+
if (PHASAR_PROVIDE_CROARING)
21+
# TODO: Is that path portable?
22+
include("${CMAKE_CURRENT_LIST_DIR}/../roaring/roaring-targets.cmake")
23+
else()
24+
find_dependency(roaring REQUIRED CONFIG)
25+
endif()
1826

1927
if (PHASAR_USE_Z3)
2028
find_dependency(Z3 REQUIRED)

examples/how-to/03-create-alias-info/CMakeLists.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,14 @@ find_package(phasar REQUIRED CONFIG)
99
add_executable(create-alias-info main.cpp)
1010
target_link_libraries(create-alias-info PRIVATE phasar::phasar)
1111

12+
add_executable(create-alias-info-andersen andersen.cpp)
13+
target_link_libraries(create-alias-info-andersen PRIVATE phasar::phasar)
14+
1215
if (TARGET run_sample_programs)
1316
add_custom_target(run_create_alias_info
14-
DEPENDS create-alias-info LLFileGeneration
17+
DEPENDS create-alias-info create-alias-info-andersen LLFileGeneration
1518
COMMAND $<TARGET_FILE:create-alias-info> "${CMAKE_CURRENT_BINARY_DIR}/../llvm-hello-world/target/pointers_cpp_dbg.ll"
19+
COMMAND $<TARGET_FILE:create-alias-info-andersen> "${CMAKE_CURRENT_BINARY_DIR}/../llvm-hello-world/target/pointers_cpp_dbg.ll"
1620
)
1721

1822
add_dependencies(run_sample_programs run_create_alias_info)
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
#include "phasar/PhasarLLVM/ControlFlow.h"
2+
#include "phasar/PhasarLLVM/DB.h"
3+
#include "phasar/PhasarLLVM/Pointer.h"
4+
#include "phasar/PhasarLLVM/Utils.h"
5+
6+
#include "llvm/IR/InstIterator.h"
7+
8+
#include <cassert>
9+
10+
int main(int Argc, char *Argv[]) {
11+
using namespace std::string_literals;
12+
if (Argc < 2) {
13+
llvm::errs() << "USAGE: create-alias-info-andersen <LLVM-IR file>\n";
14+
return 1;
15+
}
16+
17+
// Load the IR
18+
psr::LLVMProjectIRDB IRDB(Argv[1]);
19+
if (!IRDB) {
20+
return 1;
21+
}
22+
23+
// Mapping the entry-points (here, just the main function) to LLVM IR:
24+
auto Entrypoints = psr::getEntryFunctions(IRDB, {"main"s});
25+
26+
// Computing the Andersen-stale alias information.
27+
auto Aliases = psr::computeAndersenOTF(IRDB, Entrypoints);
28+
29+
// The Andersen alias result is compatible with the LLVMAliasIteratorRef
30+
// interface.
31+
psr::LLVMAliasIteratorRef AIt = &Aliases;
32+
33+
const auto *MainF = IRDB.getFunctionDefinition("main");
34+
if (!MainF) {
35+
llvm::errs() << "Required function 'main' not found\n";
36+
return 1;
37+
}
38+
39+
// Manually printing the alias sets:
40+
41+
for (const auto &Inst : llvm::instructions(MainF)) {
42+
if (!Inst.getType()->isPointerTy()) {
43+
// For aliasing, we only care about pointers...
44+
continue;
45+
}
46+
47+
llvm::outs() << "For pointer " << psr::llvmIRToString(&Inst) << ":\n";
48+
49+
// Iterate over the aliases of the result of the instruction Inst (first
50+
// parameter) at the program location determined by Inst (second parameter).
51+
//
52+
// Implementations may ignore the second parameter.
53+
Aliases.forallAliasesOf(&Inst, &Inst, [&](const llvm::Value *Alias) {
54+
llvm::outs() << "> aliasing " << psr::llvmIRToShortString(Alias) << '\n';
55+
56+
// You can also check, whether two pointers are (potentially) aliasing:
57+
assert(Aliases.mayAlias(&Inst, Alias, &Inst));
58+
});
59+
60+
llvm::outs() << '\n';
61+
}
62+
}

examples/how-to/03-create-alias-info/main.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ int main(int Argc, char *Argv[]) {
3030
// it.
3131
psr::LLVMAliasInfoRef ASRef = &AS;
3232

33+
// For APIs that don't need the expressiveness of the LLVMAliasInfoRef, PhASAR
34+
// provides a simpler interface: LLVMAliasIteratorRef. It only provides a
35+
// function forallAliasesOf() that allows invoking a callback for all aliases
36+
// of a pointer; for most applications, this is sufficient.
37+
// Similar to LLVMAliasInfoRef, it is a non-owning reference.
38+
psr::LLVMAliasIteratorRef AIt = &AS;
39+
3340
// You can print and load alias information from/to JSON:
3441
AS.printAsJson();
3542

external/CRoaring

Submodule CRoaring added at 2e8395f

include/phasar/PhasarLLVM/ControlFlow/Resolver/Resolver.h

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@
1818
#define PHASAR_PHASARLLVM_CONTROLFLOW_RESOLVER_RESOLVER_H_
1919

2020
#include "phasar/PhasarLLVM/Pointer/LLVMAliasInfo.h"
21+
#include "phasar/PhasarLLVM/Utils/VirtualCallUtils.h"
2122
#include "phasar/Utils/MaybeUniquePtr.h"
2223

2324
#include "llvm/ADT/DenseSet.h"
2425
#include "llvm/ADT/SmallVector.h"
25-
#include "llvm/IR/DerivedTypes.h"
2626

2727
#include <memory>
2828
#include <optional>
@@ -41,15 +41,6 @@ class LLVMVFTableProvider;
4141
class DIBasedTypeHierarchy;
4242
enum class CallGraphAnalysisType;
4343

44-
/// Assuming that `CallSite` is a virtual call through a vtable, retrieves the
45-
/// index in the vtable of the virtual function called.
46-
[[nodiscard]] std::optional<unsigned>
47-
getVFTIndex(const llvm::CallBase *CallSite);
48-
49-
/// Similar to getVFTIndex(), but also returns a pointer to the vtable
50-
[[nodiscard]] std::optional<std::pair<const llvm::Value *, uint64_t>>
51-
getVFTIndexAndVT(const llvm::CallBase *CallSite);
52-
5344
/// Assuming that `CallSite` is a call to a non-static member function,
5445
/// retrieves the type of the receiver. Returns nullptr, if the receiver-type
5546
/// could not be extracted
@@ -64,12 +55,6 @@ getReceiverType(const llvm::CallBase *CallSite);
6455

6556
[[nodiscard]] std::string getReceiverTypeName(const llvm::CallBase *CallSite);
6657

67-
/// Checks whether the signature of `DestFun` matches the required withature of
68-
/// `CallSite`, such that `DestFun` qualifies as callee-candidate, if `CallSite`
69-
/// is an indirect/virtual call.
70-
[[nodiscard]] bool isConsistentCall(const llvm::CallBase *CallSite,
71-
const llvm::Function *DestFun);
72-
7358
[[nodiscard]] bool isVirtualCall(const llvm::Instruction *Inst,
7459
const LLVMVFTableProvider &VTP);
7560

include/phasar/PhasarLLVM/Pointer.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,16 @@
1212

1313
#include "phasar/Config/phasar-config.h" // for PHASAR_USE_SVF
1414
#include "phasar/PhasarLLVM/Pointer/AliasAnalysisView.h"
15+
#include "phasar/PhasarLLVM/Pointer/AndersenOTFAA.h"
1516
#include "phasar/PhasarLLVM/Pointer/FilteredLLVMAliasSet.h"
1617
#include "phasar/PhasarLLVM/Pointer/LLVMAliasInfo.h"
1718
#include "phasar/PhasarLLVM/Pointer/LLVMAliasSet.h"
19+
#include "phasar/PhasarLLVM/Pointer/LLVMGlobalInitCache.h"
20+
#include "phasar/PhasarLLVM/Pointer/LLVMPointsToInfo.h"
1821
#include "phasar/PhasarLLVM/Pointer/LLVMPointsToUtils.h"
22+
#include "phasar/PhasarLLVM/Pointer/LLVMUnionFindAA.h"
23+
#include "phasar/PhasarLLVM/Pointer/LLVMUnionFindAliasSet.h"
24+
#include "phasar/PhasarLLVM/Pointer/MemSSAUtils.h"
1925

2026
#ifdef PHASAR_USE_SVF
2127
#include "phasar/PhasarLLVM/Pointer/SVF/SVFPointsToSet.h"
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
#pragma once
2+
3+
/******************************************************************************
4+
* Copyright (c) 2026 Fabian Schiebel.
5+
* All rights reserved. This program and the accompanying materials are made
6+
* available under the terms of LICENSE.txt.
7+
*
8+
* Contributors:
9+
* Fabian Schiebel and others
10+
*****************************************************************************/
11+
12+
#include "phasar/PhasarLLVM/ControlFlow/LLVMBasedCallGraph.h"
13+
#include "phasar/PhasarLLVM/Pointer/LLVMPointerAssignmentGraph.h"
14+
#include "phasar/PhasarLLVM/Pointer/LLVMUnionFindAA.h"
15+
#include "phasar/Pointer/RawAliasSet.h"
16+
#include "phasar/Pointer/UnionFindAA.h"
17+
#include "phasar/Utils/MaybeUniquePtr.h"
18+
#include "phasar/Utils/NonNullPtr.h"
19+
#include "phasar/Utils/Soundness.h"
20+
#include "phasar/Utils/TypedVector.h"
21+
#include "phasar/Utils/ValueCompressor.h"
22+
23+
#include "llvm/ADT/ArrayRef.h"
24+
25+
namespace llvm {
26+
class Function;
27+
} // namespace llvm
28+
29+
namespace psr {
30+
31+
class LLVMProjectIRDB;
32+
33+
/// Alias-analysis result for the Andersen-style OTF points-to analysis.
34+
///
35+
/// Two values may-alias iff their points-to sets share at least one abstract
36+
/// object. Satisfies \c UnionFindAAResult so it can be wrapped by
37+
/// \c LLVMUnionFindAliasIterator.
38+
struct AndersenOTFResult {
39+
TypedVector<ValueId, RawAliasSet<ValueId>> AliasSets;
40+
LLVMBasedCallGraph CG;
41+
42+
[[nodiscard]] static constexpr bool isCached() noexcept { return true; }
43+
[[nodiscard]] constexpr size_t size() const noexcept {
44+
return AliasSets.size();
45+
}
46+
47+
[[nodiscard]] RawAliasSet<ValueId>
48+
getRawAliasSet(ValueId Var) const noexcept {
49+
if (!AliasSets.inbounds(Var)) {
50+
return {};
51+
}
52+
return AliasSets[Var];
53+
}
54+
55+
[[nodiscard]] bool mayAlias(ValueId Var1, ValueId Var2) const noexcept {
56+
if (Var1 == Var2) {
57+
return true;
58+
}
59+
if (!AliasSets.inbounds(Var1)) {
60+
return false;
61+
}
62+
return AliasSets[Var1].contains(Var2);
63+
}
64+
};
65+
66+
static_assert(UnionFindAAResult<AndersenOTFResult>);
67+
68+
/// Andersen-style inclusion-based points-to analysis that co-refines the call
69+
/// graph and points-to sets in a single fixpoint.
70+
///
71+
/// Unlike the staged pipeline (resolver → PA), this solver owns its own
72+
/// function-worklist loop: direct calls add callees immediately; indirect
73+
/// calls are resolved as \c pts(fp) grows.
74+
///
75+
/// Phase 1: context- and field-insensitive.
76+
class AndersenOTFSolver {
77+
public:
78+
explicit AndersenOTFSolver(const LLVMProjectIRDB &IRDB,
79+
llvm::ArrayRef<const llvm::Function *> Entries,
80+
ValueCompressor<PAGVariable> &VC,
81+
Soundness S = Soundness::Soundy) noexcept;
82+
83+
/// Run the full OTF fixpoint and return the alias-analysis result.
84+
[[nodiscard]] AndersenOTFResult solve();
85+
86+
private:
87+
struct SolverData;
88+
89+
NonNullPtr<const LLVMProjectIRDB> IRDB;
90+
llvm::ArrayRef<const llvm::Function *> Entries;
91+
NonNullPtr<ValueCompressor<PAGVariable>> VC;
92+
Soundness S;
93+
};
94+
95+
// ---- Factory functions ------------------------------------------------
96+
97+
/// Runs the Andersen OTF fixpoint and returns the raw alias-analysis result
98+
/// (no LLVM-value wrapping). If \p VC is null, a fresh one is allocated.
99+
[[nodiscard]] AndersenOTFResult
100+
computeAndersenOTFRaw(const LLVMProjectIRDB &IRDB,
101+
llvm::ArrayRef<const llvm::Function *> EntryPoints,
102+
MaybeUniquePtr<ValueCompressor<PAGVariable>> VC = nullptr,
103+
Soundness S = Soundness::Soundy);
104+
105+
/// Runs the Andersen OTF fixpoint and returns an \c LLVMUnionFindAliasIterator
106+
/// that implements \c IsLLVMAliasIterator.
107+
[[nodiscard]] LLVMUnionFindAliasIterator<AndersenOTFResult>
108+
computeAndersenOTF(const LLVMProjectIRDB &IRDB,
109+
llvm::ArrayRef<const llvm::Function *> EntryPoints,
110+
MaybeUniquePtr<ValueCompressor<PAGVariable>> VC = nullptr,
111+
Soundness S = Soundness::Soundy);
112+
113+
} // namespace psr

0 commit comments

Comments
 (0)