Joos1W Compiler Framework
All Classes Functions Typedefs Pages
BasicBlock.h
1 #pragma once
2 
3 #include "tir/Value.h"
4 #include "utils/DotPrinter.h"
5 #include "utils/Generator.h"
6 
7 namespace tir {
8 
9 class Instruction;
10 class Function;
11 
12 class BasicBlock final : public Value {
13  friend class Instruction;
14 
15 private:
16  // Private implementation of the iterator
17  struct iterator_pimpl {
18  // True if this iterator is after the last instruction in the list
19  bool afterEnd;
20  // True if this iterator is before the first instruction in the list
21  bool beforeBegin;
22  // The current instruction, this is never nullptr unless list is empty
23  Instruction* inst;
24  void next();
25  void prev();
26  bool equal(const iterator_pimpl& other) const {
27  return afterEnd == other.afterEnd && beforeBegin == other.beforeBegin &&
28  inst == other.inst;
29  }
30  };
31 
32  // The iterator template to support both const and non-const iterators
33  template <typename T>
34  class iterator_impl {
35  private:
36  friend class Instruction;
37  friend class BasicBlock;
38  iterator_impl(Instruction* inst, T bb, bool afterEnd, bool beforeBegin)
39  : pimpl_{afterEnd, beforeBegin, inst}, bb_{bb} {}
40 
41  public:
42  iterator_impl() : pimpl_{true, false, nullptr} {}
43  Instruction* operator*() const {
44  assert(!pimpl_.beforeBegin && !pimpl_.afterEnd);
45  return pimpl_.inst;
46  }
47  Instruction* operator->() const {
48  assert(!pimpl_.beforeBegin && !pimpl_.afterEnd);
49  return pimpl_.inst;
50  }
51  iterator_impl& operator++() {
52  pimpl_.next();
53  return *this;
54  }
55  iterator_impl& operator--() {
56  pimpl_.prev();
57  return *this;
58  }
59  bool operator==(const iterator_impl& other) const {
60  return pimpl_.equal(other.pimpl_);
61  }
62  bool operator!=(const iterator_impl& other) const {
63  return !(*this == other);
64  }
65  T getBB() const { return bb_; }
66  // Does this iterator point before the first instruction?
67  bool isBeforeFirst() const { return pimpl_.beforeBegin; }
68  // Does this iterator point past the end of the list?
69  bool isAfterLast() const { return pimpl_.afterEnd; }
70 
71  private:
72  // Private implementation of the iterator
73  iterator_pimpl pimpl_;
74  // The parent basic block, in case this iterator is nullptr
75  T bb_;
76  };
77 
78 public:
79  /**
80  * @brief The iterator class for instructions in a basic block allows us to
81  * express points before the first instruction and after the last instruction.
82  * Otherwise, a pointer to the current instruction would be sufficient.
83  *
84  * Two iterators are equal iff they express the same point in the BB,
85  * which means they must also be necessarily in the same BB.
86  *
87  * The increment and decrement moves to the previous and next iterators.
88  * The minimum iterator is therefore the one before the first instruction,
89  * and the maximum iterator is the one after the last instruction.
90  */
91  using iterator = iterator_impl<BasicBlock*>;
92 
93  // See BasicBlock::iterator
94  using const_iterator = iterator_impl<const BasicBlock*>;
95 
96 private:
97  BasicBlock(Context& ctx, Function* parent);
98 
99 public:
100  static BasicBlock* Create(Context& ctx, Function* parent) {
101  auto* buf =
102  ctx.alloc().allocate_bytes(sizeof(BasicBlock), alignof(BasicBlock));
103  return new(buf) BasicBlock{ctx, parent};
104  }
105  // Gets the parent function of this basic block
106  auto* parent() const { return parent_; }
107  // Gets an iterator to the first instruction of the block (if not empty)
108  auto begin() { return iterator{first_, this, first_ == nullptr, false}; }
109  // Gets an iterator to AFTER the last instruction of the block
110  auto end() { return iterator{last_, this, true, false}; }
111  // Const iterator
112  auto begin() const {
113  return const_iterator{first_, this, first_ == nullptr, false};
114  }
115  // Const iterator
116  auto end() const { return const_iterator{last_, this, true, false}; }
117  // Append an instruction to the end of the basic block
118  void appendAfterEnd(Instruction* instr);
119  // Insert an instruction before the first instruction in the basic block
120  void insertBeforeBegin(Instruction* instr);
121  // Print the basic block to the given output stream
122  std::ostream& print(std::ostream& os) const override;
123  // Get the terminator instruction of this basic block
124  auto* terminator() const { return last_; }
125  // Erase an instruction from the basic block
126  void erase(Instruction* instr);
127  // Erases this basic block from the parent function
128  void eraseFromParent();
129  // Prints the DOT representation of this basic block
130  int printDotNode(utils::DotPrinter&) const;
131  // Grab the sucessor basic blocks of this basic block
132  utils::Generator<BasicBlock*> successors() const;
133  // Grab the predecessor basic blocks of this basic block
134  utils::Generator<BasicBlock*> predecessors() const;
135 
136 private:
137  Instruction* first_;
138  Instruction* last_;
139  Function* parent_;
140 };
141 
142 } // namespace tir