llir-opt  0.0.1
Low-Level Post-Link Optimiser for OCaml and C
block.h
1 // This file if part of the llir-opt project.
2 // Licensing information can be found in the LICENSE file.
3 // (C) 2018 Nandor Licker. All rights reserved.
4 
5 #pragma once
6 
7 #include <string>
8 #include <string_view>
9 #include <vector>
10 
11 #include <llvm/ADT/ilist.h>
12 #include <llvm/ADT/ilist_node.h>
13 #include <llvm/ADT/iterator_range.h>
14 #include <llvm/IR/CFG.h>
15 #include <llvm/Support/raw_ostream.h>
16 
17 #include "core/inst.h"
18 #include "core/global.h"
19 #include "core/symbol_table.h"
20 
21 class Func;
22 class PhiInst;
23 
24 
25 
29 class Block final : public llvm::ilist_node_with_parent<Block, Func>, public Global {
30 public:
32  static constexpr Global::Kind kGlobalKind = Global::Kind::BLOCK;
33 
34 public:
35  // Type of the instruction list.
36  using InstListType = llvm::ilist<Inst>;
37 
38  // Iterator types over instructions.
39  using iterator = InstListType::iterator;
40  using reverse_iterator = InstListType::reverse_iterator;
41  using const_iterator = InstListType::const_iterator;
42  using const_reverse_iterator = InstListType::const_reverse_iterator;
43 
44  // Iterator wrapper.
45  template<typename T>
46  using iter_fwd = std::iterator<std::forward_iterator_tag, T, ptrdiff_t, T *, T *>;
47 
49  template <class BlockT, class UseIterator>
50  class PredIterator : public iter_fwd<BlockT> {
51  private:
53  UseIterator use_;
54 
55  public:
56  using pointer = typename iter_fwd<BlockT>::pointer;
57  using reference = typename iter_fwd<BlockT>::reference;
58 
59  PredIterator() = default;
60 
61  inline PredIterator(UseIterator it) : use_(it) { SkipToTerminator(); }
62 
63  inline bool operator==(const PredIterator& x) const { return use_ == x.use_; }
64  inline bool operator!=(const PredIterator& x) const { return !operator==(x); }
65 
66  inline reference operator*() const
67  {
68  return static_cast<const TerminatorInst *>(*use_)->getParent();
69  }
70 
71  inline pointer *operator->() const
72  {
73  return &operator*();
74  }
75 
76  inline PredIterator& operator++()
77  {
78  ++use_;
79  SkipToTerminator();
80  return *this;
81  }
82 
83  inline PredIterator operator++(int) {
84  PredIterator tmp = *this;
85  ++*this;
86  return tmp;
87  }
88 
89  private:
90  inline void SkipToTerminator()
91  {
92  while (!use_.atEnd()) {
93  if (!*use_ || !(*use_)->Is(Value::Kind::INST)) {
94  ++use_;
95  continue;
96  }
97 
98  if (!static_cast<const Inst *>(*use_)->IsTerminator()) {
99  ++use_;
100  continue;
101  }
102 
103  break;
104  }
105  }
106  };
107 
108  // Iterator over connected basic blocks.
109  using succ_iterator = llvm::SuccIterator<TerminatorInst, Block>;
110  using const_succ_iterator = llvm::SuccIterator<const TerminatorInst, const Block>;
113 
114  // Forward iterator wrapper.
115  template<typename It, typename T>
116  using facade_fwd = llvm::iterator_facade_base<It, std::forward_iterator_tag, T>;
117 
119  template<typename PhiT, typename IterT>
120  class PhiIterator : public facade_fwd<PhiIterator<PhiT, IterT>, PhiT> {
121  public:
123  template <typename PhiU, typename IterU>
125  : phi_(rhs.phi_)
126  {
127  }
128 
130  bool operator == (const PhiIterator &rhs) const { return phi_ == rhs.phi_; }
131 
133  PhiT &operator * () const { return *phi_; }
134 
137  {
138  auto end = phi_->getParent()->end();
139  auto it = std::next(IterT(phi_));
140  if (it != end && it->Is(Inst::Kind::PHI)) {
141  phi_ = static_cast<PhiT *>(&*it);
142  } else {
143  phi_ = nullptr;
144  }
145  return *this;
146  }
147 
150  {
151  PhiIterator it = *this;
152  *this++;
153  return it;
154  }
155 
156  private:
158  PhiIterator(PhiT *phi_) : phi_(phi_) {}
159 
160  private:
161  friend Block;
162  PhiT *phi_;
163  };
164 
165  using phi_iterator = PhiIterator<PhiInst, iterator>;
166  using const_phi_iterator = PhiIterator<const PhiInst, const_iterator>;
167 
168 public:
175  Block(
176  const std::string_view name,
177  Visibility visibility = Visibility::LOCAL
178  );
179 
183  ~Block();
184 
186  void removeFromParent() override;
188  void eraseFromParent() override;
189 
191  void AddInst(Inst *inst, Inst *before = nullptr);
192 
194  void AddPhi(PhiInst *phi);
195 
197  Func *getParent() const { return parent_; }
198 
200  TerminatorInst *GetTerminator();
201  const TerminatorInst *GetTerminator() const;
202 
204  std::optional<llvm::Align> GetAlignment() const override
205  {
206  return llvm::Align(1u);
207  }
208 
210  bool HasAddressTaken() const;
212  bool IsLandingPad() const;
214  bool IsTrap() const;
215 
217  void insert(Inst *inst, iterator it);
219  void insertAfter(Inst *inst, iterator it);
220 
222  void remove(iterator it);
224  void erase(iterator it);
226  void erase(iterator first, iterator last);
227 
229  void clear();
230 
231  // Iterator over the instructions.
232  bool empty() const { return insts_.empty(); }
233  iterator begin() { return insts_.begin(); }
234  iterator end() { return insts_.end(); }
235  const_iterator begin() const { return insts_.begin(); }
236  const_iterator end() const { return insts_.end(); }
237  reverse_iterator rbegin() { return insts_.rbegin(); }
238  reverse_iterator rend() { return insts_.rend(); }
239  const_reverse_iterator rbegin() const { return insts_.rbegin(); }
240  const_reverse_iterator rend() const { return insts_.rend(); }
241 
243  size_t size() const { return insts_.size(); }
244 
245  // Iterator over the successors.
246  succ_iterator succ_begin();
247  succ_iterator succ_end();
248  inline llvm::iterator_range<succ_iterator> successors()
249  {
250  return llvm::make_range(succ_begin(), succ_end());
251  }
252 
253  const_succ_iterator succ_begin() const;
254  const_succ_iterator succ_end() const;
255  inline llvm::iterator_range<const_succ_iterator> successors() const
256  {
257  return llvm::make_range(succ_begin(), succ_end());
258  }
259 
260  inline unsigned succ_size() const
261  {
262  return std::distance(succ_begin(), succ_end());
263  }
264 
265  inline bool succ_empty() const { return succ_begin() == succ_end(); }
266 
267  // Iterator over the predecessors.
268  inline bool pred_empty() const { return pred_begin() == pred_end(); }
269  inline unsigned pred_size() const
270  {
271  return std::distance(pred_begin(), pred_end());
272  }
273  pred_iterator pred_begin() { return pred_iterator(user_begin()); }
274  pred_iterator pred_end() { return pred_iterator(user_end()); }
275  const_pred_iterator pred_begin() const { return const_pred_iterator(user_begin()); }
276  const_pred_iterator pred_end() const { return const_pred_iterator(user_end()); }
277  inline llvm::iterator_range<pred_iterator> predecessors()
278  {
279  return llvm::make_range(pred_begin(), pred_end());
280  }
281  inline llvm::iterator_range<const_pred_iterator> predecessors() const
282  {
283  return llvm::make_range(pred_begin(), pred_end());
284  }
285 
286  // Checks whether the block lacks phi nodes.
287  bool phi_empty() const { return !begin()->Is(Inst::Kind::PHI); }
288  // Iterator over PHI nodes.
289  llvm::iterator_range<const_phi_iterator> phis() const {
290  return const_cast<Block *>(this)->phis();
291  }
292  llvm::iterator_range<phi_iterator> phis();
293 
295  iterator first_non_phi();
296 
298  Block *splitBlock(iterator I);
299 
300  // LLVM: Debug printing.
301  void printAsOperand(llvm::raw_ostream &O, bool PrintType = true) const;
302 
304  Prog *getProg() override;
305 
307  void dump(llvm::raw_ostream &os = llvm::errs()) const;
308 
309 private:
310  friend struct llvm::ilist_traits<Inst>;
311  friend struct SymbolTableListTraits<Block>;
313  void setParent(Func *parent) { parent_ = parent; }
314 
315 private:
317  Func *parent_;
319  InstListType insts_;
320 };
321 
323 inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Block &block)
324 {
325  block.dump(os);
326  return os;
327 }
Block::remove
void remove(iterator it)
Removes an instruction.
Definition: block.cpp:53
Inst
Definition: inst.h:53
Block::AddInst
void AddInst(Inst *inst, Inst *before=nullptr)
Adds an instruction to the basic block.
Definition: block.cpp:79
Func
Definition: func.h:30
Block::removeFromParent
void removeFromParent() override
Removes the global from the parent container.
Definition: block.cpp:29
Inst::IsTerminator
virtual bool IsTerminator() const
Checks if the instruction is a terminator.
Definition: inst.h:100
Block::insert
void insert(Inst *inst, iterator it)
Add an instruction to the block.
Definition: block.cpp:41
Block::eraseFromParent
void eraseFromParent() override
Removes a block from the parent.
Definition: block.cpp:35
Global::Kind
Kind
Enumeration of global kinds.
Definition: global.h:30
Block::HasAddressTaken
bool HasAddressTaken() const
Checks if the address of the block is taken.
Definition: block.cpp:134
Block::PhiIterator::PhiIterator
PhiIterator(const PhiIterator< PhiU, IterU > &rhs)
Convert from non-const to const.
Definition: block.h:124
Block::AddPhi
void AddPhi(PhiInst *phi)
Adds a PHI instruction to the basic block.
Definition: block.cpp:89
Block::splitBlock
Block * splitBlock(iterator I)
Split the block at the given iterator.
Definition: block.cpp:207
Block::PhiIterator::operator==
bool operator==(const PhiIterator &rhs) const
Check for end of iteration.
Definition: block.h:130
Block::PhiIterator::operator++
PhiIterator & operator++()
Pre-increment.
Definition: block.h:136
Block::insertAfter
void insertAfter(Inst *inst, iterator it)
Add an instruction after another in the block.
Definition: block.cpp:47
SymbolTableListTraits
Definition: symbol_table.h:33
Block::kGlobalKind
static constexpr Global::Kind kGlobalKind
Kind of the global.
Definition: block.h:32
Block::size
size_t size() const
Returns the size of the block.
Definition: block.h:243
Block::PhiIterator::operator*
PhiT & operator*() const
Return PHI node.
Definition: block.h:133
Block::getParent
Func * getParent() const
Returns a pointer to the parent block.
Definition: block.h:197
Block::IsLandingPad
bool IsLandingPad() const
Checks if the block is an exception landing pad.
Definition: block.cpp:164
Block::clear
void clear()
Clears all blocks.
Definition: block.cpp:65
Block::first_non_phi
iterator first_non_phi()
Iterator to the first non-phi instruction.
Definition: block.cpp:197
Prog
Definition: prog.h:33
Block::GetTerminator
TerminatorInst * GetTerminator()
Returns the terminator of the block.
Definition: block.cpp:119
Block::dump
void dump(llvm::raw_ostream &os=llvm::errs()) const
Dumps the textual representation of the instruction.
Definition: block.cpp:245
Block
Definition: block.h:29
Block::PhiIterator
Iterator over PHI nodes.
Definition: block.h:120
Block::getProg
Prog * getProg() override
Returns the program to which the extern belongs.
Definition: block.cpp:239
Block::Block
Block(const std::string_view name, Visibility visibility=Visibility::LOCAL)
Definition: block.cpp:17
Block::GetAlignment
std::optional< llvm::Align > GetAlignment() const override
Blocks have no known alignment.
Definition: block.h:204
PhiInst
Definition: phi.h:14
Block::erase
void erase(iterator it)
Erases an instruction.
Definition: block.cpp:59
Block::~Block
~Block()
Definition: block.cpp:24
Block::PredIterator
Iterator over the predecessors of a block.
Definition: block.h:50
Block::IsTrap
bool IsTrap() const
Checks if the block is a single trap.
Definition: block.cpp:147
Global
Definition: global.h:23