Joos1W Compiler Framework
All Classes Functions Typedefs Pages
CFGBuilder.h
1 #pragma once
2 
3 #include <unordered_map>
4 #include <variant>
5 #include <vector>
6 
7 #include "ast/AstNode.h"
8 #include "ast/Decl.h"
9 #include "ast/DeclContext.h"
10 #include "ast/Stmt.h"
11 #include "diagnostics/Location.h"
12 #include "semantic/ConstantTypeResolver.h"
13 #include "semantic/Semantic.h"
14 #include "utils/BumpAllocator.h"
15 #include "utils/DotPrinter.h"
16 
17 namespace semantic {
18 
19 using utils::DotPrinter;
20 class CFGNode {
21 public:
22  struct EmptyExpr {};
23 
24 private:
25  friend class CFGBuilder;
26  std::pmr::vector<CFGNode*> children;
27  std::pmr::vector<CFGNode*> parents;
28  std::variant<const ast::Expr*, const ast::VarDecl*, EmptyExpr> data;
29  bool isReturn;
30  bool start;
31  bool isInfinite;
32  mutable bool isVisited;
33 
34 public:
35  CFGNode(BumpAllocator& alloc,
36  std::variant<const ast::Expr*, const ast::VarDecl*, EmptyExpr> data,
37  bool isReturn = false)
38  : children{alloc}, parents{alloc}, data{data}, isReturn{isReturn} {
39  start = false;
40  isInfinite = false;
41  isVisited = false;
42  }
43 
44  std::ostream& printDot(std::ostream& os) const {
45  std::pmr::unordered_map<const CFGNode*, int> visited;
46  DotPrinter dp{os};
47  dp.startGraph();
48  dp.print("compound=true;");
49  printDotNode(dp, visited);
50  dp.endGraph();
51  return os;
52  }
53 
54  utils::Generator<const CFGNode*> getChildren() const {
55  for(auto child : children) {
56  co_yield child;
57  }
58  }
59 
60  utils::Generator<const CFGNode*> getParents() const {
61  for(auto parent : parents) {
62  co_yield parent;
63  }
64  }
65 
66  std::optional<SourceRange> location() const {
67  if(std::holds_alternative<const ast::Expr*>(data)) {
68  return std::get<const ast::Expr*>(data)->location();
69  } else if(std::holds_alternative<const ast::VarDecl*>(data)) {
70  return std::get<const ast::VarDecl*>(data)->location();
71  } else {
72  return std::nullopt;
73  }
74  }
75  std::variant<const ast::Expr*, const ast::VarDecl*, EmptyExpr> getData() const {
76  return data;
77  }
78  bool isReturnNode() const { return isReturn; }
79  bool isStart() const { return start; }
80  bool isInfiniteLoop() const { return isInfinite; }
81  bool hasBeenVisited() const { return isVisited; }
82  void setVisited(bool val) const { isVisited = val; }
83 
84 private:
85  int printDotNode(utils::DotPrinter& dp,
86  std::pmr::unordered_map<const CFGNode*, int>& visited) const {
87  if(visited.count(this) > 0) {
88  return visited[this];
89  }
90  int id = dp.id();
91  dp.startTLabel(id);
92  if(start) {
93  dp.printTableSingleRow("Start", {"bgcolor", "lightblue"});
94  }
95  if(isReturn) {
96  dp.printTableSingleRow("Return Statement", {"bgcolor", "lightblue"});
97  }
98  if(std::holds_alternative<const ast::Expr*>(data)) {
99  std::ostringstream expr;
100  std::get<const ast::Expr*>(data)->print(expr, -1);
101  dp.printTableSingleRow("Expr", {"bgcolor", "lightblue"});
102  dp.printTableDoubleRow(
103  "expr", expr.str(), {"port", "condition"}, {"balign", "left"});
104  } else if(std::holds_alternative<const ast::VarDecl*>(data)) {
105  auto name = std::get<const ast::VarDecl*>(data)->name();
106  dp.printTableSingleRow("VarDecl", {"bgcolor", "lightblue"});
107  dp.printTableDoubleRow(
108  "expr", name, {"port", "condition"}, {"balign", "left"});
109  } else {
110  dp.printTableSingleRow("Empty Expr", {"bgcolor", "lightblue"});
111  }
112  dp.endTLabel();
113  visited[this] = id;
114  for(auto child : children) {
115  dp.printConnection(id, child->printDotNode(dp, visited));
116  }
117  return id;
118  }
119 };
120 
121 class CFGBuilder {
122  using Heap = std::pmr::memory_resource;
123  struct CFGInfo {
124  CFGNode* head;
125  std::pmr::vector<CFGNode*> leafs;
126  // Constructor for 1 leaf
127  CFGInfo(BumpAllocator& alloc, CFGNode* head, CFGNode* firstLeaf)
128  : head{head}, leafs{alloc} {
129  leafs.push_back(firstLeaf);
130  }
131  // Constructor for no leaves
132  CFGInfo(BumpAllocator& alloc, CFGNode* head) : head{head}, leafs{alloc} {}
133  };
134 
135 private:
136  CFGInfo buildIteratively(const ast::Stmt* stmt, CFGNode* parent = nullptr);
137  CFGInfo buildForStmt(const ast::ForStmt* forStmt);
138  CFGInfo buildIfStmt(const ast::IfStmt* ifStmt);
139  CFGInfo buildDeclStmt(const ast::DeclStmt* declStmt);
140  CFGInfo buildExprStmt(const ast::ExprStmt* exprStmt);
141  CFGInfo buildReturnStmt(const ast::ReturnStmt* returnStmt);
142  CFGInfo buildWhileStmt(const ast::WhileStmt* whileStmt);
143  CFGInfo buildBlockStmt(const ast::BlockStatement* blockStmt);
144 
145  void connectCFGNode(CFGNode* parent, CFGNode* child);
146  void connectLeafsToChild(CFGInfo parent, CFGNode* child);
147 
148 public:
149  CFGBuilder(diagnostics::DiagnosticEngine& diag,
150  ConstantTypeResolver* constTypeResolver, Heap* heap,
151  ast::Semantic& sema)
152  : diag{diag},
153  alloc{heap},
154  heap{heap},
155  sema{sema},
156  constTypeResolver{constTypeResolver} {}
157  CFGNode* build(const ast::Stmt* stmt) {
158  CFGInfo info = buildIteratively(stmt);
159  info.head->start = true;
160  return info.head;
161  }
162 
163 private:
164  diagnostics::DiagnosticEngine& diag;
165  SourceRange loc_;
166  mutable BumpAllocator alloc;
167  Heap* heap;
168  ast::Semantic& sema;
169  ConstantTypeResolver* constTypeResolver;
170 };
171 } // namespace semantic