diff --git a/include/dfa/analysis/core/assign_resolver.hpp b/include/dfa/analysis/core/assign_resolver.hpp new file mode 100644 index 0000000..b3c3c80 --- /dev/null +++ b/include/dfa/analysis/core/assign_resolver.hpp @@ -0,0 +1,63 @@ +//===- assign_resolver.hpp --------------------------------------------===// +// +// Copyright (c) 2024 Junjie Shen +// +// see https://github.com/shenjunjiekoda/knight/blob/main/LICENSE for +// license information. +// +//===------------------------------------------------------------------===// +// +// This header defines the assign resolver. +// +//===------------------------------------------------------------------===// + +#pragma once + +#include "dfa/analysis/core/symbol_resolver.hpp" +#include "dfa/analysis_context.hpp" +namespace knight::dfa { + +namespace internal { + +constexpr unsigned AssignmentContextAlignment = 64U; + +struct alignas(AssignmentContextAlignment) + AssignmentContext { // NOLINT(altera-struct-pack-align) + std::optional< const TypedRegion* > treg = std::nullopt; + std::optional< const clang::Stmt* > stmt = std::nullopt; + std::optional< const clang::Expr* > rhs_expr = std::nullopt; + SExprRef lhs_sexpr{}; + SExprRef rhs_sexpr{}; + clang::BinaryOperator::Opcode op = clang::BinaryOperator::Opcode::BO_Assign; +}; // struct AssignmentContext + +} // namespace internal + +class AssignResolver { + private: + AnalysisContext* m_ctx; + const SymbolResolver* m_sym_resolver; + + public: + AssignResolver(AnalysisContext* ctx, const SymbolResolver* sym_resolver) + : m_ctx(ctx), m_sym_resolver(sym_resolver) {} + + public: + [[nodiscard]] ProgramStateRef resolve(internal::AssignmentContext) const; + + private: + void handle_int_assign(internal::AssignmentContext assign_ctx, + SymbolRef res_sym, + bool is_direct_assign, + clang::BinaryOperator::Opcode op, + ProgramStateRef& state, + SExprRef& binary_sexpr) const; + void handle_ptr_assign(internal::AssignmentContext assign_ctx, + SymbolRef res_sym, + bool is_direct_assign, + clang::BinaryOperator::Opcode op, + ProgramStateRef& state, + SExprRef& binary_sexpr) const; +}; // class AssignResolver + +} // namespace knight::dfa \ No newline at end of file diff --git a/include/dfa/analysis/core/binary_op_resolver.hpp b/include/dfa/analysis/core/binary_op_resolver.hpp new file mode 100644 index 0000000..6eef94e --- /dev/null +++ b/include/dfa/analysis/core/binary_op_resolver.hpp @@ -0,0 +1,69 @@ +//===- binary_op_resolver.hpp ------------------------------------------===// +// +// Copyright (c) 2024 Junjie Shen +// +// see https://github.com/shenjunjiekoda/knight/blob/main/LICENSE for +// license information. +// +//===------------------------------------------------------------------===// +// +// This header defines the uanry op resolver. +// +//===------------------------------------------------------------------===// + +#pragma once + +#include "clang/AST/Expr.h" +#include "dfa/analysis/core/symbol_resolver.hpp" +#include "dfa/analysis/core/unary_op_resolver.hpp" +#include "dfa/analysis_context.hpp" + +namespace knight::dfa { + +namespace internal { + +constexpr unsigned BinaryOperationContextAlignment = 128U; + +struct alignas(BinaryOperationContextAlignment) BinaryOperationContext { + clang::BinaryOperator::Opcode op{}; + // lhs_expr has value or lhs_sexpr has value + std::optional< const clang::Expr* > lhs_expr; + std::optional< SExprRef > lhs_sexpr; + + // rhs_expr has value or rhs_sexpr has value + std::optional< const clang::Expr* > rhs_expr; + std::optional< SExprRef > rhs_sexpr; + + clang::QualType result_type; + const clang::Stmt* result_stmt{}; +}; // struct BinaryOperationContext + +} // namespace internal + +class BinaryOpResolver { + friend class UnaryOpResolver; + + private: + AnalysisContext* m_ctx; + const SymbolResolver* m_sym_resolver; + + public: + explicit BinaryOpResolver(AnalysisContext* ctx, + const SymbolResolver* sym_resolver) + : m_ctx(ctx), m_sym_resolver(sym_resolver) {} + + public: + void resolve(const clang::BinaryOperator*) const; + + private: + void handle_binary_operation(internal::BinaryOperationContext) const; + void handle_assign_binary_operation(internal::BinaryOperationContext) const; + void handle_int_binary_operation(internal::BinaryOperationContext) const; + void handle_int_non_assign_binary_operation( + internal::BinaryOperationContext) const; + void handle_ref_binary_operation(internal::BinaryOperationContext) const; + void handle_ptr_binary_operation(internal::BinaryOperationContext) const; + +}; // class BinaryOpResolver + +} // namespace knight::dfa \ No newline at end of file diff --git a/include/dfa/analysis/core/symbol_resolver.hpp b/include/dfa/analysis/core/symbol_resolver.hpp index c6b1707..98e20cb 100644 --- a/include/dfa/analysis/core/symbol_resolver.hpp +++ b/include/dfa/analysis/core/symbol_resolver.hpp @@ -33,13 +33,6 @@ namespace knight::dfa { -namespace internal { - -constexpr unsigned BinaryOperationContextAlignment = 128U; -constexpr unsigned AssignmentContextAlignment = 64U; - -} // namespace internal - class SymbolResolver : public Analysis< SymbolResolver, analyze::EvalStmt< clang::Stmt >, @@ -75,62 +68,12 @@ class SymbolResolver } private: - struct alignas(internal::BinaryOperationContextAlignment) - BinaryOperationContext { - clang::BinaryOperator::Opcode op{}; - // lhs_expr has value or lhs_sexpr has value - std::optional< const clang::Expr* > lhs_expr; - std::optional< SExprRef > lhs_sexpr; - - // rhs_expr has value or rhs_sexpr has value - std::optional< const clang::Expr* > rhs_expr; - std::optional< SExprRef > rhs_sexpr; - - clang::QualType result_type; - const clang::Stmt* result_stmt{}; - }; // struct BinaryOperationContext - void handle_var_decl(const clang::VarDecl* var_decl, ProgramStateRef& state, SExprRef& stmt_sexpr) const; - void handle_int_unary_operation(const clang::UnaryOperator*) const; - void handle_ptr_unary_operation(const clang::UnaryOperator*) const; - - void handle_binary_operation(BinaryOperationContext) const; - void handle_assign_binary_operation(BinaryOperationContext) const; - void handle_int_binary_operation(BinaryOperationContext) const; - void handle_int_non_assign_binary_operation(BinaryOperationContext) const; - void handle_ref_binary_operation(BinaryOperationContext) const; - void handle_ptr_binary_operation(BinaryOperationContext) const; - void handle_int_cond_op(const clang::ConditionalOperator*) const; - struct alignas(internal::AssignmentContextAlignment) - AssignmentContext { // NOLINT(altera-struct-pack-align) - std::optional< const TypedRegion* > treg = std::nullopt; - std::optional< const clang::Stmt* > stmt = std::nullopt; - std::optional< const clang::Expr* > rhs_expr = std::nullopt; - SExprRef lhs_sexpr{}; - SExprRef rhs_sexpr{}; - clang::BinaryOperator::Opcode op = - clang::BinaryOperator::Opcode::BO_Assign; - }; - - [[nodiscard]] ProgramStateRef handle_assign(AssignmentContext) const; - void handle_int_assign(AssignmentContext assign_ctx, - SymbolRef res_sym, - bool is_direct_assign, - clang::BinaryOperator::Opcode op, - ProgramStateRef& state, - SExprRef& binary_sexpr) const; - void handle_ptr_assign(AssignmentContext assign_ctx, - SymbolRef res_sym, - bool is_direct_assign, - clang::BinaryOperator::Opcode op, - ProgramStateRef& state, - SExprRef& binary_sexpr) const; - void handle_load(const clang::Expr* load_expr) const; }; diff --git a/include/dfa/analysis/core/unary_op_resolver.hpp b/include/dfa/analysis/core/unary_op_resolver.hpp new file mode 100644 index 0000000..af4ace8 --- /dev/null +++ b/include/dfa/analysis/core/unary_op_resolver.hpp @@ -0,0 +1,41 @@ +//===- unary_op_resolver.hpp ------------------------------------------===// +// +// Copyright (c) 2024 Junjie Shen +// +// see https://github.com/shenjunjiekoda/knight/blob/main/LICENSE for +// license information. +// +//===------------------------------------------------------------------===// +// +// This header defines the uanry op resolver. +// +//===------------------------------------------------------------------===// + +#pragma once + +#include "clang/AST/Expr.h" +#include "dfa/analysis/core/symbol_resolver.hpp" +#include "dfa/analysis_context.hpp" + +namespace knight::dfa { + +class UnaryOpResolver { + private: + AnalysisContext* m_ctx; + const SymbolResolver* m_sym_resolver; + + public: + explicit UnaryOpResolver(AnalysisContext* ctx, + const SymbolResolver* sym_resolver) + : m_ctx(ctx), m_sym_resolver(sym_resolver) {} + + public: + void resolve(const clang::UnaryOperator*) const; + + private: + void handle_int_unary_operation(const clang::UnaryOperator*) const; + void handle_ptr_unary_operation(const clang::UnaryOperator*) const; + +}; // class UnaryOpResolver + +} // namespace knight::dfa \ No newline at end of file diff --git a/include/dfa/domain/pointer.hpp b/include/dfa/domain/pointer.hpp index eb698cf..6de6ab9 100644 --- a/include/dfa/domain/pointer.hpp +++ b/include/dfa/domain/pointer.hpp @@ -29,13 +29,13 @@ namespace knight::dfa { constexpr DomID PointerInfoID = get_domain_id(DomainKind::PointerInfo); -using PointToSet = DiscreteDom< RegionDef, DomainKind::PointToSetDomain >; +using PointToSet = DiscreteDom< RegionDefRef, DomainKind::PointToSetDomain >; using RegionPointToDom = MapDom< RegionRef, PointToSet, DomainKind::RegionPointToSetDomain >; using StmtPointToDom = MapDom< internal::StmtRef, RegionPointToDom, DomainKind::StmtPointToSetDomain >; -using AliasToSet = DiscreteDom< RegionDef, DomainKind::AliasToDomain >; +using AliasToSet = DiscreteDom< RegionDefRef, DomainKind::AliasToDomain >; using RegionAliasDom = MapDom< RegionRef, AliasToSet, DomainKind::RegionAliasToDomain >; using StmtAliasDom = diff --git a/include/dfa/program_state.hpp b/include/dfa/program_state.hpp index 548869a..5e73f8f 100644 --- a/include/dfa/program_state.hpp +++ b/include/dfa/program_state.hpp @@ -65,7 +65,7 @@ namespace knight::dfa { using ProgramStateRef = llvm::IntrusiveRefCntPtr< const ProgramState >; using DomValMap = llvm::DenseMap< DomID, SharedVal >; using RegionDefMap = llvm::DenseMap< std::pair< RegionRef, const StackFrame* >, - const RegionSymVal* >; + const RegionDef* >; using StmtSExprMap = llvm::DenseMap< std::pair< ProcCFG::StmtRef, const StackFrame* >, SExprRef >; @@ -153,14 +153,14 @@ class ProgramState : public llvm::FoldingSetNode { [[nodiscard]] ProgramStateRef set_region_def(RegionRef region, const StackFrame* frame, - const RegionSymVal* def) const; + const RegionDef* def) const; [[nodiscard]] ProgramStateRef set_stmt_sexpr(ProcCFG::StmtRef stmt, const StackFrame* frame, SExprRef sexpr) const; [[nodiscard]] ProgramStateRef set_constraint_system( const ConstraintSystem& cst_system) const; - [[nodiscard]] std::optional< const RegionSymVal* > get_region_def( + [[nodiscard]] std::optional< const RegionDef* > get_region_def( RegionRef region, const StackFrame* frame) const; [[nodiscard]] std::optional< SExprRef > get_stmt_sexpr( ProcCFG::StmtRef stmt, const StackFrame* frame) const; diff --git a/include/dfa/symbol.hpp b/include/dfa/symbol.hpp index 6cd2c55..2944059 100644 --- a/include/dfa/symbol.hpp +++ b/include/dfa/symbol.hpp @@ -64,12 +64,12 @@ bool is_valid_type_for_sym_expr(clang::QualType type); class SymExpr; class TypedRegion; class Sym; -class RegionSymVal; +class RegionDef; using SExprRef = const SymExpr*; using SymbolRef = const Sym*; using RegionRef = const TypedRegion*; -using RegionDef = const RegionSymVal*; +using RegionDefRef = const RegionDef*; class SymIterator { private: @@ -194,12 +194,12 @@ class ScalarInt : public Scalar { }; // class Integer /// \brief A scalar region address -class ScalarRegion : public Scalar { +class RegionAddr : public Scalar { private: const TypedRegion* m_region; public: - explicit ScalarRegion(const TypedRegion* region) + explicit RegionAddr(const TypedRegion* region) : Scalar(SymExprKind::RegionSymbolVal), m_region(region) {} [[nodiscard]] const TypedRegion* get_region() const; @@ -221,7 +221,7 @@ class ScalarRegion : public Scalar { } void Profile(llvm::FoldingSetNodeID& id) const override { // NOLINT - ScalarRegion::profile(id, m_region); + RegionAddr::profile(id, m_region); } }; @@ -251,7 +251,7 @@ class Sym : public SymExpr { }; // class Sym /// \brief A symbol representing a region value. -class RegionSymVal : public Sym { +class RegionDef : public Sym { private: /// \brief The region that the symbol represents. RegionRef m_region; @@ -264,11 +264,11 @@ class RegionSymVal : public Sym { bool m_is_external; public: - RegionSymVal(SymID id, - RegionRef region, - const LocationContext* loc_ctx, - bool is_external); - ~RegionSymVal() override = default; + RegionDef(SymID id, + RegionRef region, + const LocationContext* loc_ctx, + bool is_external); + ~RegionDef() override = default; [[gnu::returns_nonnull]] RegionRef get_region() const; [[nodiscard]] bool is_external() const { return m_is_external; } @@ -285,11 +285,11 @@ class RegionSymVal : public Sym { } void Profile(llvm::FoldingSetNodeID& profile) const override { // NOLINT - RegionSymVal::profile(profile, - get_id(), - m_region, - m_loc_ctx, - m_is_external); + RegionDef::profile(profile, + get_id(), + m_region, + m_loc_ctx, + m_is_external); } [[nodiscard]] llvm::StringRef get_kind_name() const override { @@ -313,7 +313,7 @@ class RegionSymVal : public Sym { return sym->get_kind() == SymExprKind::RegionSymbolVal; } -}; // class RegionSymVal +}; // class RegionDef class RegionSymExtent : public Sym { private: diff --git a/include/dfa/symbol_manager.hpp b/include/dfa/symbol_manager.hpp index f0f8aa7..d7506bf 100644 --- a/include/dfa/symbol_manager.hpp +++ b/include/dfa/symbol_manager.hpp @@ -36,20 +36,19 @@ class SymbolManager { return get_persistent_sexpr< ScalarInt >(value, type); } - [[nodiscard]] const ScalarRegion* get_scalar_region( - const TypedRegion* region) { - return get_persistent_sexpr< ScalarRegion >(region); + [[nodiscard]] const RegionAddr* get_region_addr(const TypedRegion* region) { + return get_persistent_sexpr< RegionAddr >(region); } - [[nodiscard]] const RegionSymVal* get_region_sym_val( + [[nodiscard]] const RegionDef* get_region_def( const TypedRegion* typed_region, const LocationContext* loc_ctx) { m_sym_cnt++; const auto* space = typed_region->get_memory_space(); bool is_external = space == nullptr || space->is_stack_arg(); - return get_persistent_sexpr< RegionSymVal >(m_sym_cnt, - typed_region, - loc_ctx, - is_external); + return get_persistent_sexpr< RegionDef >(m_sym_cnt, + typed_region, + loc_ctx, + is_external); } [[nodiscard]] const SymbolConjured* get_symbol_conjured( diff --git a/src/dfa/analysis/core/assign_resolver.cpp b/src/dfa/analysis/core/assign_resolver.cpp new file mode 100644 index 0000000..1cf5d59 --- /dev/null +++ b/src/dfa/analysis/core/assign_resolver.cpp @@ -0,0 +1,192 @@ +//===- assign_resolver.cpp --------------------------------------------===// +// +// Copyright (c) 2024 Junjie Shen +// +// see https://github.com/shenjunjiekoda/knight/blob/main/LICENSE for +// license information. +// +//===------------------------------------------------------------------===// +// +// This header implements the assign resolver. +// +//===------------------------------------------------------------------===// + +#include "dfa/analysis/core/assign_resolver.hpp" +#include "util/log.hpp" + +#define DEBUG_TYPE "assign_resolver" + +namespace knight::dfa { + +void AssignResolver::handle_ptr_assign(internal::AssignmentContext assign_ctx, + SymbolRef res_sym, + bool is_direct_assign, + clang::BinaryOperator::Opcode op, + ProgramStateRef& state, + SExprRef& binary_sexpr) const { + auto type = assign_ctx.rhs_sexpr->get_type(); + auto& sym_mgr = m_ctx->get_symbol_manager(); + if (!is_direct_assign) { + knight_unreachable("indirect ptr assign not supported yet"); + (void)op; + } + auto region_def = llvm::dyn_cast< RegionDef >(binary_sexpr); + auto region_addr_val = llvm::dyn_cast< RegionAddr >(binary_sexpr); +} + +void AssignResolver::handle_int_assign(internal::AssignmentContext assign_ctx, + SymbolRef res_sym, + bool is_direct_assign, + clang::BinaryOperator::Opcode op, + ProgramStateRef& state, + SExprRef& binary_sexpr) const { + auto type = assign_ctx.rhs_sexpr->get_type(); + auto& sym_mgr = m_ctx->get_symbol_manager(); + ZVariable x(res_sym); + + ZLinearExpr cstr; + cstr += x; + + knight_log_nl(llvm::outs() << "zvar x: "; x.dump(llvm::outs()); + llvm::outs() << "\n";); + auto lhs_var = assign_ctx.lhs_sexpr != nullptr + ? assign_ctx.lhs_sexpr->get_as_zvariable() + : std::nullopt; + auto lhs_num = assign_ctx.lhs_sexpr != nullptr + ? assign_ctx.lhs_sexpr->get_as_znum() + : std::nullopt; + auto rhs_var = assign_ctx.rhs_sexpr->get_as_zvariable(); + auto rhs_num = assign_ctx.rhs_sexpr->get_as_znum(); + if (!is_direct_assign && lhs_var && rhs_var) { + LinearNumericalAssignEvent + event(ZVarAssignBinaryVarVar{op, x, *lhs_var, *rhs_var}, state); + m_sym_resolver->dispatch_event(event); + + cstr -= (*lhs_var + *rhs_var); + } else if (!is_direct_assign && + ((lhs_var && rhs_num) || (lhs_num && rhs_var))) { + auto y = lhs_var ? *lhs_var : *rhs_var; + auto z = lhs_var ? *rhs_num : *lhs_num; + LinearNumericalAssignEvent event(ZVarAssignBinaryVarNum{op, x, y, z}, + state); + m_sym_resolver->dispatch_event(event); + + cstr -= (y + z); + } else if (auto zexpr = binary_sexpr->get_as_zexpr()) { + if (auto znum = binary_sexpr->get_as_znum()) { + LinearNumericalAssignEvent event(ZVarAssignZNum{x, *znum}, state); + m_sym_resolver->dispatch_event(event); + + binary_sexpr = sym_mgr.get_scalar_int(*znum, type); + cstr -= *znum; + } else if (auto zvar = binary_sexpr->get_as_zvariable()) { + LinearNumericalAssignEvent event(ZVarAssignZVar{x, *zvar}, state); + m_sym_resolver->dispatch_event(event); + + cstr -= *zvar; + } else { + LinearNumericalAssignEvent event(ZVarAssignZLinearExpr{x, *zexpr}, + state); + m_sym_resolver->dispatch_event(event); + + cstr -= *zexpr; + } + } else if (auto rhs_expr = assign_ctx.rhs_expr) { + ZVariable y( + sym_mgr.get_symbol_conjured(*rhs_expr, + m_ctx->get_current_stack_frame())); + LinearNumericalAssignEvent event(ZVarAssignZVar{x, y}, state); + m_sym_resolver->dispatch_event(event); + cstr -= y; + } else { + knight_log(llvm::outs() << "unhandled case!\n"); + return; + } + state = state->add_zlinear_constraint( + ZLinearConstraint(cstr, LinearConstraintKind::LCK_Equality)); +} + +ProgramStateRef AssignResolver::resolve( + internal::AssignmentContext assign_ctx) const { + auto op = assign_ctx.op; + bool is_direct_assign = !clang::BinaryOperator::isCompoundAssignmentOp(op); + + knight_assert_msg(assign_ctx.rhs_sexpr != nullptr, + "rhs sexpr shall be nonnull in assignment context"); + knight_assert_msg(assign_ctx.lhs_sexpr != nullptr || is_direct_assign, + "lhs sexpr shall be nonnull in indirect assignment " + "context"); + knight_assert_msg((!assign_ctx.stmt && assign_ctx.treg) || + (assign_ctx.stmt && !assign_ctx.treg), + "either stmt or treg should be set in assignment " + "context"); + + auto state = m_ctx->get_state(); + auto& sym_mgr = m_ctx->get_symbol_manager(); + auto type = assign_ctx.rhs_sexpr->get_type(); + SExprRef binary_sexpr = nullptr; + if (is_direct_assign) { + binary_sexpr = assign_ctx.rhs_sexpr; + } else { + op = clang::BinaryOperator::getOpForCompoundAssignment(op); + binary_sexpr = sym_mgr.get_binary_sym_expr(assign_ctx.lhs_sexpr, + assign_ctx.rhs_sexpr, + op, + type); + } + + SymbolRef res_sym = nullptr; + if (assign_ctx.treg) { + res_sym = sym_mgr.get_region_def(*assign_ctx.treg, + m_ctx->get_current_location_context()); + } else { + res_sym = sym_mgr.get_symbol_conjured(*assign_ctx.stmt, + type, + m_ctx->get_current_stack_frame()); + } + + knight_log_nl( + llvm::outs() << "lhs_sexpr: "; if (assign_ctx.lhs_sexpr != nullptr) { + assign_ctx.lhs_sexpr->dump(llvm::outs()); + } else { + llvm::outs() << "nullptr"; + } llvm::outs() << "\nrhs_sexpr: " + << *assign_ctx.rhs_sexpr << "\n"; + llvm::outs() << "binary_sexpr: " << *binary_sexpr << "\n";); + + if (type->isPointerType()) { + handle_ptr_assign(assign_ctx, + res_sym, + is_direct_assign, + op, + state, + binary_sexpr); + } else if (type->isIntegralOrEnumerationType()) { + handle_int_assign(assign_ctx, + res_sym, + is_direct_assign, + op, + state, + binary_sexpr); + } + + if (assign_ctx.treg) { + knight_log_nl(llvm::outs() << "\nset region: "; + assign_ctx.treg.value()->dump(llvm::outs()); + llvm::outs() << " to new_def: "; + res_sym->dump(llvm::outs()); + llvm::outs() << "\n"); + + state = state->set_region_def(*assign_ctx.treg, + m_ctx->get_current_stack_frame(), + cast< RegionDef >(res_sym)); + } else { + state = state->set_stmt_sexpr(*assign_ctx.stmt, + m_ctx->get_current_stack_frame(), + res_sym); + } + + return state; +} + +} // namespace knight::dfa \ No newline at end of file diff --git a/src/dfa/analysis/core/binary_op_resolver.cpp b/src/dfa/analysis/core/binary_op_resolver.cpp new file mode 100644 index 0000000..b020b6f --- /dev/null +++ b/src/dfa/analysis/core/binary_op_resolver.cpp @@ -0,0 +1,236 @@ +//===- binary_op_resolver.hpp ------------------------------------------===// +// +// Copyright (c) 2024 Junjie Shen +// +// see https://github.com/shenjunjiekoda/knight/blob/main/LICENSE for +// license information. +// +//===------------------------------------------------------------------===// +// +// This header implements the uanry op resolver. +// +//===------------------------------------------------------------------===// + +#include "dfa/analysis/core/binary_op_resolver.hpp" +#include "clang/AST/Expr.h" +#include "dfa/analysis/core/assign_resolver.hpp" +#include "dfa/analysis/core/numerical_event.hpp" +#include "dfa/symbol_manager.hpp" + +#define DEBUG_TYPE "binary_op_resolver" + +namespace knight::dfa { + +void BinaryOpResolver::resolve( + const clang::BinaryOperator* binary_operator) const { + handle_binary_operation( + internal::BinaryOperationContext{binary_operator->getOpcode(), + binary_operator->getLHS(), + std::nullopt, + binary_operator->getRHS(), + std::nullopt, + binary_operator->getType(), + binary_operator}); +} + +void BinaryOpResolver::handle_binary_operation( + internal::BinaryOperationContext bo_ctx) const { + using enum clang::BinaryOperator::Opcode; + + bool is_int = bo_ctx.result_type->isIntegralOrEnumerationType(); + bool is_ref = bo_ctx.result_type->isReferenceType(); + bool is_ptr = bo_ctx.result_type->isPointerType(); + if (is_ref) { + handle_ref_binary_operation(bo_ctx); + } + if (is_ptr) { + handle_ptr_binary_operation(bo_ctx); + } + if (is_int) { + handle_int_binary_operation(bo_ctx); + return; + } + knight_log(llvm::outs() << "not int type binary operation!\n"); +} + +void BinaryOpResolver::handle_assign_binary_operation( + internal::BinaryOperationContext bo_ctx) const { + auto state = m_ctx->get_state(); + auto& sym_mgr = m_ctx->get_symbol_manager(); + internal::ExprRef lhs_expr = *bo_ctx.lhs_expr; + auto rhs_expr_opt = bo_ctx.rhs_expr; + auto op = bo_ctx.op; + + knight_assert_msg(clang::BinaryOperator::isAssignmentOp(op), + "shall be assign op here."); + + bool is_direct_assign = !clang::BinaryOperator::isCompoundAssignmentOp(op); + SExprRef lhs_sexpr = + is_direct_assign + ? sym_mgr.get_symbol_conjured(lhs_expr, + m_ctx->get_current_stack_frame()) + : state->get_stmt_sexpr(lhs_expr, m_ctx->get_current_stack_frame()) + .value_or(nullptr); + if (lhs_sexpr == nullptr) { + knight_log(llvm::outs() << "lhs_sexpr is null!\n"); + return; + } + + SExprRef rhs_sexpr = + rhs_expr_opt ? state->get_stmt_sexpr_or_conjured( + *rhs_expr_opt, m_ctx->get_current_location_context()) + : *bo_ctx.rhs_sexpr; + + knight_log_nl(llvm::outs() << "lhs_sexpr: "; lhs_sexpr->dump(llvm::outs()); + llvm::outs() << "\nrhs_sexpr: "; + rhs_sexpr->dump(llvm::outs()); + llvm::outs() << "\n";); + + auto treg = state->get_region(lhs_expr, m_ctx->get_current_stack_frame()); + std::optional< const clang::Stmt* > stmt = + treg ? std::nullopt : std::make_optional(bo_ctx.result_stmt); + AssignResolver resolver(m_ctx, m_sym_resolver); + m_ctx->set_state(resolver.resolve(internal::AssignmentContext{treg, + stmt, + rhs_expr_opt, + lhs_sexpr, + rhs_sexpr, + op})); +} + +void BinaryOpResolver::handle_int_non_assign_binary_operation( + internal::BinaryOperationContext bo_ctx) const { + auto state = m_ctx->get_state(); + auto& sym_mgr = m_ctx->get_symbol_manager(); + + auto lhs_expr = bo_ctx.lhs_expr; + auto rhs_expr = bo_ctx.rhs_expr; + + auto op = bo_ctx.op; + knight_assert_msg(!clang::BinaryOperator::isAssignmentOp(op), + "cannot be assign op here."); + + SExprRef lhs_sexpr = + lhs_expr ? state->get_stmt_sexpr_or_conjured( + *lhs_expr, m_ctx->get_current_location_context()) + : *bo_ctx.lhs_sexpr; + SExprRef rhs_sexpr = + rhs_expr ? state->get_stmt_sexpr_or_conjured( + *rhs_expr, m_ctx->get_current_location_context()) + : *bo_ctx.rhs_sexpr; + + knight_log_nl(llvm::outs() << "lhs_sexpr: "; lhs_sexpr->dump(llvm::outs()); + llvm::outs() << "\nrhs_sexpr: "; + rhs_sexpr->dump(llvm::outs()); + llvm::outs() << "\n";); + + SExprRef binary_sexpr = sym_mgr.get_binary_sym_expr(lhs_sexpr, + rhs_sexpr, + bo_ctx.op, + bo_ctx.result_type); + knight_log(llvm::outs() << "binary_sexpr: " << *binary_sexpr << "\n"); + + const auto* binary_conjured_sym = + sym_mgr.get_symbol_conjured(bo_ctx.result_stmt, + bo_ctx.result_type, + m_ctx->get_current_stack_frame()); + + ZVariable x(binary_conjured_sym); + + knight_log_nl(llvm::outs() << "zvar x: "; x.dump(llvm::outs()); + llvm::outs() << "\n";); + + ZLinearExpr cstr(x); + auto lhs_var = lhs_sexpr->get_as_zvariable(); + auto lhs_num = lhs_sexpr->get_as_znum(); + auto rhs_var = rhs_sexpr->get_as_zvariable(); + auto rhs_num = rhs_sexpr->get_as_znum(); + if (lhs_var && rhs_var) { + LinearNumericalAssignEvent + event(ZVarAssignBinaryVarVar{op, x, *lhs_var, *rhs_var}, state); + m_sym_resolver->dispatch_event(event); + + cstr -= (*lhs_var + *rhs_var); + } else if ((lhs_var && rhs_num) || (lhs_num && rhs_var)) { + auto y = lhs_var ? *lhs_var : *rhs_var; + auto z = lhs_var ? *rhs_num : *lhs_num; + LinearNumericalAssignEvent event(ZVarAssignBinaryVarNum{op, x, y, z}, + state); + m_sym_resolver->dispatch_event(event); + + cstr -= (y + z); + } else if (auto zexpr = binary_sexpr->get_as_zexpr()) { + if (auto znum = binary_sexpr->get_as_znum()) { + LinearNumericalAssignEvent event(ZVarAssignZNum{x, *znum}, state); + m_sym_resolver->dispatch_event(event); + + binary_sexpr = sym_mgr.get_scalar_int(*znum, bo_ctx.result_type); + cstr -= *znum; + } else if (auto zvar = binary_sexpr->get_as_zvariable()) { + LinearNumericalAssignEvent event(ZVarAssignZVar{x, *zvar}, state); + m_sym_resolver->dispatch_event(event); + + cstr -= *zvar; + } else { + LinearNumericalAssignEvent event(ZVarAssignZLinearExpr{x, *zexpr}, + state); + m_sym_resolver->dispatch_event(event); + + cstr -= *zexpr; + } + state = state->add_zlinear_constraint( + ZLinearConstraint(cstr, LinearConstraintKind::LCK_Equality)); + } + + knight_log(llvm::outs() + << "binary sexpr: " << *binary_sexpr << " complexity: " + << binary_sexpr->get_worst_complexity() << "\n"); + + if (binary_sexpr->get_worst_complexity() > 1U) { + state = state->set_stmt_sexpr(bo_ctx.result_stmt, + m_ctx->get_current_stack_frame(), + binary_conjured_sym); + + knight_log_nl(llvm::outs() << "set binary conjured: "; + binary_conjured_sym->dump(llvm::outs()); + llvm::outs() << "\n"); + } else { + state = state->set_stmt_sexpr(bo_ctx.result_stmt, + m_ctx->get_current_stack_frame(), + binary_sexpr); + + knight_log_nl(llvm::outs() << "set binary binary_sexpr: "; + binary_sexpr->dump(llvm::outs()); + llvm::outs() << "\n"); + } + knight_log(llvm::outs() + << "after transfer binary here state: " << *state << "\n"); + + m_ctx->set_state(state); +} + +void BinaryOpResolver::handle_int_binary_operation( + internal::BinaryOperationContext bo_ctx) const { + auto op = bo_ctx.op; + if (clang::BinaryOperator::isAssignmentOp(op)) { + handle_assign_binary_operation(bo_ctx); + } else { + handle_int_non_assign_binary_operation(bo_ctx); + } +} + +void BinaryOpResolver::handle_ref_binary_operation( + internal::BinaryOperationContext bo_ctx) const { + // TODO(ref-binary-op): handle ref binary operation. +} + +void BinaryOpResolver::handle_ptr_binary_operation( + internal::BinaryOperationContext bo_ctx) const { + // TODO(ptr-binary-op): handle ptr binary operation. + auto op = bo_ctx.op; + if (clang::BinaryOperator::isAssignmentOp(op)) { + handle_assign_binary_operation(bo_ctx); + } +} + +} // namespace knight::dfa \ No newline at end of file diff --git a/src/dfa/analysis/core/symbol_resolver.cpp b/src/dfa/analysis/core/symbol_resolver.cpp index bd46f1e..9239aad 100644 --- a/src/dfa/analysis/core/symbol_resolver.cpp +++ b/src/dfa/analysis/core/symbol_resolver.cpp @@ -12,7 +12,10 @@ //===------------------------------------------------------------------===// #include "dfa/analysis/core/symbol_resolver.hpp" +#include "dfa/analysis/core/assign_resolver.hpp" +#include "dfa/analysis/core/binary_op_resolver.hpp" #include "dfa/analysis/core/numerical_event.hpp" +#include "dfa/analysis/core/unary_op_resolver.hpp" #include "dfa/analysis_manager.hpp" #include "dfa/constraint/linear.hpp" #include "dfa/program_state.hpp" @@ -105,502 +108,14 @@ void SymbolResolver::VisitIntegerLiteral( void SymbolResolver::VisitUnaryOperator( const clang::UnaryOperator* unary_operator) const { - auto type = unary_operator->getType(); - if (type->isIntegralOrEnumerationType()) { - handle_int_unary_operation(unary_operator); - return; - } - if (type->isPointerType()) { - handle_ptr_unary_operation(unary_operator); - return; - } - knight_log(llvm::outs() << "unhandled unary operator type: " << type); -} - -void SymbolResolver::handle_ptr_unary_operation( - const clang::UnaryOperator* unary_operator) const { - auto type = unary_operator->getType(); - auto state = m_ctx->get_state(); - auto* operand_expr = unary_operator->getSubExpr(); - SExprRef operand_sexpr = - state - ->get_stmt_sexpr_or_conjured(operand_expr, - m_ctx->get_current_location_context()); - auto& sym_mgr = m_ctx->get_symbol_manager(); - auto unary_op = unary_operator->getOpcode(); - switch (unary_op) { - using enum clang::UnaryOperatorKind; - case clang::UO_AddrOf: { - // TODO (stmt-pt, region-pt) - auto treg = state->get_region(operand_expr, - m_ctx->get_current_stack_frame()); - if (!treg) { - auto treg = operand_sexpr->get_as_region(); - } - if (treg) { - const auto* reg_addr_val = sym_mgr.get_scalar_region(*treg); - state = state->set_stmt_sexpr(unary_operator, - m_ctx->get_current_stack_frame(), - reg_addr_val); - knight_log_nl( - llvm::outs() << "set addr of: "; - operand_expr->printPretty(llvm::outs(), - nullptr, - m_ctx->get_ast_context() - .getPrintingPolicy()); - llvm::outs() << " to region: "; - treg.value()->dump(llvm::outs()); - llvm::outs() << " to scalar: "; - reg_addr_val->dump(llvm::outs()); - llvm::outs() << "\n";); - } - } break; - default: - break; - } -} - -void SymbolResolver::handle_int_unary_operation( - const clang::UnaryOperator* unary_operator) const { - auto type = unary_operator->getType(); - auto state = m_ctx->get_state(); - auto* operand_expr = unary_operator->getSubExpr(); - auto& sym_mgr = m_ctx->get_symbol_manager(); - auto unary_op = unary_operator->getOpcode(); - switch (unary_op) { - using enum clang::UnaryOperatorKind; - case clang::UO_LNot: { - handle_binary_operation( - BinaryOperationContext{clang::BO_EQ, - std::nullopt, - sym_mgr.get_scalar_int(ZNum(0), type), - operand_expr, - std::nullopt, - unary_operator->getType(), - unary_operator}); - return; - } - case clang::UO_Plus: - [[fallthrough]]; - case clang::UO_Minus: { - handle_binary_operation( - BinaryOperationContext{unary_op == UO_Plus ? clang::BO_Add - : clang::BO_Sub, - std::nullopt, - sym_mgr.get_scalar_int(ZNum(0), type), - operand_expr, - std::nullopt, - unary_operator->getType(), - unary_operator}); - return; - } break; - case clang::UO_PostInc: - [[fallthrough]]; - case clang::UO_PreInc: { - handle_binary_operation( - BinaryOperationContext{clang::BO_AddAssign, - operand_expr, - std::nullopt, - std::nullopt, - sym_mgr.get_scalar_int(ZNum(1), type), - unary_operator->getType(), - unary_operator}); - return; - } - case clang::UO_PostDec: - [[fallthrough]]; - case clang::UO_PreDec: { - handle_binary_operation( - BinaryOperationContext{clang::BO_SubAssign, - operand_expr, - std::nullopt, - std::nullopt, - sym_mgr.get_scalar_int(ZNum(1), type), - unary_operator->getType(), - unary_operator}); - return; - } - default: - break; - } -} - -void SymbolResolver::handle_ptr_assign(AssignmentContext assign_ctx, - SymbolRef res_sym, - bool is_direct_assign, - clang::BinaryOperator::Opcode op, - ProgramStateRef& state, - SExprRef& binary_sexpr) const { - auto type = assign_ctx.rhs_sexpr->get_type(); - auto& sym_mgr = m_ctx->get_symbol_manager(); - if (!is_direct_assign) { - knight_unreachable("indirect ptr assign not supported yet"); - (void)op; - } - auto region_def = llvm::dyn_cast< RegionSymVal >(binary_sexpr); - auto region_addr_val = llvm::dyn_cast< ScalarRegion >(binary_sexpr); -} - -void SymbolResolver::handle_int_assign(AssignmentContext assign_ctx, - SymbolRef res_sym, - bool is_direct_assign, - clang::BinaryOperator::Opcode op, - ProgramStateRef& state, - SExprRef& binary_sexpr) const { - auto type = assign_ctx.rhs_sexpr->get_type(); - auto& sym_mgr = m_ctx->get_symbol_manager(); - ZVariable x(res_sym); - - ZLinearExpr cstr; - cstr += x; - - knight_log_nl(llvm::outs() << "zvar x: "; x.dump(llvm::outs()); - llvm::outs() << "\n";); - auto lhs_var = assign_ctx.lhs_sexpr != nullptr - ? assign_ctx.lhs_sexpr->get_as_zvariable() - : std::nullopt; - auto lhs_num = assign_ctx.lhs_sexpr != nullptr - ? assign_ctx.lhs_sexpr->get_as_znum() - : std::nullopt; - auto rhs_var = assign_ctx.rhs_sexpr->get_as_zvariable(); - auto rhs_num = assign_ctx.rhs_sexpr->get_as_znum(); - if (!is_direct_assign && lhs_var && rhs_var) { - LinearNumericalAssignEvent - event(ZVarAssignBinaryVarVar{op, x, *lhs_var, *rhs_var}, state); - dispatch_event(event); - - cstr -= (*lhs_var + *rhs_var); - } else if (!is_direct_assign && - ((lhs_var && rhs_num) || (lhs_num && rhs_var))) { - auto y = lhs_var ? *lhs_var : *rhs_var; - auto z = lhs_var ? *rhs_num : *lhs_num; - LinearNumericalAssignEvent event(ZVarAssignBinaryVarNum{op, x, y, z}, - state); - dispatch_event(event); - - cstr -= (y + z); - } else if (auto zexpr = binary_sexpr->get_as_zexpr()) { - if (auto znum = binary_sexpr->get_as_znum()) { - LinearNumericalAssignEvent event(ZVarAssignZNum{x, *znum}, state); - dispatch_event(event); - - binary_sexpr = sym_mgr.get_scalar_int(*znum, type); - cstr -= *znum; - } else if (auto zvar = binary_sexpr->get_as_zvariable()) { - LinearNumericalAssignEvent event(ZVarAssignZVar{x, *zvar}, state); - dispatch_event(event); - - cstr -= *zvar; - } else { - LinearNumericalAssignEvent event(ZVarAssignZLinearExpr{x, *zexpr}, - state); - dispatch_event(event); - - cstr -= *zexpr; - } - } else if (auto rhs_expr = assign_ctx.rhs_expr) { - ZVariable y( - sym_mgr.get_symbol_conjured(*rhs_expr, - m_ctx->get_current_stack_frame())); - LinearNumericalAssignEvent event(ZVarAssignZVar{x, y}, state); - dispatch_event(event); - cstr -= y; - } else { - knight_log(llvm::outs() << "unhandled case!\n"); - return; - } - state = state->add_zlinear_constraint( - ZLinearConstraint(cstr, LinearConstraintKind::LCK_Equality)); -} - -ProgramStateRef SymbolResolver::handle_assign( - AssignmentContext assign_ctx) const { - auto op = assign_ctx.op; - bool is_direct_assign = !clang::BinaryOperator::isCompoundAssignmentOp(op); - - knight_assert_msg(assign_ctx.rhs_sexpr != nullptr, - "rhs sexpr shall be nonnull in assignment context"); - knight_assert_msg(assign_ctx.lhs_sexpr != nullptr || is_direct_assign, - "lhs sexpr shall be nonnull in indirect assignment " - "context"); - knight_assert_msg((!assign_ctx.stmt && assign_ctx.treg) || - (assign_ctx.stmt && !assign_ctx.treg), - "either stmt or treg should be set in assignment " - "context"); - - auto state = m_ctx->get_state(); - auto& sym_mgr = m_ctx->get_symbol_manager(); - auto type = assign_ctx.rhs_sexpr->get_type(); - SExprRef binary_sexpr = nullptr; - if (is_direct_assign) { - binary_sexpr = assign_ctx.rhs_sexpr; - } else { - op = clang::BinaryOperator::getOpForCompoundAssignment(op); - binary_sexpr = sym_mgr.get_binary_sym_expr(assign_ctx.lhs_sexpr, - assign_ctx.rhs_sexpr, - op, - type); - } - - SymbolRef res_sym = nullptr; - if (assign_ctx.treg) { - res_sym = - sym_mgr.get_region_sym_val(*assign_ctx.treg, - m_ctx->get_current_location_context()); - } else { - res_sym = sym_mgr.get_symbol_conjured(*assign_ctx.stmt, - type, - m_ctx->get_current_stack_frame()); - } - - knight_log_nl( - llvm::outs() << "lhs_sexpr: "; if (assign_ctx.lhs_sexpr != nullptr) { - assign_ctx.lhs_sexpr->dump(llvm::outs()); - } else { - llvm::outs() << "nullptr"; - } llvm::outs() << "\nrhs_sexpr: " - << *assign_ctx.rhs_sexpr << "\n"; - llvm::outs() << "binary_sexpr: " << *binary_sexpr << "\n";); - - if (type->isPointerType()) { - handle_ptr_assign(assign_ctx, - res_sym, - is_direct_assign, - op, - state, - binary_sexpr); - } else if (type->isIntegralOrEnumerationType()) { - handle_int_assign(assign_ctx, - res_sym, - is_direct_assign, - op, - state, - binary_sexpr); - } - - if (assign_ctx.treg) { - knight_log_nl(llvm::outs() << "\nset region: "; - assign_ctx.treg.value()->dump(llvm::outs()); - llvm::outs() << " to new_def: "; - res_sym->dump(llvm::outs()); - llvm::outs() << "\n"); - - state = state->set_region_def(*assign_ctx.treg, - m_ctx->get_current_stack_frame(), - cast< RegionSymVal >(res_sym)); - } else { - state = state->set_stmt_sexpr(*assign_ctx.stmt, - m_ctx->get_current_stack_frame(), - res_sym); - } - - return state; + UnaryOpResolver resolver(m_ctx, this); + resolver.resolve(unary_operator); } void SymbolResolver::VisitBinaryOperator( const clang::BinaryOperator* binary_operator) const { - handle_binary_operation(BinaryOperationContext{binary_operator->getOpcode(), - binary_operator->getLHS(), - std::nullopt, - binary_operator->getRHS(), - std::nullopt, - binary_operator->getType(), - binary_operator}); -} - -void SymbolResolver::handle_binary_operation( - BinaryOperationContext bo_ctx) const { - using enum clang::BinaryOperator::Opcode; - - bool is_int = bo_ctx.result_type->isIntegralOrEnumerationType(); - bool is_ref = bo_ctx.result_type->isReferenceType(); - bool is_ptr = bo_ctx.result_type->isPointerType(); - if (is_ref) { - handle_ref_binary_operation(bo_ctx); - } - if (is_ptr) { - handle_ptr_binary_operation(bo_ctx); - } - if (is_int) { - handle_int_binary_operation(bo_ctx); - return; - } - knight_log(llvm::outs() << "not int type binary operation!\n"); -} - -void SymbolResolver::handle_assign_binary_operation( - BinaryOperationContext bo_ctx) const { - auto state = m_ctx->get_state(); - auto& sym_mgr = m_ctx->get_symbol_manager(); - internal::ExprRef lhs_expr = *bo_ctx.lhs_expr; - auto rhs_expr_opt = bo_ctx.rhs_expr; - auto op = bo_ctx.op; - - knight_assert_msg(clang::BinaryOperator::isAssignmentOp(op), - "shall be assign op here."); - - bool is_direct_assign = !clang::BinaryOperator::isCompoundAssignmentOp(op); - SExprRef lhs_sexpr = - is_direct_assign - ? sym_mgr.get_symbol_conjured(lhs_expr, - m_ctx->get_current_stack_frame()) - : state->get_stmt_sexpr(lhs_expr, m_ctx->get_current_stack_frame()) - .value_or(nullptr); - if (lhs_sexpr == nullptr) { - knight_log(llvm::outs() << "lhs_sexpr is null!\n"); - return; - } - - SExprRef rhs_sexpr = - rhs_expr_opt ? state->get_stmt_sexpr_or_conjured( - *rhs_expr_opt, m_ctx->get_current_location_context()) - : *bo_ctx.rhs_sexpr; - - knight_log_nl(llvm::outs() << "lhs_sexpr: "; lhs_sexpr->dump(llvm::outs()); - llvm::outs() << "\nrhs_sexpr: "; - rhs_sexpr->dump(llvm::outs()); - llvm::outs() << "\n";); - - auto treg = state->get_region(lhs_expr, m_ctx->get_current_stack_frame()); - std::optional< const clang::Stmt* > stmt = - treg ? std::nullopt : std::make_optional(bo_ctx.result_stmt); - m_ctx->set_state(handle_assign( - AssignmentContext{treg, stmt, rhs_expr_opt, lhs_sexpr, rhs_sexpr, op})); -} - -void SymbolResolver::handle_int_non_assign_binary_operation( - BinaryOperationContext bo_ctx) const { - auto state = m_ctx->get_state(); - auto& sym_mgr = m_ctx->get_symbol_manager(); - - auto lhs_expr = bo_ctx.lhs_expr; - auto rhs_expr = bo_ctx.rhs_expr; - - auto op = bo_ctx.op; - knight_assert_msg(!clang::BinaryOperator::isAssignmentOp(op), - "cannot be assign op here."); - - SExprRef lhs_sexpr = - lhs_expr ? state->get_stmt_sexpr_or_conjured( - *lhs_expr, m_ctx->get_current_location_context()) - : *bo_ctx.lhs_sexpr; - SExprRef rhs_sexpr = - rhs_expr ? state->get_stmt_sexpr_or_conjured( - *rhs_expr, m_ctx->get_current_location_context()) - : *bo_ctx.rhs_sexpr; - - knight_log_nl(llvm::outs() << "lhs_sexpr: "; lhs_sexpr->dump(llvm::outs()); - llvm::outs() << "\nrhs_sexpr: "; - rhs_sexpr->dump(llvm::outs()); - llvm::outs() << "\n";); - - SExprRef binary_sexpr = sym_mgr.get_binary_sym_expr(lhs_sexpr, - rhs_sexpr, - bo_ctx.op, - bo_ctx.result_type); - knight_log(llvm::outs() << "binary_sexpr: " << *binary_sexpr << "\n"); - - const auto* binary_conjured_sym = - sym_mgr.get_symbol_conjured(bo_ctx.result_stmt, - bo_ctx.result_type, - m_ctx->get_current_stack_frame()); - - ZVariable x(binary_conjured_sym); - - knight_log_nl(llvm::outs() << "zvar x: "; x.dump(llvm::outs()); - llvm::outs() << "\n";); - - ZLinearExpr cstr(x); - auto lhs_var = lhs_sexpr->get_as_zvariable(); - auto lhs_num = lhs_sexpr->get_as_znum(); - auto rhs_var = rhs_sexpr->get_as_zvariable(); - auto rhs_num = rhs_sexpr->get_as_znum(); - if (lhs_var && rhs_var) { - LinearNumericalAssignEvent - event(ZVarAssignBinaryVarVar{op, x, *lhs_var, *rhs_var}, state); - dispatch_event< LinearNumericalAssignEvent >(event); - - cstr -= (*lhs_var + *rhs_var); - } else if ((lhs_var && rhs_num) || (lhs_num && rhs_var)) { - auto y = lhs_var ? *lhs_var : *rhs_var; - auto z = lhs_var ? *rhs_num : *lhs_num; - LinearNumericalAssignEvent event(ZVarAssignBinaryVarNum{op, x, y, z}, - state); - dispatch_event(event); - - cstr -= (y + z); - } else if (auto zexpr = binary_sexpr->get_as_zexpr()) { - if (auto znum = binary_sexpr->get_as_znum()) { - LinearNumericalAssignEvent event(ZVarAssignZNum{x, *znum}, state); - dispatch_event(event); - - binary_sexpr = sym_mgr.get_scalar_int(*znum, bo_ctx.result_type); - cstr -= *znum; - } else if (auto zvar = binary_sexpr->get_as_zvariable()) { - LinearNumericalAssignEvent event(ZVarAssignZVar{x, *zvar}, state); - dispatch_event(event); - - cstr -= *zvar; - } else { - LinearNumericalAssignEvent event(ZVarAssignZLinearExpr{x, *zexpr}, - state); - dispatch_event(event); - - cstr -= *zexpr; - } - state = state->add_zlinear_constraint( - ZLinearConstraint(cstr, LinearConstraintKind::LCK_Equality)); - } - - knight_log(llvm::outs() - << "binary sexpr: " << *binary_sexpr << " complexity: " - << binary_sexpr->get_worst_complexity() << "\n"); - - if (binary_sexpr->get_worst_complexity() > 1U) { - state = state->set_stmt_sexpr(bo_ctx.result_stmt, - m_ctx->get_current_stack_frame(), - binary_conjured_sym); - - knight_log_nl(llvm::outs() << "set binary conjured: "; - binary_conjured_sym->dump(llvm::outs()); - llvm::outs() << "\n"); - } else { - state = state->set_stmt_sexpr(bo_ctx.result_stmt, - m_ctx->get_current_stack_frame(), - binary_sexpr); - - knight_log_nl(llvm::outs() << "set binary binary_sexpr: "; - binary_sexpr->dump(llvm::outs()); - llvm::outs() << "\n"); - } - knight_log(llvm::outs() - << "after transfer binary here state: " << *state << "\n"); - - m_ctx->set_state(state); -} - -void SymbolResolver::handle_int_binary_operation( - BinaryOperationContext bo_ctx) const { - auto op = bo_ctx.op; - if (clang::BinaryOperator::isAssignmentOp(op)) { - handle_assign_binary_operation(bo_ctx); - } else { - handle_int_non_assign_binary_operation(bo_ctx); - } -} - -void SymbolResolver::handle_ref_binary_operation( - BinaryOperationContext bo_ctx) const { - // TODO(ref-binary-op): handle ref binary operation. -} - -void SymbolResolver::handle_ptr_binary_operation( - BinaryOperationContext bo_ctx) const { - // TODO(ptr-binary-op): handle ptr binary operation. - auto op = bo_ctx.op; - if (clang::BinaryOperator::isAssignmentOp(op)) { - handle_assign_binary_operation(bo_ctx); - } + BinaryOpResolver resolver(m_ctx, this); + resolver.resolve(binary_operator); } void SymbolResolver::VisitConditionalOperator( @@ -627,23 +142,24 @@ void SymbolResolver::handle_int_cond_op( ->get_stmt_sexpr_or_conjured(false_expr, m_ctx->get_current_location_context()); - auto state_with_true_br = - handle_assign(AssignmentContext{std::nullopt, - conditional_operator, - true_expr, - nullptr, - true_sexpr}); + AssignResolver assign_resolver(m_ctx, this); + ProgramStateRef state_with_true_br = assign_resolver.resolve( + internal::AssignmentContext{std::nullopt, + conditional_operator, + true_expr, + nullptr, + true_sexpr}); knight_log_nl(llvm::outs() << "true branch state: "; state_with_true_br->dump(llvm::outs()); llvm::outs() << "\n";); - auto state_with_false_br = - handle_assign(AssignmentContext{std::nullopt, - conditional_operator, - false_expr, - nullptr, - false_sexpr}); + auto state_with_false_br = assign_resolver.resolve( + internal::AssignmentContext{std::nullopt, + conditional_operator, + false_expr, + nullptr, + false_sexpr}); knight_log_nl(llvm::outs() << "false branch state: "; state_with_false_br->dump(llvm::outs()); @@ -680,11 +196,13 @@ void SymbolResolver::handle_var_decl(const clang::VarDecl* var_decl, if (type->isPointerType()) { } if (type->isIntegralOrEnumerationType()) { - state = handle_assign(AssignmentContext{treg, - std::nullopt, - init_expr, - nullptr, - init_sexpr_opt.value()}); + AssignResolver assign_resolver(m_ctx, this); + state = assign_resolver.resolve( + internal::AssignmentContext{treg, + std::nullopt, + init_expr, + nullptr, + init_sexpr_opt.value()}); init_sexpr_opt = state->get_stmt_sexpr_or_conjured( init_expr, m_ctx->get_current_location_context()); diff --git a/src/dfa/analysis/core/unary_op_resolver.cpp b/src/dfa/analysis/core/unary_op_resolver.cpp new file mode 100644 index 0000000..08da07a --- /dev/null +++ b/src/dfa/analysis/core/unary_op_resolver.cpp @@ -0,0 +1,153 @@ +//===- unary_op_resolver.cpp ------------------------------------------===// +// +// Copyright (c) 2024 Junjie Shen +// +// see https://github.com/shenjunjiekoda/knight/blob/main/LICENSE for +// license information. +// +//===------------------------------------------------------------------===// +// +// This header implements the uanry op resolver. +// +//===------------------------------------------------------------------===// + +#include "dfa/analysis/core/unary_op_resolver.hpp" +#include "dfa/analysis/core/binary_op_resolver.hpp" +#include "util/log.hpp" + +#define DEBUG_TYPE "unary_op_resolver" + +namespace knight::dfa { + +void UnaryOpResolver::resolve( + const clang::UnaryOperator* unary_operator) const { + auto type = unary_operator->getType(); + if (type->isIntegralOrEnumerationType()) { + handle_int_unary_operation(unary_operator); + return; + } + if (type->isPointerType()) { + handle_ptr_unary_operation(unary_operator); + return; + } + knight_log(llvm::outs() << "unhandled unary operator type: " << type); +} + +void UnaryOpResolver::handle_ptr_unary_operation( + const clang::UnaryOperator* unary_operator) const { + auto type = unary_operator->getType(); + auto state = m_ctx->get_state(); + auto* operand_expr = unary_operator->getSubExpr(); + SExprRef operand_sexpr = + state + ->get_stmt_sexpr_or_conjured(operand_expr, + m_ctx->get_current_location_context()); + auto& sym_mgr = m_ctx->get_symbol_manager(); + auto unary_op = unary_operator->getOpcode(); + switch (unary_op) { + using enum clang::UnaryOperatorKind; + case clang::UO_AddrOf: { + // TODO (stmt-pt, region-pt) + auto treg = state->get_region(operand_expr, + m_ctx->get_current_stack_frame()); + if (!treg) { + auto treg = operand_sexpr->get_as_region(); + } + if (treg) { + const auto* reg_addr_val = sym_mgr.get_region_addr(*treg); + state = state->set_stmt_sexpr(unary_operator, + m_ctx->get_current_stack_frame(), + reg_addr_val); + knight_log_nl( + llvm::outs() << "set addr of: "; + operand_expr->printPretty(llvm::outs(), + nullptr, + m_ctx->get_ast_context() + .getPrintingPolicy()); + llvm::outs() << " to region: "; + treg.value()->dump(llvm::outs()); + llvm::outs() << " to scalar: "; + reg_addr_val->dump(llvm::outs()); + llvm::outs() << "\n";); + } + } break; + default: + break; + } +} + +void UnaryOpResolver::handle_int_unary_operation( + const clang::UnaryOperator* unary_operator) const { + auto type = unary_operator->getType(); + auto state = m_ctx->get_state(); + auto* operand_expr = unary_operator->getSubExpr(); + auto& sym_mgr = m_ctx->get_symbol_manager(); + auto unary_op = unary_operator->getOpcode(); + switch (unary_op) { + using enum clang::UnaryOperatorKind; + case clang::UO_LNot: { + BinaryOpResolver resolver(m_ctx, m_sym_resolver); + resolver.handle_binary_operation( + internal::BinaryOperationContext{clang::BO_EQ, + std::nullopt, + sym_mgr.get_scalar_int(ZNum(0), + type), + operand_expr, + std::nullopt, + unary_operator->getType(), + unary_operator}); + return; + } + case clang::UO_Plus: + [[fallthrough]]; + case clang::UO_Minus: { + BinaryOpResolver resolver(m_ctx, m_sym_resolver); + resolver.handle_binary_operation( + internal::BinaryOperationContext{unary_op == UO_Plus + ? clang::BO_Add + : clang::BO_Sub, + std::nullopt, + sym_mgr.get_scalar_int(ZNum(0), + type), + operand_expr, + std::nullopt, + unary_operator->getType(), + unary_operator}); + return; + } break; + case clang::UO_PostInc: + [[fallthrough]]; + case clang::UO_PreInc: { + BinaryOpResolver resolver(m_ctx, m_sym_resolver); + resolver.handle_binary_operation( + internal::BinaryOperationContext{clang::BO_AddAssign, + operand_expr, + std::nullopt, + std::nullopt, + sym_mgr.get_scalar_int(ZNum(1), + type), + unary_operator->getType(), + unary_operator}); + return; + } + case clang::UO_PostDec: + [[fallthrough]]; + case clang::UO_PreDec: { + BinaryOpResolver resolver(m_ctx, m_sym_resolver); + resolver.handle_binary_operation( + internal::BinaryOperationContext{clang::BO_SubAssign, + operand_expr, + std::nullopt, + std::nullopt, + sym_mgr.get_scalar_int(ZNum(1), + type), + unary_operator->getType(), + unary_operator}); + return; + } + default: + break; + } +} + +} // namespace knight::dfa \ No newline at end of file diff --git a/src/dfa/program_state.cpp b/src/dfa/program_state.cpp index 5924fb1..8d90cba 100644 --- a/src/dfa/program_state.cpp +++ b/src/dfa/program_state.cpp @@ -137,7 +137,7 @@ std::optional< RegionRef > ProgramState::get_region( ProgramStateRef ProgramState::set_region_def(RegionRef region, const StackFrame* frame, - const RegionSymVal* def) const { + const RegionDef* def) const { auto region_defs = m_region_defs; region_defs[{region, frame}] = def; return get_state_manager() @@ -160,7 +160,7 @@ ProgramStateRef ProgramState::set_constraint_system( cst_system); } -std::optional< const RegionSymVal* > ProgramState::get_region_def( +std::optional< const RegionDef* > ProgramState::get_region_def( RegionRef region, const StackFrame* frame) const { auto it = m_region_defs.find({region, frame}); if (it != m_region_defs.end()) { @@ -168,8 +168,7 @@ std::optional< const RegionSymVal* > ProgramState::get_region_def( } if (region->get_memory_space()->is_stack_arg()) { return get_state_manager() - .m_symbol_mgr.get_region_sym_val(region, - frame->get_entry_location()); + .m_symbol_mgr.get_region_def(region, frame->get_entry_location()); } return std::nullopt; } @@ -209,8 +208,7 @@ SExprRef ProgramState::get_stmt_sexpr_or_conjured( } if (region_opt) { - return m_state_mgr->m_symbol_mgr.get_region_sym_val(*region_opt, - loc_ctx); + return m_state_mgr->m_symbol_mgr.get_region_def(*region_opt, loc_ctx); } return m_state_mgr->m_symbol_mgr.get_symbol_conjured(stmt, type, frame); @@ -276,8 +274,8 @@ ProgramStateRef ProgramState::set_to_top() const { }); \ \ RegionDefMap region_defs = m_region_defs; \ - std::map< const RegionSymVal*, \ - std::pair< const RegionSymVal*, const RegionSymVal* > > \ + std::map< const RegionDef*, \ + std::pair< const RegionDef*, const RegionDef* > > \ new_zregion_def; \ for (const auto [region_frame_pair, def] : other->m_region_defs) { \ auto it = region_defs.find(region_frame_pair); \ @@ -292,8 +290,8 @@ ProgramStateRef ProgramState::set_to_top() const { region->dump(llvm::outs());); \ \ const auto* new_def = \ - get_state_manager().m_symbol_mgr.get_region_sym_val(region, \ - loc_ctx); \ + get_state_manager().m_symbol_mgr.get_region_def(region, \ + loc_ctx); \ \ if (region->get_value_type()->isIntegralOrEnumerationType()) { \ new_zregion_def[new_def] = {it->second, def}; \ @@ -396,8 +394,8 @@ ProgramStateRef ProgramState::join(const ProgramStateRef& other, }); RegionDefMap region_defs = m_region_defs; - std::map< const RegionSymVal*, - std::pair< const RegionSymVal*, const RegionSymVal* > > + std::map< const RegionDef*, + std::pair< const RegionDef*, const RegionDef* > > new_zregion_def; for (const auto [region_frame_pair, def] : other->m_region_defs) { auto it = region_defs.find(region_frame_pair); @@ -412,8 +410,8 @@ ProgramStateRef ProgramState::join(const ProgramStateRef& other, region->dump(llvm::outs());); const auto* new_def = - get_state_manager().m_symbol_mgr.get_region_sym_val(region, - loc_ctx); + get_state_manager().m_symbol_mgr.get_region_def(region, + loc_ctx); if (region->get_value_type()->isIntegralOrEnumerationType()) { new_zregion_def[new_def] = {it->second, def}; @@ -542,8 +540,8 @@ ProgramStateRef ProgramState::widen_with_threshold( }); RegionDefMap region_defs = m_region_defs; - std::map< const RegionSymVal*, - std::pair< const RegionSymVal*, const RegionSymVal* > > + std::map< const RegionDef*, + std::pair< const RegionDef*, const RegionDef* > > new_zregion_def; for (const auto [region_frame_pair, def] : other->m_region_defs) { auto it = region_defs.find(region_frame_pair); @@ -558,8 +556,8 @@ ProgramStateRef ProgramState::widen_with_threshold( region->dump(llvm::outs());); const auto* new_def = - get_state_manager().m_symbol_mgr.get_region_sym_val(region, - loc_ctx); + get_state_manager().m_symbol_mgr.get_region_def(region, + loc_ctx); if (region->get_value_type()->isIntegralOrEnumerationType()) { new_zregion_def[new_def] = {it->second, def}; diff --git a/src/dfa/symbol.cpp b/src/dfa/symbol.cpp index d258026..199ce1d 100644 --- a/src/dfa/symbol.cpp +++ b/src/dfa/symbol.cpp @@ -87,7 +87,7 @@ const Sym* SymIterator::operator*() { } std::optional< RegionRef > SymExpr::get_as_region() const { - if (const auto* reg_sym = dyn_cast< RegionSymVal >(this)) { + if (const auto* reg_sym = dyn_cast< RegionDef >(this)) { return reg_sym->get_region(); } return std::nullopt; @@ -100,10 +100,10 @@ std::optional< SymbolRef > SymExpr::get_as_symbol() const { return std::nullopt; } -RegionSymVal::RegionSymVal(SymID id, - RegionRef region, - const LocationContext* loc_ctx, - bool is_external) +RegionDef::RegionDef(SymID id, + RegionRef region, + const LocationContext* loc_ctx, + bool is_external) : Sym(id, SymExprKind::RegionSymbolVal), m_loc_ctx(loc_ctx), m_region(region), @@ -113,11 +113,11 @@ RegionSymVal::RegionSymVal(SymID id, "Invalid type for region symbol value"); } -RegionRef RegionSymVal::get_region() const { +RegionRef RegionDef::get_region() const { return m_region; } -void RegionSymVal::dump(llvm::raw_ostream& os) const { +void RegionDef::dump(llvm::raw_ostream& os) const { os << get_kind_name() << get_id() << "<" << get_type() << ' '; get_region()->dump(os); if (auto loc = get_loc_ctx()->get_source_location()) { @@ -132,7 +132,7 @@ void RegionSymVal::dump(llvm::raw_ostream& os) const { os << '>'; } -clang::QualType RegionSymVal::get_type() const { +clang::QualType RegionDef::get_type() const { return get_region()->get_value_type(); } @@ -226,15 +226,15 @@ std::optional< ZLinearExpr > SymExpr::get_as_zexpr() const { return std::nullopt; } -const TypedRegion* ScalarRegion::get_region() const { +const TypedRegion* RegionAddr::get_region() const { return m_region; } -clang::QualType ScalarRegion::get_type() const { +clang::QualType RegionAddr::get_type() const { return m_region->get_value_type(); } -void ScalarRegion::dump(llvm::raw_ostream& os) const { +void RegionAddr::dump(llvm::raw_ostream& os) const { os << "&" << *m_region; }