diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h new file mode 100644 --- /dev/null +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h @@ -0,0 +1,134 @@ +//===- DataflowAnalysis.h ---------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines base types and functions for building dataflow analyses +// that run over Control-Flow Graphs (CFGs). +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWANALYSIS_H +#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWANALYSIS_H + +#include +#include +#include + +#include "clang/AST/ASTContext.h" +#include "clang/AST/Stmt.h" +#include "clang/Analysis/CFG.h" +#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" +#include "clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h" +#include "llvm/ADT/Any.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/STLExtras.h" + +namespace clang { +namespace dataflow { + +/// Base class template for dataflow analyses built on a single lattice type. +/// +/// Requirements: +/// +/// `Derived` must be derived from a specialization of this class template and +/// must provide the following public members: +/// * `LatticeT initialElement()` - returns a lattice element that models the +/// initial state of a basic block; +/// * `LatticeT transfer(const Stmt *, const LatticeT &, Environment &)` - +/// applies the analysis transfer function for a given statement and lattice +/// element. +/// +/// `LatticeT` is a bounded join-semilattice that is used by `Derived` and must +/// provide the following public members: +/// * `LatticeJoinEffect join(const LatticeT &)` - joins the object and the +/// argument by computing their least upper bound, modifies the object if +/// necessary, and returns an effect indicating whether any changes were +/// made to it; +/// * `bool operator==(const LatticeT &) const` - returns true if and only if +/// the object is equal to the argument. +template +class DataflowAnalysis : public TypeErasedDataflowAnalysis { +public: + /// Bounded join-semilattice that is used in the analysis. + using Lattice = LatticeT; + + explicit DataflowAnalysis(ASTContext &Context) : Context(Context) {} + + ASTContext &getASTContext() final { return Context; } + + AnyLatticeElement typeErasedInitialElement() final { + return {static_cast(this)->initialElement()}; + } + + LatticeJoinEffect joinTypeErased(TypeErasedLattice &E1, + const TypeErasedLattice &E2) final { + Lattice &L1 = llvm::any_cast(E1.Value); + const Lattice &L2 = llvm::any_cast(E2.Value); + return L1.join(L2); + } + + bool isEqualTypeErased(const TypeErasedLattice &E1, + const TypeErasedLattice &E2) final { + const Lattice &L1 = llvm::any_cast(E1.Value); + const Lattice &L2 = llvm::any_cast(E2.Value); + return L1 == L2; + } + + AnyLatticeElement transferTypeErased(const Stmt *Stmt, + const AnyLatticeElement &E, + Environment &Env) final { + const Lattice &L = llvm::any_cast(E.Value); + return {static_cast(this)->transfer(Stmt, L, Env)}; + } + +private: + ASTContext &Context; +}; + +// Model of the program at a given program point. +template struct DataflowAnalysisState { + // Model of a program property. + LatticeT Lattice; + + // Model of the state of the program (store and heap). + Environment Env; +}; + +/// Performs dataflow analysis and returns a mapping from basic block IDs to +/// dataflow analysis states that model the respective basic blocks. Indices +/// of the returned vector correspond to basic block IDs. +/// +/// Requirements: +/// +/// `Cfg` must have been built with `CFG::BuildOptions::setAllAlwaysAdd()` to +/// ensure that all sub-expressions in a basic block are evaluated. +template +std::vector>> +runDataflowAnalysis(const CFG &Cfg, AnalysisT &Analysis, + const Environment &InitEnv) { + auto TypeErasedBlockStates = + runTypeErasedDataflowAnalysis(Cfg, Analysis, InitEnv); + std::vector< + llvm::Optional>> + BlockStates; + BlockStates.reserve(TypeErasedBlockStates.size()); + llvm::transform(std::move(TypeErasedBlockStates), + std::back_inserter(BlockStates), [](auto &OptState) { + return std::move(OptState).map([](auto &&State) { + return DataflowAnalysisState{ + llvm::any_cast( + std::move(State.Lattice.Value)), + std::move(State.Env)}; + }); + }); + return BlockStates; +} + +} // namespace dataflow +} // namespace clang + +#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWANALYSIS_H diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h new file mode 100644 --- /dev/null +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -0,0 +1,27 @@ +//===-- DataflowEnvironment.h -----------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines an Environment class that is used by dataflow analyses +// that run over Control-Flow Graphs (CFGs) to keep track of the state of the +// program at given program points. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWENVIRONMENT_H +#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWENVIRONMENT_H + +namespace clang { +namespace dataflow { + +/// Holds the state of the program (store and heap) at a given program point. +class Environment {}; + +} // namespace dataflow +} // namespace clang + +#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWENVIRONMENT_H diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowLattice.h b/clang/include/clang/Analysis/FlowSensitive/DataflowLattice.h new file mode 100644 --- /dev/null +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowLattice.h @@ -0,0 +1,29 @@ +//===- DataflowLattice.h ----------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines base types for building lattices to be used in dataflow +// analyses that run over Control-Flow Graphs (CFGs). +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWLATTICE_H +#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWLATTICE_H + +namespace clang { +namespace dataflow { + +/// Effect indicating whether a lattice join operation resulted in a new value. +enum class LatticeJoinEffect { + Unchanged, + Changed, +}; + +} // namespace dataflow +} // namespace clang + +#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWLATTICE_H diff --git a/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h b/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h new file mode 100644 --- /dev/null +++ b/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h @@ -0,0 +1,93 @@ +//===- TypeErasedDataflowAnalysis.h -----------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines type-erased base types and functions for building dataflow +// analyses that run over Control-Flow Graphs (CFGs). +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_TYPEERASEDDATAFLOWANALYSIS_H +#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_TYPEERASEDDATAFLOWANALYSIS_H + +#include + +#include "clang/AST/ASTContext.h" +#include "clang/AST/Stmt.h" +#include "clang/Analysis/CFG.h" +#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" +#include "clang/Analysis/FlowSensitive/DataflowLattice.h" +#include "llvm/ADT/Any.h" +#include "llvm/ADT/Optional.h" + +namespace clang { +namespace dataflow { + +/// Type-erased lattice element container. +/// +/// Requirements: +/// +/// The type of the object stored in the container must be a bounded +/// join-semilattice. +struct TypeErasedLattice { + llvm::Any Value; +}; + +/// Type-erased base class for dataflow analyses built on a single lattice type. +class TypeErasedDataflowAnalysis { +public: + /// Returns the `ASTContext` that is used by the analysis. + virtual ASTContext &getASTContext() = 0; + + /// Returns a type-erased lattice element that models the initial state of a + /// basic block. + virtual TypeErasedLattice typeErasedInitialElement() = 0; + + /// Joins two type-erased lattice elements by computing their least upper + /// bound. Places the join result in the left element and returns an effect + /// indicating whether any changes were made to it. + virtual LatticeJoinEffect joinTypeErased(TypeErasedLattice &, + const TypeErasedLattice &) = 0; + + /// Returns true if and only if the two given type-erased lattice elements are + /// equal. + virtual bool isEqualTypeErased(const TypeErasedLattice &, + const TypeErasedLattice &) = 0; + + /// Applies the analysis transfer function for a given statement and + /// type-erased lattice element. + virtual TypeErasedLattice transferTypeErased(const Stmt *, + const TypeErasedLattice &, + Environment &) = 0; +}; + +/// Type-erased model of the program at a given program point. +struct TypeErasedDataflowAnalysisState { + /// Type-erased model of a program property. + TypeErasedLattice Lattice; + + /// Model of the state of the program (store and heap). + Environment Env; +}; + +/// Performs dataflow analysis and returns a mapping from basic block IDs to +/// dataflow analysis states that model the respective basic blocks. Indices +/// of the returned vector correspond to basic block IDs. +/// +/// Requirements: +/// +/// `Cfg` must have been built with `CFG::BuildOptions::setAllAlwaysAdd()` to +/// ensure that all sub-expressions in a basic block are evaluated. +std::vector> +runTypeErasedDataflowAnalysis(const CFG &Cfg, + TypeErasedDataflowAnalysis &Analysis, + const Environment &InitEnv); + +} // namespace dataflow +} // namespace clang + +#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_TYPEERASEDDATAFLOWANALYSIS_H diff --git a/clang/lib/Analysis/CMakeLists.txt b/clang/lib/Analysis/CMakeLists.txt --- a/clang/lib/Analysis/CMakeLists.txt +++ b/clang/lib/Analysis/CMakeLists.txt @@ -44,3 +44,4 @@ ) add_subdirectory(plugins) +add_subdirectory(FlowSensitive) diff --git a/clang/lib/Analysis/FlowSensitive/CMakeLists.txt b/clang/lib/Analysis/FlowSensitive/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/clang/lib/Analysis/FlowSensitive/CMakeLists.txt @@ -0,0 +1,7 @@ +add_clang_library(clangAnalysisFlowSensitive + TypeErasedDataflowAnalysis.cpp + + LINK_LIBS + clangAnalysis + clangAST + ) diff --git a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp new file mode 100644 --- /dev/null +++ b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp @@ -0,0 +1,35 @@ +//===- TypeErasedDataflowAnalysis.cpp -------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines type-erased base types and functions for building dataflow +// analyses that run over Control-Flow Graphs (CFGs). +// +//===----------------------------------------------------------------------===// + +#include + +#include "clang/Analysis/CFG.h" +#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" +#include "clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h" +#include "llvm/ADT/Optional.h" + +using namespace clang; +using namespace dataflow; + +std::vector> +runTypeErasedDataflowAnalysis(const CFG &Cfg, + TypeErasedDataflowAnalysis &Analysis, + const Environment &InitEnv) { + // FIXME: Consider enforcing that `Cfg` meets the requirements that + // are specified in the header. This could be done by remembering + // what options were used to build `Cfg` and asserting on them here. + + // FIXME: Implement work list-based algorithm to compute the fixed + // point of `Analysis::transform` for every basic block in `Cfg`. + return {}; +}