diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h --- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -430,6 +430,7 @@ } LLVM_DUMP_METHOD void dump() const; + LLVM_DUMP_METHOD void dump(raw_ostream &OS) const; private: /// Creates a value appropriate for `Type`, if `Type` is supported, otherwise diff --git a/clang/include/clang/Analysis/FlowSensitive/Value.h b/clang/include/clang/Analysis/FlowSensitive/Value.h --- a/clang/include/clang/Analysis/FlowSensitive/Value.h +++ b/clang/include/clang/Analysis/FlowSensitive/Value.h @@ -19,6 +19,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" #include #include @@ -310,6 +311,8 @@ llvm::DenseMap Children; }; +raw_ostream &operator<<(raw_ostream &OS, const Value &Val); + } // namespace dataflow } // namespace clang diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -786,9 +786,29 @@ return DACtx->flowConditionImplies(*FlowConditionToken, Val); } -void Environment::dump() const { +void Environment::dump(raw_ostream &OS) const { + // FIXME: add printing for remaining and allow controller to decide what + // fields are printed. + llvm::dbgs() << "DeclToLoc:\n"; + for (auto [D, L] : DeclToLoc) + llvm::dbgs() << " [" << D->getName() << ", " << L << "]\n"; + + llvm::dbgs() << "ExprToLoc:\n"; + for (auto [E, L] : ExprToLoc) + llvm::dbgs() << " [" << E << ", " << L << "]\n"; + + llvm::dbgs() << "LocToVal:\n"; + for (auto [L, V] : LocToVal) { + llvm::dbgs() << " [" << L << ", " << V << ": " << *V << "]\n"; + } + + llvm::dbgs() << "FlowConditionToken:\n"; DACtx->dumpFlowCondition(*FlowConditionToken); } +void Environment::dump() const { + dump(llvm::dbgs()); +} + } // namespace dataflow } // namespace clang diff --git a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp --- a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp +++ b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp @@ -32,8 +32,10 @@ #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/Error.h" -#include "llvm/Support/ErrorHandling.h" + +#define DEBUG_TYPE "clang-dataflow" namespace clang { namespace dataflow { @@ -431,6 +433,8 @@ std::min(RelativeMaxIterations, AbsoluteMaxIterations); uint32_t Iterations = 0; while (const CFGBlock *Block = Worklist.dequeue()) { + LLVM_DEBUG(llvm::dbgs() + << "Processing Block " << Block->getBlockID() << "\n"); if (++Iterations > MaxIterations) { return llvm::createStringError(std::errc::timed_out, "maximum number of iterations reached"); @@ -440,8 +444,16 @@ BlockStates[Block->getBlockID()]; TypeErasedDataflowAnalysisState NewBlockState = transferCFGBlock(*Block, AC); + LLVM_DEBUG({ + llvm::errs() << "New Env:\n"; + NewBlockState.Env.dump(); + }); if (OldBlockState) { + LLVM_DEBUG({ + llvm::errs() << "Old Env:\n"; + OldBlockState->Env.dump(); + }); if (isLoopHead(*Block)) { LatticeJoinEffect Effect1 = Analysis.widenTypeErased( NewBlockState.Lattice, OldBlockState->Lattice); diff --git a/clang/lib/Analysis/FlowSensitive/Value.cpp b/clang/lib/Analysis/FlowSensitive/Value.cpp --- a/clang/lib/Analysis/FlowSensitive/Value.cpp +++ b/clang/lib/Analysis/FlowSensitive/Value.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "clang/Analysis/FlowSensitive/Value.h" +#include "clang/Analysis/FlowSensitive/DebugSupport.h" #include "llvm/Support/Casting.h" namespace clang { @@ -35,5 +36,21 @@ areEquivalentIndirectionValues(Val1, Val2))); } +raw_ostream &operator<<(raw_ostream &OS, const Value &Val) { + switch (Val.getKind()) { + case Value::Kind::Reference: { + const auto *RV = cast(&Val); + return OS << "Reference(" << &RV->getReferentLoc() << ")"; + } + case Value::Kind::Pointer: { + const auto *PV = dyn_cast(&Val); + return OS << "Pointer(" << &PV->getPointeeLoc() << ")"; + } + // FIXME: support remaining cases. + default: + return OS << debugString(Val.getKind()); + } +} + } // namespace dataflow } // namespace clang