Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctionComposer.h"
#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h"
#include "phasar/PhasarLLVM/Domain/AnalysisDomain.h"
#include "phasar/PhasarLLVM/Utils/LatticeDomain.h"

namespace llvm {
class Instruction;
Expand All @@ -31,7 +32,7 @@ namespace psr {

struct IDELinearConstantAnalysisDomain : public LLVMAnalysisDomainDefault {
// int64_t corresponds to llvm's type of constant integer
using l_t = int64_t;
using l_t = LatticeDomain<int64_t>;
};

class LLVMBasedICFG;
Expand Down Expand Up @@ -176,10 +177,10 @@ class IDELinearConstantAnalysis
public std::enable_shared_from_this<GenConstant> {
private:
const unsigned GenConstantId;
const l_t IntConst;
const int64_t IntConst;

public:
explicit GenConstant(l_t IntConst);
explicit GenConstant(int64_t IntConst);

l_t computeTarget(l_t Source) override;

Expand Down Expand Up @@ -253,7 +254,7 @@ class IDELinearConstantAnalysis
* @param rop right operand
* @return Result of binary operation
*/
static l_t executeBinOperation(unsigned Op, l_t Lop, l_t Rop);
static l_t executeBinOperation(unsigned Op, l_t LVal, l_t RVal);

static char opToChar(unsigned Op);

Expand Down
124 changes: 91 additions & 33 deletions include/phasar/PhasarLLVM/Utils/LatticeDomain.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,27 @@
#ifndef PHASAR_PHASARLLVM_UTILS_LATTICEDOMAIN_H
#define PHASAR_PHASARLLVM_UTILS_LATTICEDOMAIN_H

#include "llvm/Support/ErrorHandling.h"

#include <iostream>
#include <type_traits>
#include <variant>

#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"

#include "phasar/Utils/TypeTraits.h"

namespace psr {

/// Represents the infimum of the lattice:
/// Top is the greatest element that is less than or equal to all elements of
/// the lattice.
struct Top {};

static inline std::ostream &operator<<(std::ostream &OS,
[[maybe_unused]] const Top &T) {
inline std::ostream &operator<<(std::ostream &OS, Top /*unused*/) {
return OS << "Top";
}

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Top /*unused*/) {
return OS << "Top";
}

Expand All @@ -32,43 +39,96 @@ static inline std::ostream &operator<<(std::ostream &OS,
/// of the lattice.
struct Bottom {};

static inline std::ostream &operator<<(std::ostream &OS,
[[maybe_unused]] const Bottom &B) {
inline std::ostream &operator<<(std::ostream &OS, Bottom /*unused*/) {
return OS << "Bottom";
}

/// A easy shorthand to construct a complete lattice of L.
template <typename L> using LatticeDomain = std::variant<L, Top, Bottom>;
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Bottom /*unused*/) {
return OS << "Bottom";
}

/// A easy shorthand to construct a complete lattice of L.
template <typename L>
struct LatticeDomain : public std::variant<Top, L, Bottom> {
using std::variant<Top, L, Bottom>::variant;

[[nodiscard]] inline bool isBottom() const noexcept {
return std::holds_alternative<Bottom>(*this);
}
[[nodiscard]] inline bool isTop() const noexcept {
return std::holds_alternative<Top>(*this);
}
[[nodiscard]] inline L *getValueOrNull() noexcept {
return std::get_if<L>(this);
}
[[nodiscard]] inline const L *getValueOrNull() const noexcept {
return std::get_if<L>(this);
}
};

template <typename L,
typename = std::void_t<decltype(std::declval<std::ostream &>()
<< std::declval<L>())>>
inline std::ostream &operator<<(std::ostream &OS, const LatticeDomain<L> &LD) {
if (auto T = std::get_if<Top>(&LD)) {
return OS << *T;
if (LD.isBottom()) {
return OS << "Bottom";
}
if (auto B = std::get_if<Bottom>(&LD)) {
return OS << *B;
if (LD.isTop()) {
return OS << "Top";
}
return OS << std::get<L>(LD);

const auto *Val = LD.getValueOrNull();
assert(Val && "Only alternative remaining is L");
return OS << *Val;
}

template <typename L,
typename = std::void_t<decltype(std::declval<llvm::raw_ostream &>()
<< std::declval<L>())>>
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
const LatticeDomain<L> &LD) {
if (LD.isBottom()) {
return OS << "Bottom";
}
if (LD.isTop()) {
return OS << "Top";
}

const auto *Val = LD.getValueOrNull();
assert(Val && "Only alternative remaining is L");
return OS << *Val;
}

template <typename L>
inline bool operator==(const LatticeDomain<L> &Lhs,
const LatticeDomain<L> &Rhs) {
if (std::holds_alternative<Top>(Lhs) && std::holds_alternative<Top>(Rhs)) {
return true;
if (Lhs.index() != Rhs.index()) {
return false;
}
if (std::holds_alternative<Bottom>(Lhs) &&
std::holds_alternative<Bottom>(Rhs)) {
return true;
if (auto LhsPtr = Lhs.getValueOrNull()) {
/// No need to check whether Lhs is an L; the indices are already the same
return *LhsPtr == *Rhs.getValueOrNull();
}
if (auto *LhsPtr = std::get_if<L>(&Lhs)) {
if (auto *RhsPtr = std::get_if<L>(&Rhs)) {
return *LhsPtr == *RhsPtr;
}
return true;
}

template <
typename L, typename LL,
typename = std::void_t<decltype(std::declval<LL>() == std::declval<L>())>>
inline bool operator==(const LL &Lhs, const LatticeDomain<L> Rhs) {
if (auto RVal = Rhs.getValueOrNull()) {
return Lhs == *RVal;
}
return false;
}

template <
typename L, typename LL,
typename = std::void_t<decltype(std::declval<LL>() == std::declval<L>())>>
inline bool operator==(const LatticeDomain<L> Lhs, const LL &Rhs) {
return Rhs == Lhs;
}

template <typename L>
inline bool operator!=(const LatticeDomain<L> &Lhs,
const LatticeDomain<L> &Rhs) {
Expand All @@ -78,26 +138,24 @@ inline bool operator!=(const LatticeDomain<L> &Lhs,
template <typename L>
inline bool operator<(const LatticeDomain<L> &Lhs,
const LatticeDomain<L> &Rhs) {
// Top < (Lhs::L < Rhs::L) < Bottom
if (std::holds_alternative<Top>(Rhs)) {
/// Top < (Lhs::L < Rhs::L) < Bottom
if (Rhs.isTop()) {
return false;
}
if (std::holds_alternative<Top>(Lhs)) {
if (Lhs.isTop()) {
return true;
}

if (auto *LhsPtr = std::get_if<L>(&Lhs)) {
if (auto *RhsPtr = std::get_if<L>(&Rhs)) {
if (auto LhsPtr = Lhs.getValueOrNull()) {
if (auto RhsPtr = Rhs.getValueOrNull()) {
return *LhsPtr < *RhsPtr;
}
}

if (std::holds_alternative<Bottom>(Rhs)) {
return !std::holds_alternative<Bottom>(Lhs);
}
if (std::holds_alternative<Bottom>(Lhs)) {
if (Lhs.isBottom()) {
return false;
}
if (Rhs.isBottom()) {
return true;
}
llvm_unreachable("All comparision cases should be handled above.");
}

Expand Down
10 changes: 10 additions & 0 deletions include/phasar/Utils/TypeTraits.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <ostream>
#include <tuple>
#include <type_traits>
#include <variant>

#include "llvm/Support/raw_ostream.h"

Expand Down Expand Up @@ -109,6 +110,15 @@ constexpr bool is_std_hashable_v = detail::is_std_hashable<T>::value; // NOLINT
template <typename T>
constexpr bool is_llvm_hashable_v = // NOLINT
detail::is_llvm_hashable<T>::value;

template <typename T> struct is_variant : std::false_type {}; // NOLINT

template <typename... Args>
struct is_variant<std::variant<Args...>> : std::true_type {}; // NOLINT

template <typename T>
inline constexpr bool is_variant_v = is_variant<T>::value; // NOLINT

// NOLINTEND(readability-identifier-naming)
} // namespace psr

Expand Down
Loading