Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ jobs:
fail-fast: true
matrix:
os: [ubuntu-24.04, ubuntu-24.04-arm]
compiler: [ [clang++-19, clang-19, "clang-19 libclang-rt-19-dev clang-tools-19"] ]
compiler: [ [clang++-22, clang-22, "clang-22 libclang-rt-22-dev clang-tools-22"] ]
build: [ Debug, Release, DebugLibdeps, DebugCov ]
llvm-version: [ 16, 17 ]
llvm-version: [ 16, 22.1 ]
include:
- build: Debug
cmake_build_type: Debug
Expand All @@ -31,7 +31,7 @@ jobs:
- build: DebugCov
cmake_build_type: Debug
flags: -DCODE_COVERAGE=ON
extra_dependencies: llvm-19 # For coverage
extra_dependencies: llvm-22 # For coverage
exclude:
- os: ubuntu-24.04-arm
build: Debug
Expand All @@ -43,7 +43,7 @@ jobs:
continue-on-error: false
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
fetch-depth: 0
submodules: recursive
Expand Down Expand Up @@ -102,7 +102,7 @@ jobs:

- name: Upload coverage HTML report artifact
if: matrix.build == 'DebugCov'
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: phasar-coverage-report-llvm-${{ matrix.llvm-version }}
path: ./build/ccov/all-merged/
Expand Down
6 changes: 3 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ FROM "$baseimage" AS build

RUN --mount=type=bind,source=./utils/InstallAptDependencies.sh,target=/InstallAptDependencies.sh \
set -eux; \
./InstallAptDependencies.sh --noninteractive tzdata clang-19 libclang-rt-19-dev clang-tools-19
./InstallAptDependencies.sh --noninteractive tzdata clang-22 libclang-rt-22-dev clang-tools-22

ENV CC=/usr/bin/clang-19 \
CXX=/usr/bin/clang++-19
ENV CC=/usr/bin/clang-22 \
CXX=/usr/bin/clang++-22

FROM build

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ PhASAR supports C++20 modules as an experimental feature.

## Currently Supported Version of LLVM

**NEW**: PhASAR is currently set up to support **LLVM-16 and 17**, using LLVM 16 by default.<br>
**NEW**: PhASAR is currently set up to support LLVM versions **between LLVM-16 and LLVM-22.1**, using LLVM 16 by default. We actively test PHASAR with LLVM-16 and LLVM-22.1, so if something does not work, try these versions instead.<br>
Specify the `PHASAR_LLVM_VERSION` cmake-variable to change the LLVM version to use.


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,13 @@ class PathSensitivityManagerMixin {
return pathsDagToAll(Inst, llvm::ArrayRef(&Fact, 1), Config, PFilter);
}

if (auto Next = Inst->getNextNonDebugInstruction()) {
if (auto Next =
#if LLVM_VERSION_MAJOR <= 18
Inst->getNextNonDebugInstruction()
#else
Inst->getNextNode()
#endif
) {
return pathsDagToAll(Next, llvm::ArrayRef(&Fact, 1), Config, PFilter);
}

Expand All @@ -203,9 +209,11 @@ class PathSensitivityManagerMixin {

for (const auto *BB : llvm::successors(Inst)) {
const auto *First = &BB->front();
#if LLVM_VERSION_MAJOR <= 18
if (llvm::isa<llvm::DbgInfoIntrinsic>(First)) {
First = First->getNextNonDebugInstruction();
}
#endif
if (ESG.getNodeOrNull(First, Fact)) {
return pathsDagToAll(First, llvm::ArrayRef(&Fact, 1), Config, PFilter);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,11 @@ namespace psr::detail {
if (!Stmt->getNextNode()) {
auto GetStartRow = [&Self](const llvm::BasicBlock *BB) -> decltype(auto) {
const auto *First = &BB->front();
#if LLVM_VERSION_MAJOR <= 18
if (llvm::isa<llvm::DbgInfoIntrinsic>(First)) {
First = First->getNextNonDebugInstruction();
}
#endif
return Self.row(First);
};

Expand Down Expand Up @@ -104,9 +106,11 @@ namespace psr::detail {
auto GetStartVal = [&Self,
&Fact](const llvm::BasicBlock *BB) -> decltype(auto) {
const auto *First = &BB->front();
#if LLVM_VERSION_MAJOR <= 18
if (llvm::isa<llvm::DbgInfoIntrinsic>(First)) {
First = First->getNextNonDebugInstruction();
}
#endif
return Self.resultAt(First, Fact);
};

Expand Down
6 changes: 6 additions & 0 deletions include/phasar/PhasarLLVM/Utils/LLVMShorthands.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ bool isHeapAllocatingFunction(const llvm::Function *F) noexcept;
///
/// \note This function is less useful in practice than you may think. Consider
/// using isConsistentCall() instead.
LLVM_DEPRECATED("With opaque pointers, this function is not very useful. Use "
"isConsistentCall() instead.",
"psr::isConsistentCall")
bool matchesSignature(const llvm::Function *F, const llvm::FunctionType *FType,
bool ExactMatch = true);

Expand All @@ -79,6 +82,9 @@ bool matchesSignature(const llvm::Function *F, const llvm::FunctionType *FType,
///
/// \note This function is less useful in practice than you may think. Consider
/// using isConsistentCall() instead.
LLVM_DEPRECATED("With opaque pointers, this function is not very useful. Use "
"isConsistentCall() instead.",
"psr::isConsistentCall")
bool matchesSignature(const llvm::FunctionType *FType1,
const llvm::FunctionType *FType2);

Expand Down
7 changes: 3 additions & 4 deletions lib/PhasarLLVM/ControlFlow/GlobalCtorsDtorsModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -379,10 +379,9 @@ bool GlobalCtorsDtorsModel::isPhasarGenerated(
const llvm::Function &F) noexcept {
if (F.hasName()) {
llvm::StringRef FunctionName = F.getName();
return llvm::StringSwitch<bool>(FunctionName)
.Cases(ModelName, DtorModelName, DtorsCallerName, UserEntrySelectorName,
true)
.Default(false);
const auto Cases = {ModelName, DtorModelName, DtorsCallerName,
UserEntrySelectorName};
return llvm::is_contained(Cases, FunctionName);
}

return false;
Expand Down
31 changes: 29 additions & 2 deletions lib/PhasarLLVM/ControlFlow/LLVMBasedCFG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ auto detail::LLVMBasedCFGImpl<Derived>::getFunctionOfImpl(
template <typename Derived>
auto detail::LLVMBasedCFGImpl<Derived>::getPredsOfImpl(n_t I) const
-> llvm::SmallVector<n_t, 2> {
#if LLVM_VERSION_MAJOR > 18
if (const auto *PrevInst = I->getPrevNode()) {
return {PrevInst};
}
#else

if (!IgnoreDbgInstructions) {
if (const auto *PrevInst = I->getPrevNode()) {
return {PrevInst};
Expand All @@ -44,6 +50,7 @@ auto detail::LLVMBasedCFGImpl<Derived>::getPredsOfImpl(n_t I) const
return {PrevNonDbgInst};
}
}
#endif
// If we do not have a predecessor yet, look for basic blocks which
// lead to our instruction in question!

Expand All @@ -53,10 +60,12 @@ auto detail::LLVMBasedCFGImpl<Derived>::getPredsOfImpl(n_t I) const
[](const llvm::BasicBlock *BB) {
assert(BB && "BB under analysis was not well formed.");
const llvm::Instruction *Pred = BB->getTerminator();
#if LLVM_VERSION_MAJOR <= 18
if (llvm::isa<llvm::DbgInfoIntrinsic>(Pred)) {
Pred = Pred->getPrevNonDebugInstruction(
false /*Only debug instructions*/);
}
#endif
return Pred;
});

Expand All @@ -66,6 +75,11 @@ auto detail::LLVMBasedCFGImpl<Derived>::getPredsOfImpl(n_t I) const
template <typename Derived>
auto detail::LLVMBasedCFGImpl<Derived>::getSuccsOfImpl(n_t I) const
-> llvm::SmallVector<n_t, 2> {
#if LLVM_VERSION_MAJOR > 18
if (const auto *NextInst = I->getNextNode()) {
return {NextInst};
}
#else
// case we wish to consider LLVM's debug instructions
if (!IgnoreDbgInstructions) {
if (const auto *NextInst = I->getNextNode()) {
Expand All @@ -75,14 +89,18 @@ auto detail::LLVMBasedCFGImpl<Derived>::getSuccsOfImpl(n_t I) const
false /*Only debug instructions*/)) {
return {NextNonDbgInst};
}
#endif

if (const auto *Branch = llvm::dyn_cast<llvm::BranchInst>(I);
Branch && isStaticVariableLazyInitializationBranch(Branch)) {
// Skip the "already initialized" case, such that the analysis is always
// aware of the initialized value.
const auto *NextInst = &Branch->getSuccessor(0)->front();
#if LLVM_VERSION_MAJOR <= 18
if (IgnoreDbgInstructions && llvm::isa<llvm::DbgInfoIntrinsic>(NextInst)) {
NextInst = NextInst->getNextNonDebugInstruction(false);
}
#endif
return {NextInst};
}

Expand All @@ -93,10 +111,12 @@ auto detail::LLVMBasedCFGImpl<Derived>::getSuccsOfImpl(n_t I) const
[IgnoreDbgInstructions{IgnoreDbgInstructions}](
const llvm::BasicBlock *BB) {
const llvm::Instruction *Succ = &BB->front();
#if LLVM_VERSION_MAJOR <= 18
if (IgnoreDbgInstructions && llvm::isa<llvm::DbgInfoIntrinsic>(Succ)) {
Succ = Succ->getNextNonDebugInstruction(
false /*Only debug instructions*/);
}
#endif
return Succ;
});
return Successors;
Expand Down Expand Up @@ -133,10 +153,12 @@ auto detail::LLVMBasedCFGImpl<Derived>::getStartPointsOfImpl(f_t Fun) const
}
if (!Fun->isDeclaration()) {
const auto *EntryInst = &Fun->front().front();
#if LLVM_VERSION_MAJOR <= 18
if (IgnoreDbgInstructions && llvm::isa<llvm::DbgInfoIntrinsic>(EntryInst)) {
return {EntryInst->getNextNonDebugInstruction(
false /*Only debug instructions*/)};
}
#endif
return {EntryInst};
}
PHASAR_LOG_LEVEL_CAT(DEBUG, "LLVMBasedCFG",
Expand Down Expand Up @@ -170,8 +192,13 @@ bool detail::LLVMBasedCFGImpl<Derived>::isStartPointImpl(
if (Inst == FirstInst) {
return true;
}
return llvm::isa<llvm::DbgInfoIntrinsic>(FirstInst) &&
Inst == FirstInst->getNextNonDebugInstruction(false);
#if LLVM_VERSION_MAJOR <= 18
if (llvm::isa<llvm::DbgInfoIntrinsic>(FirstInst)) {
FirstInst = FirstInst->getNextNonDebugInstruction(false);
}
#endif

return Inst == FirstInst;
}

template <typename Derived>
Expand Down
7 changes: 7 additions & 0 deletions lib/PhasarLLVM/ControlFlow/LLVMBasedICFGExportsImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,14 @@ LLVMBasedICFG::exportICFGAsDot(bool WithSourceCodeInfo) const {
assert(BB && !BB->empty());
const auto *InterTo = &BB->front();

#if LLVM_VERSION_MAJOR <= 18
if (IgnoreDbgInstructions && llvm::isa<llvm::DbgInfoIntrinsic>(InterTo)) {
InterTo = InterTo->getNextNonDebugInstruction(false);
}
#else
(void)IgnoreDbgInstructions;
#endif

// createEdge(From, InterTo);
OS << intptr_t(CS) << "->" << intptr_t(InterTo) << ";\n";

Expand Down Expand Up @@ -238,9 +243,11 @@ struct GetIR {
llvm::BasicBlock::const_iterator End) {
assert(It != End);

#if LLVM_VERSION_MAJOR <= 18
if (It->isDebugOrPseudoInst()) {
return llvmIRToStableString(It->getNextNonDebugInstruction());
}
#endif

return llvmIRToStableString(&*It);
}
Expand Down
52 changes: 51 additions & 1 deletion lib/PhasarLLVM/ControlFlow/Resolver/Resolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h"
#include "phasar/Utils/Logger.h"

#include "llvm/ADT/STLExtras.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/DebugInfoMetadata.h"
Expand Down Expand Up @@ -146,9 +147,58 @@ bool psr::isConsistentCall(const llvm::CallBase *CallSite,
if (CallSite->arg_size() != DestFun->arg_size() && !DestFun->isVarArg()) {
return false;
}
if (!matchesSignature(DestFun, CallSite->getFunctionType(), false)) {

for (const auto &[Param, ArgOp] :
llvm::zip_first(DestFun->args(), CallSite->args())) {

const auto *ParamTy = Param.getType();
const auto *ArgTy = ArgOp->getType();

if (ParamTy == ArgTy) {
// Trivial equality
continue;
}

if (ParamTy->getTypeID() != ArgTy->getTypeID()) {
// Trivial non-equality, e.g. PointerType and IntegerType
return false;
}

if (ParamTy->isPointerTy()) {
if (Param.hasByValAttr() !=
CallSite->isByValArgument(ArgOp.getOperandNo())) {
return false;
}

const auto *ParamSRetTy = Param.getParamStructRetType();
const auto *ArgSRetTy =
CallSite->getParamStructRetType(ArgOp.getOperandNo());
if ((ParamSRetTy != nullptr) != (ArgSRetTy != nullptr)) {
return false;
}

if (ParamSRetTy && ArgSRetTy) {
// TODO: For better precision, compare the sret types as well
// Trivial non-equality, e.g. PointerType and IntegerType
if (ParamSRetTy->getTypeID() != ArgSRetTy->getTypeID()) {
// Trivial non-equality, e.g. PointerType and IntegerType
return false;
}
}
}

if (ParamTy->isStructTy()) {
// Copied comment from struct-case in isTypeMatchForFunctionArgument():
// > Well, we could do sanity checks here, but if the analysed code is
// > insane we would miss callees, so we don't do that.

continue;
}

// Types are non-equal and we could not find a reason to treat the same
return false;
}

return true;
}

Expand Down
Loading
Loading