xref: /llvm-project/clang/unittests/Analysis/FlowSensitive/MultiVarConstantPropagationTest.cpp (revision e955e4fba60e6d93b66903687c1dd7a34435d33c)
1dcb4950dSSam Estep //===- unittests/Analysis/FlowSensitive/MultiVarConstantPropagation.cpp --===//
249501981SYitzhak Mandelbaum //
349501981SYitzhak Mandelbaum // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
449501981SYitzhak Mandelbaum // See https://llvm.org/LICENSE.txt for license information.
549501981SYitzhak Mandelbaum // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
649501981SYitzhak Mandelbaum //
749501981SYitzhak Mandelbaum //===----------------------------------------------------------------------===//
849501981SYitzhak Mandelbaum //
949501981SYitzhak Mandelbaum //  This file defines a simplistic version of Constant Propagation as an example
1049501981SYitzhak Mandelbaum //  of a forward, monotonic dataflow analysis. The analysis tracks all
1149501981SYitzhak Mandelbaum //  variables in the scope, but lacks escape analysis.
1249501981SYitzhak Mandelbaum //
1349501981SYitzhak Mandelbaum //===----------------------------------------------------------------------===//
1449501981SYitzhak Mandelbaum 
153dd7877bSStanislav Gatev #include "TestingSupport.h"
1649501981SYitzhak Mandelbaum #include "clang/AST/ASTContext.h"
1749501981SYitzhak Mandelbaum #include "clang/AST/Decl.h"
1849501981SYitzhak Mandelbaum #include "clang/AST/Expr.h"
1949501981SYitzhak Mandelbaum #include "clang/AST/Stmt.h"
2049501981SYitzhak Mandelbaum #include "clang/ASTMatchers/ASTMatchFinder.h"
2149501981SYitzhak Mandelbaum #include "clang/ASTMatchers/ASTMatchers.h"
22cf94c52eSWei Yi Tee #include "clang/Analysis/CFG.h"
2349501981SYitzhak Mandelbaum #include "clang/Analysis/FlowSensitive/DataflowAnalysis.h"
2449501981SYitzhak Mandelbaum #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
2549501981SYitzhak Mandelbaum #include "clang/Analysis/FlowSensitive/DataflowLattice.h"
2649501981SYitzhak Mandelbaum #include "clang/Analysis/FlowSensitive/MapLattice.h"
2749501981SYitzhak Mandelbaum #include "llvm/ADT/StringRef.h"
2849501981SYitzhak Mandelbaum #include "llvm/ADT/Twine.h"
2949501981SYitzhak Mandelbaum #include "llvm/Support/Error.h"
309cbdef61SWei Yi Tee #include "llvm/Testing/ADT/StringMapEntry.h"
31875117aeSYitzhak Mandelbaum #include "llvm/Testing/Support/Error.h"
3249501981SYitzhak Mandelbaum #include "gmock/gmock.h"
3349501981SYitzhak Mandelbaum #include "gtest/gtest.h"
3449501981SYitzhak Mandelbaum #include <cstdint>
3549501981SYitzhak Mandelbaum #include <memory>
36a1580d7bSKazu Hirata #include <optional>
3749501981SYitzhak Mandelbaum #include <ostream>
3849501981SYitzhak Mandelbaum #include <string>
3949501981SYitzhak Mandelbaum #include <utility>
4049501981SYitzhak Mandelbaum 
4149501981SYitzhak Mandelbaum namespace clang {
4249501981SYitzhak Mandelbaum namespace dataflow {
4349501981SYitzhak Mandelbaum namespace {
4449501981SYitzhak Mandelbaum using namespace ast_matchers;
4549501981SYitzhak Mandelbaum 
4649501981SYitzhak Mandelbaum // Models the value of an expression at a program point, for all paths through
4749501981SYitzhak Mandelbaum // the program.
4849501981SYitzhak Mandelbaum struct ValueLattice {
4949501981SYitzhak Mandelbaum   // FIXME: change the internal representation to use a `std::variant`, once
5049501981SYitzhak Mandelbaum   // clang admits C++17 constructs.
5149501981SYitzhak Mandelbaum   enum class ValueState : bool {
5249501981SYitzhak Mandelbaum     Undefined,
5349501981SYitzhak Mandelbaum     Defined,
5449501981SYitzhak Mandelbaum   };
5549501981SYitzhak Mandelbaum   // `State` determines the meaning of the lattice when `Value` is `None`:
5649501981SYitzhak Mandelbaum   //  * `Undefined` -> bottom,
5749501981SYitzhak Mandelbaum   //  * `Defined` -> top.
5849501981SYitzhak Mandelbaum   ValueState State;
5949501981SYitzhak Mandelbaum 
60*e955e4fbSKazu Hirata   // When `std::nullopt`, the lattice is either at top or bottom, based on
61*e955e4fbSKazu Hirata   // `State`.
626ad0788cSKazu Hirata   std::optional<int64_t> Value;
6349501981SYitzhak Mandelbaum 
ValueLatticeclang::dataflow::__anon18d4833f0111::ValueLattice64a41fbb1fSKazu Hirata   constexpr ValueLattice()
65a41fbb1fSKazu Hirata       : State(ValueState::Undefined), Value(std::nullopt) {}
ValueLatticeclang::dataflow::__anon18d4833f0111::ValueLattice6649501981SYitzhak Mandelbaum   constexpr ValueLattice(int64_t V) : State(ValueState::Defined), Value(V) {}
ValueLatticeclang::dataflow::__anon18d4833f0111::ValueLattice67a41fbb1fSKazu Hirata   constexpr ValueLattice(ValueState S) : State(S), Value(std::nullopt) {}
6849501981SYitzhak Mandelbaum 
bottomclang::dataflow::__anon18d4833f0111::ValueLattice6949501981SYitzhak Mandelbaum   static constexpr ValueLattice bottom() {
7049501981SYitzhak Mandelbaum     return ValueLattice(ValueState::Undefined);
7149501981SYitzhak Mandelbaum   }
topclang::dataflow::__anon18d4833f0111::ValueLattice7249501981SYitzhak Mandelbaum   static constexpr ValueLattice top() {
7349501981SYitzhak Mandelbaum     return ValueLattice(ValueState::Defined);
7449501981SYitzhak Mandelbaum   }
7549501981SYitzhak Mandelbaum 
operator ==(const ValueLattice & Lhs,const ValueLattice & Rhs)7649501981SYitzhak Mandelbaum   friend bool operator==(const ValueLattice &Lhs, const ValueLattice &Rhs) {
7749501981SYitzhak Mandelbaum     return Lhs.State == Rhs.State && Lhs.Value == Rhs.Value;
7849501981SYitzhak Mandelbaum   }
operator !=(const ValueLattice & Lhs,const ValueLattice & Rhs)7949501981SYitzhak Mandelbaum   friend bool operator!=(const ValueLattice &Lhs, const ValueLattice &Rhs) {
8049501981SYitzhak Mandelbaum     return !(Lhs == Rhs);
8149501981SYitzhak Mandelbaum   }
8249501981SYitzhak Mandelbaum 
joinclang::dataflow::__anon18d4833f0111::ValueLattice8349501981SYitzhak Mandelbaum   LatticeJoinEffect join(const ValueLattice &Other) {
8449501981SYitzhak Mandelbaum     if (*this == Other || Other == bottom() || *this == top())
8549501981SYitzhak Mandelbaum       return LatticeJoinEffect::Unchanged;
8649501981SYitzhak Mandelbaum 
8749501981SYitzhak Mandelbaum     if (*this == bottom()) {
8849501981SYitzhak Mandelbaum       *this = Other;
8949501981SYitzhak Mandelbaum       return LatticeJoinEffect::Changed;
9049501981SYitzhak Mandelbaum     }
9149501981SYitzhak Mandelbaum 
9249501981SYitzhak Mandelbaum     *this = top();
9349501981SYitzhak Mandelbaum     return LatticeJoinEffect::Changed;
9449501981SYitzhak Mandelbaum   }
9549501981SYitzhak Mandelbaum };
9649501981SYitzhak Mandelbaum 
operator <<(std::ostream & OS,const ValueLattice & L)9749501981SYitzhak Mandelbaum std::ostream &operator<<(std::ostream &OS, const ValueLattice &L) {
98b8df4093SKazu Hirata   if (L.Value)
9949501981SYitzhak Mandelbaum     return OS << *L.Value;
10049501981SYitzhak Mandelbaum   switch (L.State) {
10149501981SYitzhak Mandelbaum   case ValueLattice::ValueState::Undefined:
10249501981SYitzhak Mandelbaum     return OS << "None";
10349501981SYitzhak Mandelbaum   case ValueLattice::ValueState::Defined:
10449501981SYitzhak Mandelbaum     return OS << "Any";
10549501981SYitzhak Mandelbaum   }
106a5af260dSAlexandre Ganea   llvm_unreachable("unknown ValueState!");
10749501981SYitzhak Mandelbaum }
10849501981SYitzhak Mandelbaum 
10949501981SYitzhak Mandelbaum using ConstantPropagationLattice = VarMapLattice<ValueLattice>;
11049501981SYitzhak Mandelbaum 
11149501981SYitzhak Mandelbaum constexpr char kDecl[] = "decl";
11249501981SYitzhak Mandelbaum constexpr char kVar[] = "var";
11349501981SYitzhak Mandelbaum constexpr char kInit[] = "init";
11449501981SYitzhak Mandelbaum constexpr char kJustAssignment[] = "just-assignment";
11549501981SYitzhak Mandelbaum constexpr char kAssignment[] = "assignment";
11649501981SYitzhak Mandelbaum constexpr char kRHS[] = "rhs";
11749501981SYitzhak Mandelbaum 
refToVar()11849501981SYitzhak Mandelbaum auto refToVar() { return declRefExpr(to(varDecl().bind(kVar))); }
11949501981SYitzhak Mandelbaum 
12049501981SYitzhak Mandelbaum // N.B. This analysis is deliberately simplistic, leaving out many important
12149501981SYitzhak Mandelbaum // details needed for a real analysis. Most notably, the transfer function does
12249501981SYitzhak Mandelbaum // not account for the variable's address possibly escaping, which would
12349501981SYitzhak Mandelbaum // invalidate the analysis. It also could be optimized to drop out-of-scope
12449501981SYitzhak Mandelbaum // variables from the map.
12549501981SYitzhak Mandelbaum class ConstantPropagationAnalysis
12649501981SYitzhak Mandelbaum     : public DataflowAnalysis<ConstantPropagationAnalysis,
12749501981SYitzhak Mandelbaum                               ConstantPropagationLattice> {
12849501981SYitzhak Mandelbaum public:
ConstantPropagationAnalysis(ASTContext & Context)12949501981SYitzhak Mandelbaum   explicit ConstantPropagationAnalysis(ASTContext &Context)
13049501981SYitzhak Mandelbaum       : DataflowAnalysis<ConstantPropagationAnalysis,
13149501981SYitzhak Mandelbaum                          ConstantPropagationLattice>(Context) {}
13249501981SYitzhak Mandelbaum 
initialElement()13349501981SYitzhak Mandelbaum   static ConstantPropagationLattice initialElement() {
13449501981SYitzhak Mandelbaum     return ConstantPropagationLattice::bottom();
13549501981SYitzhak Mandelbaum   }
13649501981SYitzhak Mandelbaum 
transfer(const CFGElement & E,ConstantPropagationLattice & Vars,Environment & Env)1376b991ba4SYitzhak Mandelbaum   void transfer(const CFGElement &E, ConstantPropagationLattice &Vars,
13864f7b2d4SYitzhak Mandelbaum                 Environment &Env) {
1396b991ba4SYitzhak Mandelbaum     auto CS = E.getAs<CFGStmt>();
140cf94c52eSWei Yi Tee     if (!CS)
141cf94c52eSWei Yi Tee       return;
142cf94c52eSWei Yi Tee     auto S = CS->getStmt();
14349501981SYitzhak Mandelbaum     auto matcher =
14449501981SYitzhak Mandelbaum         stmt(anyOf(declStmt(hasSingleDecl(
14549501981SYitzhak Mandelbaum                        varDecl(decl().bind(kVar), hasType(isInteger()),
14649501981SYitzhak Mandelbaum                                optionally(hasInitializer(expr().bind(kInit))))
14749501981SYitzhak Mandelbaum                            .bind(kDecl))),
14849501981SYitzhak Mandelbaum                    binaryOperator(hasOperatorName("="), hasLHS(refToVar()),
14949501981SYitzhak Mandelbaum                                   hasRHS(expr().bind(kRHS)))
15049501981SYitzhak Mandelbaum                        .bind(kJustAssignment),
15149501981SYitzhak Mandelbaum                    binaryOperator(isAssignmentOperator(), hasLHS(refToVar()))
15249501981SYitzhak Mandelbaum                        .bind(kAssignment)));
15349501981SYitzhak Mandelbaum 
15449501981SYitzhak Mandelbaum     ASTContext &Context = getASTContext();
15549501981SYitzhak Mandelbaum     auto Results = match(matcher, *S, Context);
15649501981SYitzhak Mandelbaum     if (Results.empty())
15764f7b2d4SYitzhak Mandelbaum       return;
15849501981SYitzhak Mandelbaum     const BoundNodes &Nodes = Results[0];
15949501981SYitzhak Mandelbaum 
16049501981SYitzhak Mandelbaum     const auto *Var = Nodes.getNodeAs<clang::VarDecl>(kVar);
16149501981SYitzhak Mandelbaum     assert(Var != nullptr);
16249501981SYitzhak Mandelbaum 
16349501981SYitzhak Mandelbaum     if (Nodes.getNodeAs<clang::VarDecl>(kDecl) != nullptr) {
16449501981SYitzhak Mandelbaum       if (const auto *E = Nodes.getNodeAs<clang::Expr>(kInit)) {
16549501981SYitzhak Mandelbaum         Expr::EvalResult R;
16649501981SYitzhak Mandelbaum         Vars[Var] = (E->EvaluateAsInt(R, Context) && R.Val.isInt())
16749501981SYitzhak Mandelbaum                         ? ValueLattice(R.Val.getInt().getExtValue())
16849501981SYitzhak Mandelbaum                         : ValueLattice::top();
16949501981SYitzhak Mandelbaum       } else {
17049501981SYitzhak Mandelbaum         // An unitialized variable holds *some* value, but we don't know what it
17149501981SYitzhak Mandelbaum         // is (it is implementation defined), so we set it to top.
17249501981SYitzhak Mandelbaum         Vars[Var] = ValueLattice::top();
17349501981SYitzhak Mandelbaum       }
17464f7b2d4SYitzhak Mandelbaum     } else if (Nodes.getNodeAs<clang::Expr>(kJustAssignment)) {
17549501981SYitzhak Mandelbaum       const auto *E = Nodes.getNodeAs<clang::Expr>(kRHS);
17649501981SYitzhak Mandelbaum       assert(E != nullptr);
17749501981SYitzhak Mandelbaum 
17849501981SYitzhak Mandelbaum       Expr::EvalResult R;
17949501981SYitzhak Mandelbaum       Vars[Var] = (E->EvaluateAsInt(R, Context) && R.Val.isInt())
18049501981SYitzhak Mandelbaum                       ? ValueLattice(R.Val.getInt().getExtValue())
18149501981SYitzhak Mandelbaum                       : ValueLattice::top();
18264f7b2d4SYitzhak Mandelbaum     } else if (Nodes.getNodeAs<clang::Expr>(kAssignment)) {
18349501981SYitzhak Mandelbaum       // Any assignment involving the expression itself resets the variable to
18449501981SYitzhak Mandelbaum       // "unknown". A more advanced analysis could try to evaluate the compound
18549501981SYitzhak Mandelbaum       // assignment. For example, `x += 0` need not invalidate `x`.
18649501981SYitzhak Mandelbaum       Vars[Var] = ValueLattice::top();
18749501981SYitzhak Mandelbaum     }
18849501981SYitzhak Mandelbaum   }
18949501981SYitzhak Mandelbaum };
19049501981SYitzhak Mandelbaum 
1919cbdef61SWei Yi Tee using ::clang::dataflow::test::AnalysisInputs;
1929cbdef61SWei Yi Tee using ::clang::dataflow::test::AnalysisOutputs;
1939cbdef61SWei Yi Tee using ::clang::dataflow::test::checkDataflow;
1949cbdef61SWei Yi Tee using ::llvm::IsStringMapEntry;
19549501981SYitzhak Mandelbaum using ::testing::Pair;
19649501981SYitzhak Mandelbaum using ::testing::UnorderedElementsAre;
19749501981SYitzhak Mandelbaum 
19849501981SYitzhak Mandelbaum MATCHER_P(Var, name,
19949501981SYitzhak Mandelbaum           (llvm::Twine(negation ? "isn't" : "is") + " a variable named `" +
20049501981SYitzhak Mandelbaum            name + "`")
20149501981SYitzhak Mandelbaum               .str()) {
20249501981SYitzhak Mandelbaum   return arg->getName() == name;
20349501981SYitzhak Mandelbaum }
20449501981SYitzhak Mandelbaum 
205b8df4093SKazu Hirata MATCHER_P(HasConstantVal, v, "") { return arg.Value && *arg.Value == v; }
20649501981SYitzhak Mandelbaum 
20749501981SYitzhak Mandelbaum MATCHER(Varies, "") { return arg == arg.top(); }
20849501981SYitzhak Mandelbaum 
20949501981SYitzhak Mandelbaum MATCHER_P(HoldsCPLattice, m,
21049501981SYitzhak Mandelbaum           ((negation ? "doesn't hold" : "holds") +
21149501981SYitzhak Mandelbaum            llvm::StringRef(" a lattice element that ") +
21249501981SYitzhak Mandelbaum            ::testing::DescribeMatcher<ConstantPropagationLattice>(m, negation))
21349501981SYitzhak Mandelbaum               .str()) {
21449501981SYitzhak Mandelbaum   return ExplainMatchResult(m, arg.Lattice, result_listener);
21549501981SYitzhak Mandelbaum }
21649501981SYitzhak Mandelbaum 
21749501981SYitzhak Mandelbaum template <typename Matcher>
RunDataflow(llvm::StringRef Code,Matcher Expectations)21849501981SYitzhak Mandelbaum void RunDataflow(llvm::StringRef Code, Matcher Expectations) {
219875117aeSYitzhak Mandelbaum   ASSERT_THAT_ERROR(
2209cbdef61SWei Yi Tee       checkDataflow<ConstantPropagationAnalysis>(
2219cbdef61SWei Yi Tee           AnalysisInputs<ConstantPropagationAnalysis>(
2229cbdef61SWei Yi Tee               Code, hasName("fun"),
22349501981SYitzhak Mandelbaum               [](ASTContext &C, Environment &) {
22449501981SYitzhak Mandelbaum                 return ConstantPropagationAnalysis(C);
2259cbdef61SWei Yi Tee               })
2269cbdef61SWei Yi Tee               .withASTBuildArgs({"-fsyntax-only", "-std=c++17"}),
2279cbdef61SWei Yi Tee           /*VerifyResults=*/
2289cbdef61SWei Yi Tee           [&Expectations](const llvm::StringMap<DataflowAnalysisState<
2299cbdef61SWei Yi Tee                               ConstantPropagationAnalysis::Lattice>> &Results,
2309cbdef61SWei Yi Tee                           const AnalysisOutputs &) {
2319cbdef61SWei Yi Tee             EXPECT_THAT(Results, Expectations);
2329cbdef61SWei Yi Tee           }),
233875117aeSYitzhak Mandelbaum       llvm::Succeeded());
23449501981SYitzhak Mandelbaum }
23549501981SYitzhak Mandelbaum 
TEST(MultiVarConstantPropagationTest,JustInit)2361d83a16bSSam Estep TEST(MultiVarConstantPropagationTest, JustInit) {
23749501981SYitzhak Mandelbaum   std::string Code = R"(
23849501981SYitzhak Mandelbaum     void fun() {
23949501981SYitzhak Mandelbaum       int target = 1;
24049501981SYitzhak Mandelbaum       // [[p]]
24149501981SYitzhak Mandelbaum     }
24249501981SYitzhak Mandelbaum   )";
2439cbdef61SWei Yi Tee   RunDataflow(Code, UnorderedElementsAre(IsStringMapEntry(
2449cbdef61SWei Yi Tee                         "p", HoldsCPLattice(UnorderedElementsAre(
2459cbdef61SWei Yi Tee                                  Pair(Var("target"), HasConstantVal(1)))))));
24649501981SYitzhak Mandelbaum }
24749501981SYitzhak Mandelbaum 
TEST(MultiVarConstantPropagationTest,Assignment)2481d83a16bSSam Estep TEST(MultiVarConstantPropagationTest, Assignment) {
24949501981SYitzhak Mandelbaum   std::string Code = R"(
25049501981SYitzhak Mandelbaum     void fun() {
25149501981SYitzhak Mandelbaum       int target = 1;
25249501981SYitzhak Mandelbaum       // [[p1]]
25349501981SYitzhak Mandelbaum       target = 2;
25449501981SYitzhak Mandelbaum       // [[p2]]
25549501981SYitzhak Mandelbaum     }
25649501981SYitzhak Mandelbaum   )";
2579cbdef61SWei Yi Tee   RunDataflow(
2589cbdef61SWei Yi Tee       Code,
2599cbdef61SWei Yi Tee       UnorderedElementsAre(
2609cbdef61SWei Yi Tee           IsStringMapEntry("p1", HoldsCPLattice(UnorderedElementsAre(
2619cbdef61SWei Yi Tee                                      Pair(Var("target"), HasConstantVal(1))))),
2629cbdef61SWei Yi Tee           IsStringMapEntry("p2", HoldsCPLattice(UnorderedElementsAre(Pair(
26349501981SYitzhak Mandelbaum                                      Var("target"), HasConstantVal(2)))))));
26449501981SYitzhak Mandelbaum }
26549501981SYitzhak Mandelbaum 
TEST(MultiVarConstantPropagationTest,AssignmentCall)2661d83a16bSSam Estep TEST(MultiVarConstantPropagationTest, AssignmentCall) {
26749501981SYitzhak Mandelbaum   std::string Code = R"(
26849501981SYitzhak Mandelbaum     int g();
26949501981SYitzhak Mandelbaum     void fun() {
27049501981SYitzhak Mandelbaum       int target;
27149501981SYitzhak Mandelbaum       target = g();
27249501981SYitzhak Mandelbaum       // [[p]]
27349501981SYitzhak Mandelbaum     }
27449501981SYitzhak Mandelbaum   )";
2759cbdef61SWei Yi Tee   RunDataflow(Code, UnorderedElementsAre(IsStringMapEntry(
2769cbdef61SWei Yi Tee                         "p", HoldsCPLattice(UnorderedElementsAre(
27749501981SYitzhak Mandelbaum                                  Pair(Var("target"), Varies()))))));
27849501981SYitzhak Mandelbaum }
27949501981SYitzhak Mandelbaum 
TEST(MultiVarConstantPropagationTest,AssignmentBinOp)2801d83a16bSSam Estep TEST(MultiVarConstantPropagationTest, AssignmentBinOp) {
28149501981SYitzhak Mandelbaum   std::string Code = R"(
28249501981SYitzhak Mandelbaum     void fun() {
28349501981SYitzhak Mandelbaum       int target;
28449501981SYitzhak Mandelbaum       target = 2 + 3;
28549501981SYitzhak Mandelbaum       // [[p]]
28649501981SYitzhak Mandelbaum     }
28749501981SYitzhak Mandelbaum   )";
2889cbdef61SWei Yi Tee   RunDataflow(Code, UnorderedElementsAre(IsStringMapEntry(
2899cbdef61SWei Yi Tee                         "p", HoldsCPLattice(UnorderedElementsAre(
2909cbdef61SWei Yi Tee                                  Pair(Var("target"), HasConstantVal(5)))))));
29149501981SYitzhak Mandelbaum }
29249501981SYitzhak Mandelbaum 
TEST(MultiVarConstantPropagationTest,PlusAssignment)2931d83a16bSSam Estep TEST(MultiVarConstantPropagationTest, PlusAssignment) {
29449501981SYitzhak Mandelbaum   std::string Code = R"(
29549501981SYitzhak Mandelbaum     void fun() {
29649501981SYitzhak Mandelbaum       int target = 1;
29749501981SYitzhak Mandelbaum       // [[p1]]
29849501981SYitzhak Mandelbaum       target += 2;
29949501981SYitzhak Mandelbaum       // [[p2]]
30049501981SYitzhak Mandelbaum     }
30149501981SYitzhak Mandelbaum   )";
3029cbdef61SWei Yi Tee   RunDataflow(
3039cbdef61SWei Yi Tee       Code, UnorderedElementsAre(
3049cbdef61SWei Yi Tee                 IsStringMapEntry("p1", HoldsCPLattice(UnorderedElementsAre(Pair(
30549501981SYitzhak Mandelbaum                                            Var("target"), HasConstantVal(1))))),
3069cbdef61SWei Yi Tee                 IsStringMapEntry("p2", HoldsCPLattice(UnorderedElementsAre(
30749501981SYitzhak Mandelbaum                                            Pair(Var("target"), Varies()))))));
30849501981SYitzhak Mandelbaum }
30949501981SYitzhak Mandelbaum 
TEST(MultiVarConstantPropagationTest,SameAssignmentInBranches)3101d83a16bSSam Estep TEST(MultiVarConstantPropagationTest, SameAssignmentInBranches) {
31149501981SYitzhak Mandelbaum   std::string Code = R"cc(
31249501981SYitzhak Mandelbaum     void fun(bool b) {
31349501981SYitzhak Mandelbaum       int target;
31449501981SYitzhak Mandelbaum       // [[p1]]
31549501981SYitzhak Mandelbaum       if (b) {
31649501981SYitzhak Mandelbaum         target = 2;
31749501981SYitzhak Mandelbaum         // [[pT]]
31849501981SYitzhak Mandelbaum       } else {
31949501981SYitzhak Mandelbaum         target = 2;
32049501981SYitzhak Mandelbaum         // [[pF]]
32149501981SYitzhak Mandelbaum       }
32249501981SYitzhak Mandelbaum       (void)0;
32349501981SYitzhak Mandelbaum       // [[p2]]
32449501981SYitzhak Mandelbaum     }
32549501981SYitzhak Mandelbaum   )cc";
3269cbdef61SWei Yi Tee   RunDataflow(
3279cbdef61SWei Yi Tee       Code,
32849501981SYitzhak Mandelbaum       UnorderedElementsAre(
3299cbdef61SWei Yi Tee           IsStringMapEntry("p1", HoldsCPLattice(UnorderedElementsAre(
33049501981SYitzhak Mandelbaum                                      Pair(Var("target"), Varies())))),
3319cbdef61SWei Yi Tee           IsStringMapEntry("pT", HoldsCPLattice(UnorderedElementsAre(
33249501981SYitzhak Mandelbaum                                      Pair(Var("target"), HasConstantVal(2))))),
3339cbdef61SWei Yi Tee           IsStringMapEntry("pF", HoldsCPLattice(UnorderedElementsAre(
33449501981SYitzhak Mandelbaum                                      Pair(Var("target"), HasConstantVal(2))))),
3359cbdef61SWei Yi Tee           IsStringMapEntry("p2", HoldsCPLattice(UnorderedElementsAre(Pair(
3369cbdef61SWei Yi Tee                                      Var("target"), HasConstantVal(2)))))));
33749501981SYitzhak Mandelbaum }
33849501981SYitzhak Mandelbaum 
33949501981SYitzhak Mandelbaum // Verifies that the analysis tracks multiple variables simultaneously.
TEST(MultiVarConstantPropagationTest,TwoVariables)3401d83a16bSSam Estep TEST(MultiVarConstantPropagationTest, TwoVariables) {
34149501981SYitzhak Mandelbaum   std::string Code = R"(
34249501981SYitzhak Mandelbaum     void fun() {
34349501981SYitzhak Mandelbaum       int target = 1;
34449501981SYitzhak Mandelbaum       // [[p1]]
34549501981SYitzhak Mandelbaum       int other = 2;
34649501981SYitzhak Mandelbaum       // [[p2]]
34749501981SYitzhak Mandelbaum       target = 3;
34849501981SYitzhak Mandelbaum       // [[p3]]
34949501981SYitzhak Mandelbaum     }
35049501981SYitzhak Mandelbaum   )";
3519cbdef61SWei Yi Tee   RunDataflow(
3529cbdef61SWei Yi Tee       Code,
35349501981SYitzhak Mandelbaum       UnorderedElementsAre(
3549cbdef61SWei Yi Tee           IsStringMapEntry("p1", HoldsCPLattice(UnorderedElementsAre(
35549501981SYitzhak Mandelbaum                                      Pair(Var("target"), HasConstantVal(1))))),
3569cbdef61SWei Yi Tee           IsStringMapEntry("p2", HoldsCPLattice(UnorderedElementsAre(
35749501981SYitzhak Mandelbaum                                      Pair(Var("target"), HasConstantVal(1)),
35849501981SYitzhak Mandelbaum                                      Pair(Var("other"), HasConstantVal(2))))),
3599cbdef61SWei Yi Tee           IsStringMapEntry("p3", HoldsCPLattice(UnorderedElementsAre(
36049501981SYitzhak Mandelbaum                                      Pair(Var("target"), HasConstantVal(3)),
36149501981SYitzhak Mandelbaum                                      Pair(Var("other"), HasConstantVal(2)))))));
36249501981SYitzhak Mandelbaum }
36349501981SYitzhak Mandelbaum 
TEST(MultiVarConstantPropagationTest,TwoVariablesInBranches)3641d83a16bSSam Estep TEST(MultiVarConstantPropagationTest, TwoVariablesInBranches) {
36549501981SYitzhak Mandelbaum   std::string Code = R"cc(
36649501981SYitzhak Mandelbaum     void fun(bool b) {
36749501981SYitzhak Mandelbaum       int target;
36849501981SYitzhak Mandelbaum       int other;
36949501981SYitzhak Mandelbaum       // [[p1]]
37049501981SYitzhak Mandelbaum       if (b) {
37149501981SYitzhak Mandelbaum         target = 2;
37249501981SYitzhak Mandelbaum         // [[pT]]
37349501981SYitzhak Mandelbaum       } else {
37449501981SYitzhak Mandelbaum         other = 3;
37549501981SYitzhak Mandelbaum         // [[pF]]
37649501981SYitzhak Mandelbaum       }
37749501981SYitzhak Mandelbaum       (void)0;
37849501981SYitzhak Mandelbaum       // [[p2]]
37949501981SYitzhak Mandelbaum     }
38049501981SYitzhak Mandelbaum   )cc";
3819cbdef61SWei Yi Tee   RunDataflow(
3829cbdef61SWei Yi Tee       Code,
3839cbdef61SWei Yi Tee       UnorderedElementsAre(
3849cbdef61SWei Yi Tee           IsStringMapEntry("p1", HoldsCPLattice(UnorderedElementsAre(
38549501981SYitzhak Mandelbaum                                      Pair(Var("target"), Varies()),
38649501981SYitzhak Mandelbaum                                      Pair(Var("other"), Varies())))),
3879cbdef61SWei Yi Tee           IsStringMapEntry("pT", HoldsCPLattice(UnorderedElementsAre(
38849501981SYitzhak Mandelbaum                                      Pair(Var("target"), HasConstantVal(2)),
38949501981SYitzhak Mandelbaum                                      Pair(Var("other"), Varies())))),
3909cbdef61SWei Yi Tee           IsStringMapEntry("pF", HoldsCPLattice(UnorderedElementsAre(
39149501981SYitzhak Mandelbaum                                      Pair(Var("other"), HasConstantVal(3)),
39249501981SYitzhak Mandelbaum                                      Pair(Var("target"), Varies())))),
3939cbdef61SWei Yi Tee           IsStringMapEntry("p2", HoldsCPLattice(UnorderedElementsAre(
39449501981SYitzhak Mandelbaum                                      Pair(Var("target"), Varies()),
39549501981SYitzhak Mandelbaum                                      Pair(Var("other"), Varies()))))));
39649501981SYitzhak Mandelbaum }
39749501981SYitzhak Mandelbaum 
TEST(MultiVarConstantPropagationTest,SameAssignmentInBranch)3981d83a16bSSam Estep TEST(MultiVarConstantPropagationTest, SameAssignmentInBranch) {
39949501981SYitzhak Mandelbaum   std::string Code = R"cc(
40049501981SYitzhak Mandelbaum     void fun(bool b) {
40149501981SYitzhak Mandelbaum       int target = 1;
40249501981SYitzhak Mandelbaum       // [[p1]]
40349501981SYitzhak Mandelbaum       if (b) {
40449501981SYitzhak Mandelbaum         target = 1;
40549501981SYitzhak Mandelbaum       }
40649501981SYitzhak Mandelbaum       (void)0;
40749501981SYitzhak Mandelbaum       // [[p2]]
40849501981SYitzhak Mandelbaum     }
40949501981SYitzhak Mandelbaum   )cc";
4109cbdef61SWei Yi Tee   RunDataflow(
4119cbdef61SWei Yi Tee       Code,
4129cbdef61SWei Yi Tee       UnorderedElementsAre(
4139cbdef61SWei Yi Tee           IsStringMapEntry("p1", HoldsCPLattice(UnorderedElementsAre(
4149cbdef61SWei Yi Tee                                      Pair(Var("target"), HasConstantVal(1))))),
4159cbdef61SWei Yi Tee           IsStringMapEntry("p2", HoldsCPLattice(UnorderedElementsAre(Pair(
41649501981SYitzhak Mandelbaum                                      Var("target"), HasConstantVal(1)))))));
41749501981SYitzhak Mandelbaum }
41849501981SYitzhak Mandelbaum 
TEST(MultiVarConstantPropagationTest,NewVarInBranch)4191d83a16bSSam Estep TEST(MultiVarConstantPropagationTest, NewVarInBranch) {
42049501981SYitzhak Mandelbaum   std::string Code = R"cc(
42149501981SYitzhak Mandelbaum     void fun(bool b) {
42249501981SYitzhak Mandelbaum       if (b) {
42349501981SYitzhak Mandelbaum         int target;
42449501981SYitzhak Mandelbaum         // [[p1]]
42549501981SYitzhak Mandelbaum         target = 1;
42649501981SYitzhak Mandelbaum         // [[p2]]
42749501981SYitzhak Mandelbaum       } else {
42849501981SYitzhak Mandelbaum         int target;
42949501981SYitzhak Mandelbaum         // [[p3]]
43049501981SYitzhak Mandelbaum         target = 1;
43149501981SYitzhak Mandelbaum         // [[p4]]
43249501981SYitzhak Mandelbaum       }
43349501981SYitzhak Mandelbaum     }
43449501981SYitzhak Mandelbaum   )cc";
4359cbdef61SWei Yi Tee   RunDataflow(
4369cbdef61SWei Yi Tee       Code,
4379cbdef61SWei Yi Tee       UnorderedElementsAre(
4389cbdef61SWei Yi Tee           IsStringMapEntry("p1", HoldsCPLattice(UnorderedElementsAre(
43949501981SYitzhak Mandelbaum                                      Pair(Var("target"), Varies())))),
4409cbdef61SWei Yi Tee           IsStringMapEntry("p2", HoldsCPLattice(UnorderedElementsAre(
4419cbdef61SWei Yi Tee                                      Pair(Var("target"), HasConstantVal(1))))),
4429cbdef61SWei Yi Tee           IsStringMapEntry("p3", HoldsCPLattice(UnorderedElementsAre(
44349501981SYitzhak Mandelbaum                                      Pair(Var("target"), Varies())))),
4449cbdef61SWei Yi Tee           IsStringMapEntry("p4", HoldsCPLattice(UnorderedElementsAre(Pair(
44549501981SYitzhak Mandelbaum                                      Var("target"), HasConstantVal(1)))))));
44649501981SYitzhak Mandelbaum }
44749501981SYitzhak Mandelbaum 
TEST(MultiVarConstantPropagationTest,DifferentAssignmentInBranches)4481d83a16bSSam Estep TEST(MultiVarConstantPropagationTest, DifferentAssignmentInBranches) {
44949501981SYitzhak Mandelbaum   std::string Code = R"cc(
45049501981SYitzhak Mandelbaum     void fun(bool b) {
45149501981SYitzhak Mandelbaum       int target;
45249501981SYitzhak Mandelbaum       // [[p1]]
45349501981SYitzhak Mandelbaum       if (b) {
45449501981SYitzhak Mandelbaum         target = 1;
45549501981SYitzhak Mandelbaum         // [[pT]]
45649501981SYitzhak Mandelbaum       } else {
45749501981SYitzhak Mandelbaum         target = 2;
45849501981SYitzhak Mandelbaum         // [[pF]]
45949501981SYitzhak Mandelbaum       }
46049501981SYitzhak Mandelbaum       (void)0;
46149501981SYitzhak Mandelbaum       // [[p2]]
46249501981SYitzhak Mandelbaum     }
46349501981SYitzhak Mandelbaum   )cc";
4649cbdef61SWei Yi Tee   RunDataflow(
4659cbdef61SWei Yi Tee       Code, UnorderedElementsAre(
4669cbdef61SWei Yi Tee                 IsStringMapEntry("p1", HoldsCPLattice(UnorderedElementsAre(
46749501981SYitzhak Mandelbaum                                            Pair(Var("target"), Varies())))),
4689cbdef61SWei Yi Tee                 IsStringMapEntry("pT", HoldsCPLattice(UnorderedElementsAre(Pair(
46949501981SYitzhak Mandelbaum                                            Var("target"), HasConstantVal(1))))),
4709cbdef61SWei Yi Tee                 IsStringMapEntry("pF", HoldsCPLattice(UnorderedElementsAre(Pair(
47149501981SYitzhak Mandelbaum                                            Var("target"), HasConstantVal(2))))),
4729cbdef61SWei Yi Tee                 IsStringMapEntry("p2", HoldsCPLattice(UnorderedElementsAre(
47349501981SYitzhak Mandelbaum                                            Pair(Var("target"), Varies()))))));
47449501981SYitzhak Mandelbaum }
47549501981SYitzhak Mandelbaum 
TEST(MultiVarConstantPropagationTest,DifferentAssignmentInBranch)4761d83a16bSSam Estep TEST(MultiVarConstantPropagationTest, DifferentAssignmentInBranch) {
47749501981SYitzhak Mandelbaum   std::string Code = R"cc(
47849501981SYitzhak Mandelbaum     void fun(bool b) {
47949501981SYitzhak Mandelbaum       int target = 1;
48049501981SYitzhak Mandelbaum       // [[p1]]
48149501981SYitzhak Mandelbaum       if (b) {
48249501981SYitzhak Mandelbaum         target = 3;
48349501981SYitzhak Mandelbaum       }
48449501981SYitzhak Mandelbaum       (void)0;
48549501981SYitzhak Mandelbaum       // [[p2]]
48649501981SYitzhak Mandelbaum     }
48749501981SYitzhak Mandelbaum   )cc";
4889cbdef61SWei Yi Tee   RunDataflow(
4899cbdef61SWei Yi Tee       Code, UnorderedElementsAre(
4909cbdef61SWei Yi Tee                 IsStringMapEntry("p1", HoldsCPLattice(UnorderedElementsAre(Pair(
49149501981SYitzhak Mandelbaum                                            Var("target"), HasConstantVal(1))))),
4929cbdef61SWei Yi Tee                 IsStringMapEntry("p2", HoldsCPLattice(UnorderedElementsAre(
49349501981SYitzhak Mandelbaum                                            Pair(Var("target"), Varies()))))));
49449501981SYitzhak Mandelbaum }
49549501981SYitzhak Mandelbaum 
49649501981SYitzhak Mandelbaum } // namespace
49749501981SYitzhak Mandelbaum } // namespace dataflow
49849501981SYitzhak Mandelbaum } // namespace clang
499