1c9666d23SWei Yi Tee //===- DebugSupport.cpp -----------------------------------------*- C++ -*-===//
2c9666d23SWei Yi Tee //
3c9666d23SWei Yi Tee // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4c9666d23SWei Yi Tee // See https://llvm.org/LICENSE.txt for license information.
5c9666d23SWei Yi Tee // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6c9666d23SWei Yi Tee //
7c9666d23SWei Yi Tee //===----------------------------------------------------------------------===//
8c9666d23SWei Yi Tee //
9c9666d23SWei Yi Tee // This file defines functions which generate more readable forms of data
10c9666d23SWei Yi Tee // structures used in the dataflow analyses, for debugging purposes.
11c9666d23SWei Yi Tee //
12c9666d23SWei Yi Tee //===----------------------------------------------------------------------===//
13c9666d23SWei Yi Tee
14b8d83e80SWei Yi Tee #include <utility>
15b8d83e80SWei Yi Tee
16c9666d23SWei Yi Tee #include "clang/Analysis/FlowSensitive/DebugSupport.h"
17b8d83e80SWei Yi Tee #include "clang/Analysis/FlowSensitive/Solver.h"
18c9666d23SWei Yi Tee #include "clang/Analysis/FlowSensitive/Value.h"
19c9666d23SWei Yi Tee #include "llvm/ADT/DenseMap.h"
20b5414b56SDmitri Gribenko #include "llvm/ADT/STLExtras.h"
21c9666d23SWei Yi Tee #include "llvm/ADT/StringSet.h"
22c9666d23SWei Yi Tee #include "llvm/Support/ErrorHandling.h"
23c9666d23SWei Yi Tee #include "llvm/Support/FormatAdapters.h"
24b8d83e80SWei Yi Tee #include "llvm/Support/FormatCommon.h"
25c9666d23SWei Yi Tee #include "llvm/Support/FormatVariadic.h"
26c9666d23SWei Yi Tee
27c9666d23SWei Yi Tee namespace clang {
28c9666d23SWei Yi Tee namespace dataflow {
29c9666d23SWei Yi Tee
30b8d83e80SWei Yi Tee using llvm::AlignStyle;
31c9666d23SWei Yi Tee using llvm::fmt_pad;
32c9666d23SWei Yi Tee using llvm::formatv;
33c9666d23SWei Yi Tee
debugString(Solver::Result::Assignment Assignment)34ee6aba85SDmitri Gribenko std::string debugString(Solver::Result::Assignment Assignment) {
35ee6aba85SDmitri Gribenko switch (Assignment) {
36ee6aba85SDmitri Gribenko case Solver::Result::Assignment::AssignedFalse:
37ee6aba85SDmitri Gribenko return "False";
38ee6aba85SDmitri Gribenko case Solver::Result::Assignment::AssignedTrue:
39ee6aba85SDmitri Gribenko return "True";
40ee6aba85SDmitri Gribenko }
41ee6aba85SDmitri Gribenko llvm_unreachable("Booleans can only be assigned true/false");
42ee6aba85SDmitri Gribenko }
43ee6aba85SDmitri Gribenko
debugString(Solver::Result::Status Status)44ee6aba85SDmitri Gribenko std::string debugString(Solver::Result::Status Status) {
45ee6aba85SDmitri Gribenko switch (Status) {
46ee6aba85SDmitri Gribenko case Solver::Result::Status::Satisfiable:
47ee6aba85SDmitri Gribenko return "Satisfiable";
48ee6aba85SDmitri Gribenko case Solver::Result::Status::Unsatisfiable:
49ee6aba85SDmitri Gribenko return "Unsatisfiable";
50ee6aba85SDmitri Gribenko case Solver::Result::Status::TimedOut:
51ee6aba85SDmitri Gribenko return "TimedOut";
52ee6aba85SDmitri Gribenko }
53ee6aba85SDmitri Gribenko llvm_unreachable("Unhandled SAT check result status");
54ee6aba85SDmitri Gribenko }
55ee6aba85SDmitri Gribenko
56c9666d23SWei Yi Tee namespace {
57c9666d23SWei Yi Tee
58c9666d23SWei Yi Tee class DebugStringGenerator {
59c9666d23SWei Yi Tee public:
DebugStringGenerator(llvm::DenseMap<const AtomicBoolValue *,std::string> AtomNamesArg)60c9666d23SWei Yi Tee explicit DebugStringGenerator(
61c9666d23SWei Yi Tee llvm::DenseMap<const AtomicBoolValue *, std::string> AtomNamesArg)
62c9666d23SWei Yi Tee : Counter(0), AtomNames(std::move(AtomNamesArg)) {
63c9666d23SWei Yi Tee #ifndef NDEBUG
64c9666d23SWei Yi Tee llvm::StringSet<> Names;
65c9666d23SWei Yi Tee for (auto &N : AtomNames) {
66c9666d23SWei Yi Tee assert(Names.insert(N.second).second &&
67c9666d23SWei Yi Tee "The same name must not assigned to different atoms");
68c9666d23SWei Yi Tee }
69c9666d23SWei Yi Tee #endif
70c9666d23SWei Yi Tee }
71c9666d23SWei Yi Tee
72c9666d23SWei Yi Tee /// Returns a string representation of a boolean value `B`.
debugString(const BoolValue & B,size_t Depth=0)73c9666d23SWei Yi Tee std::string debugString(const BoolValue &B, size_t Depth = 0) {
74c9666d23SWei Yi Tee std::string S;
75c9666d23SWei Yi Tee switch (B.getKind()) {
76c9666d23SWei Yi Tee case Value::Kind::AtomicBool: {
77c9666d23SWei Yi Tee S = getAtomName(&cast<AtomicBoolValue>(B));
78c9666d23SWei Yi Tee break;
79c9666d23SWei Yi Tee }
80c9666d23SWei Yi Tee case Value::Kind::Conjunction: {
81c9666d23SWei Yi Tee auto &C = cast<ConjunctionValue>(B);
82c9666d23SWei Yi Tee auto L = debugString(C.getLeftSubValue(), Depth + 1);
83c9666d23SWei Yi Tee auto R = debugString(C.getRightSubValue(), Depth + 1);
84c9666d23SWei Yi Tee S = formatv("(and\n{0}\n{1})", L, R);
85c9666d23SWei Yi Tee break;
86c9666d23SWei Yi Tee }
87c9666d23SWei Yi Tee case Value::Kind::Disjunction: {
88c9666d23SWei Yi Tee auto &D = cast<DisjunctionValue>(B);
89c9666d23SWei Yi Tee auto L = debugString(D.getLeftSubValue(), Depth + 1);
90c9666d23SWei Yi Tee auto R = debugString(D.getRightSubValue(), Depth + 1);
91c9666d23SWei Yi Tee S = formatv("(or\n{0}\n{1})", L, R);
92c9666d23SWei Yi Tee break;
93c9666d23SWei Yi Tee }
94c9666d23SWei Yi Tee case Value::Kind::Negation: {
95c9666d23SWei Yi Tee auto &N = cast<NegationValue>(B);
96c9666d23SWei Yi Tee S = formatv("(not\n{0})", debugString(N.getSubVal(), Depth + 1));
97c9666d23SWei Yi Tee break;
98c9666d23SWei Yi Tee }
99*b5e3dac3SDmitri Gribenko case Value::Kind::Implication: {
100*b5e3dac3SDmitri Gribenko auto &IV = cast<ImplicationValue>(B);
101*b5e3dac3SDmitri Gribenko auto L = debugString(IV.getLeftSubValue(), Depth + 1);
102*b5e3dac3SDmitri Gribenko auto R = debugString(IV.getRightSubValue(), Depth + 1);
103*b5e3dac3SDmitri Gribenko S = formatv("(=>\n{0}\n{1})", L, R);
104*b5e3dac3SDmitri Gribenko break;
105*b5e3dac3SDmitri Gribenko }
106*b5e3dac3SDmitri Gribenko case Value::Kind::Biconditional: {
107*b5e3dac3SDmitri Gribenko auto &BV = cast<BiconditionalValue>(B);
108*b5e3dac3SDmitri Gribenko auto L = debugString(BV.getLeftSubValue(), Depth + 1);
109*b5e3dac3SDmitri Gribenko auto R = debugString(BV.getRightSubValue(), Depth + 1);
110*b5e3dac3SDmitri Gribenko S = formatv("(=\n{0}\n{1})", L, R);
111*b5e3dac3SDmitri Gribenko break;
112*b5e3dac3SDmitri Gribenko }
113c9666d23SWei Yi Tee default:
114c9666d23SWei Yi Tee llvm_unreachable("Unhandled value kind");
115c9666d23SWei Yi Tee }
116c9666d23SWei Yi Tee auto Indent = Depth * 4;
117c9666d23SWei Yi Tee return formatv("{0}", fmt_pad(S, Indent, 0));
118c9666d23SWei Yi Tee }
119c9666d23SWei Yi Tee
debugString(const llvm::DenseSet<BoolValue * > & Constraints)120b5414b56SDmitri Gribenko std::string debugString(const llvm::DenseSet<BoolValue *> &Constraints) {
121b5414b56SDmitri Gribenko std::vector<std::string> ConstraintsStrings;
122b5414b56SDmitri Gribenko ConstraintsStrings.reserve(Constraints.size());
123b5414b56SDmitri Gribenko for (BoolValue *Constraint : Constraints) {
124b5414b56SDmitri Gribenko ConstraintsStrings.push_back(debugString(*Constraint));
125b5414b56SDmitri Gribenko }
126b5414b56SDmitri Gribenko llvm::sort(ConstraintsStrings);
127b5414b56SDmitri Gribenko
128b5414b56SDmitri Gribenko std::string Result;
129b5414b56SDmitri Gribenko for (const std::string &S : ConstraintsStrings) {
130b5414b56SDmitri Gribenko Result += S;
131b5414b56SDmitri Gribenko Result += '\n';
132b5414b56SDmitri Gribenko }
133b5414b56SDmitri Gribenko return Result;
134b5414b56SDmitri Gribenko }
135b5414b56SDmitri Gribenko
136b8d83e80SWei Yi Tee /// Returns a string representation of a set of boolean `Constraints` and the
137b8d83e80SWei Yi Tee /// `Result` of satisfiability checking on the `Constraints`.
debugString(ArrayRef<BoolValue * > & Constraints,const Solver::Result & Result)138589ddd7fSDmitri Gribenko std::string debugString(ArrayRef<BoolValue *> &Constraints,
139b8d83e80SWei Yi Tee const Solver::Result &Result) {
140b8d83e80SWei Yi Tee auto Template = R"(
141b8d83e80SWei Yi Tee Constraints
142b8d83e80SWei Yi Tee ------------
143b8d83e80SWei Yi Tee {0:$[
144b8d83e80SWei Yi Tee
145b8d83e80SWei Yi Tee ]}
146b8d83e80SWei Yi Tee ------------
147b8d83e80SWei Yi Tee {1}.
148b8d83e80SWei Yi Tee {2}
149b8d83e80SWei Yi Tee )";
150b8d83e80SWei Yi Tee
151b8d83e80SWei Yi Tee std::vector<std::string> ConstraintsStrings;
152b8d83e80SWei Yi Tee ConstraintsStrings.reserve(Constraints.size());
153b8d83e80SWei Yi Tee for (auto &Constraint : Constraints) {
154b8d83e80SWei Yi Tee ConstraintsStrings.push_back(debugString(*Constraint));
155b8d83e80SWei Yi Tee }
156b8d83e80SWei Yi Tee
157ee6aba85SDmitri Gribenko auto StatusString = clang::dataflow::debugString(Result.getStatus());
158b8d83e80SWei Yi Tee auto Solution = Result.getSolution();
1593c849d0aSFangrui Song auto SolutionString = Solution ? "\n" + debugString(Solution.value()) : "";
160b8d83e80SWei Yi Tee
161b8d83e80SWei Yi Tee return formatv(
162b8d83e80SWei Yi Tee Template,
163b8d83e80SWei Yi Tee llvm::make_range(ConstraintsStrings.begin(), ConstraintsStrings.end()),
164b8d83e80SWei Yi Tee StatusString, SolutionString);
165b8d83e80SWei Yi Tee }
166b8d83e80SWei Yi Tee
167c9666d23SWei Yi Tee private:
168b8d83e80SWei Yi Tee /// Returns a string representation of a truth assignment to atom booleans.
debugString(const llvm::DenseMap<AtomicBoolValue *,Solver::Result::Assignment> & AtomAssignments)169b8d83e80SWei Yi Tee std::string debugString(
170b8d83e80SWei Yi Tee const llvm::DenseMap<AtomicBoolValue *, Solver::Result::Assignment>
171b8d83e80SWei Yi Tee &AtomAssignments) {
172b8d83e80SWei Yi Tee size_t MaxNameLength = 0;
173b8d83e80SWei Yi Tee for (auto &AtomName : AtomNames) {
174b8d83e80SWei Yi Tee MaxNameLength = std::max(MaxNameLength, AtomName.second.size());
175b8d83e80SWei Yi Tee }
176b8d83e80SWei Yi Tee
177b8d83e80SWei Yi Tee std::vector<std::string> Lines;
178b8d83e80SWei Yi Tee for (auto &AtomAssignment : AtomAssignments) {
179b8d83e80SWei Yi Tee auto Line = formatv("{0} = {1}",
180b8d83e80SWei Yi Tee fmt_align(getAtomName(AtomAssignment.first),
181b8d83e80SWei Yi Tee AlignStyle::Left, MaxNameLength),
182ee6aba85SDmitri Gribenko clang::dataflow::debugString(AtomAssignment.second));
183b8d83e80SWei Yi Tee Lines.push_back(Line);
184b8d83e80SWei Yi Tee }
185b5414b56SDmitri Gribenko llvm::sort(Lines);
186b8d83e80SWei Yi Tee
187b8d83e80SWei Yi Tee return formatv("{0:$[\n]}", llvm::make_range(Lines.begin(), Lines.end()));
188b8d83e80SWei Yi Tee }
189b8d83e80SWei Yi Tee
190c9666d23SWei Yi Tee /// Returns the name assigned to `Atom`, either user-specified or created by
191c9666d23SWei Yi Tee /// default rules (B0, B1, ...).
getAtomName(const AtomicBoolValue * Atom)192c9666d23SWei Yi Tee std::string getAtomName(const AtomicBoolValue *Atom) {
193c9666d23SWei Yi Tee auto Entry = AtomNames.try_emplace(Atom, formatv("B{0}", Counter));
194c9666d23SWei Yi Tee if (Entry.second) {
195c9666d23SWei Yi Tee Counter++;
196c9666d23SWei Yi Tee }
197c9666d23SWei Yi Tee return Entry.first->second;
198c9666d23SWei Yi Tee }
199c9666d23SWei Yi Tee
200c9666d23SWei Yi Tee // Keep track of number of atoms without a user-specified name, used to assign
201c9666d23SWei Yi Tee // non-repeating default names to such atoms.
202c9666d23SWei Yi Tee size_t Counter;
203c9666d23SWei Yi Tee
204c9666d23SWei Yi Tee // Keep track of names assigned to atoms.
205c9666d23SWei Yi Tee llvm::DenseMap<const AtomicBoolValue *, std::string> AtomNames;
206c9666d23SWei Yi Tee };
207c9666d23SWei Yi Tee
208c9666d23SWei Yi Tee } // namespace
209c9666d23SWei Yi Tee
210c9666d23SWei Yi Tee std::string
debugString(const BoolValue & B,llvm::DenseMap<const AtomicBoolValue *,std::string> AtomNames)211c9666d23SWei Yi Tee debugString(const BoolValue &B,
212c9666d23SWei Yi Tee llvm::DenseMap<const AtomicBoolValue *, std::string> AtomNames) {
213c9666d23SWei Yi Tee return DebugStringGenerator(std::move(AtomNames)).debugString(B);
214c9666d23SWei Yi Tee }
215c9666d23SWei Yi Tee
216b8d83e80SWei Yi Tee std::string
debugString(const llvm::DenseSet<BoolValue * > & Constraints,llvm::DenseMap<const AtomicBoolValue *,std::string> AtomNames)217b5414b56SDmitri Gribenko debugString(const llvm::DenseSet<BoolValue *> &Constraints,
218b5414b56SDmitri Gribenko llvm::DenseMap<const AtomicBoolValue *, std::string> AtomNames) {
219b5414b56SDmitri Gribenko return DebugStringGenerator(std::move(AtomNames)).debugString(Constraints);
220b5414b56SDmitri Gribenko }
221b5414b56SDmitri Gribenko
222b5414b56SDmitri Gribenko std::string
debugString(ArrayRef<BoolValue * > Constraints,const Solver::Result & Result,llvm::DenseMap<const AtomicBoolValue *,std::string> AtomNames)223589ddd7fSDmitri Gribenko debugString(ArrayRef<BoolValue *> Constraints, const Solver::Result &Result,
224b8d83e80SWei Yi Tee llvm::DenseMap<const AtomicBoolValue *, std::string> AtomNames) {
225b8d83e80SWei Yi Tee return DebugStringGenerator(std::move(AtomNames))
226b8d83e80SWei Yi Tee .debugString(Constraints, Result);
227b8d83e80SWei Yi Tee }
228b8d83e80SWei Yi Tee
229c9666d23SWei Yi Tee } // namespace dataflow
230c9666d23SWei Yi Tee } // namespace clang
231