Add debug-dot visualization for LifetimeConstraints.
PiperOrigin-RevId: 471752987
diff --git a/lifetime_analysis/analyze.cc b/lifetime_analysis/analyze.cc
index 53cc861..bbcfb0a 100644
--- a/lifetime_analysis/analyze.cc
+++ b/lifetime_analysis/analyze.cc
@@ -222,6 +222,34 @@
"}");
}
+std::string ConstraintsEdgesDot(const ObjectRepository& object_repository,
+ const LifetimeConstraints& constraints,
+ absl::string_view name_prefix) {
+ std::vector<std::string> lines;
+
+ llvm::DenseSet<Lifetime> all_lifetimes;
+ for (const auto& cstr : constraints.AllConstraints()) {
+ lines.push_back(absl::StrFormat(R"("%1$s%2$d" -> "%1$s%3$d")", name_prefix,
+ cstr.second.Id(), cstr.first.Id()));
+ all_lifetimes.insert(cstr.first);
+ all_lifetimes.insert(cstr.second);
+ }
+
+ for (auto lftm : all_lifetimes) {
+ lines.push_back(absl::StrFormat(R"("%s%d"[label="%s"])", name_prefix,
+ lftm.Id(), lftm.DebugString()));
+ }
+
+ return absl::StrJoin(lines, ";\n");
+}
+
+std::string ConstraintsDot(const ObjectRepository& object_repository,
+ const LifetimeConstraints& constraints) {
+ return absl::StrCat("digraph d {\n",
+ ConstraintsEdgesDot(object_repository, constraints, ""),
+ "}");
+}
+
std::string CfgBlockLabel(const clang::CFGBlock* block, const clang::CFG& cfg,
const clang::ASTContext& ast_context) {
std::string block_name = absl::StrCat("B", block->getBlockID());
@@ -310,6 +338,9 @@
absl::StrAppend(&result,
PointsToEdgesDot(object_repository, lattice.PointsTo(),
absl::StrCat("B", id, "_")));
+ absl::StrAppend(&result, ConstraintsEdgesDot(
+ object_repository, lattice.Constraints(),
+ absl::StrCat("B", id, "_cstr_")));
}
}
@@ -906,6 +937,8 @@
analysis.object_repository.DebugString();
(*debug_info)[func].points_to_map_dot =
PointsToGraphDot(analysis.object_repository, analysis.points_to_map);
+ (*debug_info)[func].constraints_dot =
+ ConstraintsDot(analysis.object_repository, analysis.constraints);
}
if (llvm::Error err =
diff --git a/lifetime_analysis/analyze.h b/lifetime_analysis/analyze.h
index 2dc85a1..af4a5a9 100644
--- a/lifetime_analysis/analyze.h
+++ b/lifetime_analysis/analyze.h
@@ -33,6 +33,9 @@
// A graph of the CFG in .dot file format.
std::string cfg_dot;
+
+ // A graph of the constraints in .dot file format.
+ std::string constraints_dot;
};
// Returns if the two FunctionLifetimes have the same structures, without
diff --git a/lifetime_analysis/lifetime_constraints.h b/lifetime_analysis/lifetime_constraints.h
index 70ea271..62d5f87 100644
--- a/lifetime_analysis/lifetime_constraints.h
+++ b/lifetime_analysis/lifetime_constraints.h
@@ -35,6 +35,11 @@
return outlives_constraints_ == other.outlives_constraints_;
}
+ // Accessor for debug purposes.
+ const llvm::DenseSet<std::pair<Lifetime, Lifetime>>& AllConstraints() const {
+ return outlives_constraints_;
+ }
+
private:
// Constraints of the form p.first <= p.second
llvm::DenseSet<std::pair<Lifetime, Lifetime>> outlives_constraints_;
diff --git a/lifetime_analysis/test/lifetime_analysis_test.cc b/lifetime_analysis/test/lifetime_analysis_test.cc
index b608eb6..d918d35 100644
--- a/lifetime_analysis/test/lifetime_analysis_test.cc
+++ b/lifetime_analysis/test/lifetime_analysis_test.cc
@@ -56,6 +56,9 @@
SaveDotFile(debug_info.points_to_map_dot,
absl::StrCat(func, "_points_to"), test_name,
"Points-to map of exit block");
+ SaveDotFile(debug_info.constraints_dot,
+ absl::StrCat(func, "_constraints"), test_name,
+ "Constraint set at exit block");
SaveDotFile(debug_info.cfg_dot, absl::StrCat(func, "_cfg"), test_name,
"Control-flow graph");
}