llir-opt  0.0.1
Low-Level Post-Link Optimiser for OCaml and C
symbolic_pointer.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 <optional>
8 #include <set>
9 #include <unordered_map>
10 #include <unordered_set>
11 #include <variant>
12 
13 #include <llvm/Support/raw_ostream.h>
14 
15 #include "core/adt/id.h"
16 #include "core/adt/hash.h"
17 #include "core/adt/bitset.h"
18 
19 class Block;
20 class CallSite;
21 class Extern;
22 class Func;
23 class Atom;
24 class SymbolicObject;
25 class SymbolicFrame;
26 
27 
28 
32 class SymbolicAddress final {
33 public:
35  enum class Kind : uint8_t {
36  OBJECT,
37  OBJECT_RANGE,
38  EXTERN,
39  EXTERN_RANGE,
40  FUNC,
41  BLOCK,
42  STACK,
43  };
44 
46  class AddrObject {
47  public:
53  int64_t Offset;
54 
55  private:
56  friend class SymbolicAddress;
57 
58  AddrObject(ID<SymbolicObject> object, int64_t offset)
59  : K(Kind::OBJECT), Object(object), Offset(offset)
60  {
61  }
62  };
63 
66  public:
71 
72  private:
73  friend class SymbolicAddress;
74 
76  : K(Kind::OBJECT_RANGE), Object(object)
77  {
78  }
79  };
80 
82  class AddrExtern {
83  public:
89  int64_t Offset;
90 
91  private:
92  friend class SymbolicAddress;
93 
94  AddrExtern(Extern *symbol, int64_t offset)
95  : K(Kind::EXTERN), Symbol(symbol), Offset(offset)
96  {
97  }
98  };
99 
102  public:
107 
108  private:
109  friend class SymbolicAddress;
110 
111  AddrExternRange(Extern *symbol)
112  : K(Kind::EXTERN_RANGE), Symbol(symbol)
113  {
114  }
115  };
116 
118  class AddrFunc {
119  public:
124 
125  private:
126  friend class SymbolicAddress;
127 
128  AddrFunc(ID<Func> func) : K(Kind::FUNC), F(func) { }
129  };
130 
132  class AddrBlock {
133  public:
138 
139  private:
140  friend class SymbolicAddress;
141 
142  AddrBlock(Block *block) : K(Kind::BLOCK), B(block) { }
143  };
144 
146  class AddrStack {
147  public:
152 
153  private:
154  friend class SymbolicAddress;
155 
156  AddrStack(ID<SymbolicFrame> frame) : K(Kind::STACK), Frame(frame) { }
157  };
158 
159 public:
162  const std::pair
163  < std::unordered_map<int64_t, BitSet<SymbolicObject>>::const_iterator
165  : v_(*arg.second, arg.first->first)
166  {
167  }
168 
171  : v_(*arg)
172  {
173  }
175  SymbolicAddress(std::unordered_map<Extern *, int64_t>::const_iterator arg)
176  : v_(arg->first, arg->second)
177  {
178  }
180  SymbolicAddress(std::unordered_set<Extern *>::const_iterator arg)
181  : v_(*arg)
182  {
183  }
186  : v_(*func)
187  {
188  }
190  SymbolicAddress(std::unordered_set<Block *>::const_iterator block)
191  : v_(*block)
192  {
193  }
196  : v_(*stack)
197  {
198  }
199 
201  Kind GetKind() const { return v_.K; }
202 
204  const AddrObject &AsObject() const { return v_.O; }
205  const AddrObjectRange &AsObjectRange() const { return v_.OR; }
206  const AddrExtern &AsExtern() const { return v_.E; }
207  const AddrExternRange &AsExternRange() const { return v_.ER; }
208  const AddrFunc &AsFunc() const { return v_.F; }
209  const AddrBlock &AsBlock() const { return v_.B; }
210  const AddrStack &AsStack() const { return v_.S; }
211 
213  bool IsPrecise() const;
214 
216  const AddrObject *ToObject() const
217  {
218  return v_.K == Kind::OBJECT ? &v_.O : nullptr;
219  }
220 
223  {
224  return v_.K == Kind::OBJECT_RANGE ? &v_.OR : nullptr;
225  }
226 
228  bool operator==(const SymbolicAddress &that) const;
229 
231  void dump(llvm::raw_ostream &os) const;
232 
233 private:
235  union P {
236  Kind K;
237  AddrObject O;
238  AddrObjectRange OR;
239  AddrExtern E;
240  AddrExternRange ER;
241  AddrFunc F;
242  AddrBlock B;
243  AddrStack S;
244 
245  P(ID<SymbolicObject> object, int64_t offset) : O(object, offset) { }
246  P(ID<SymbolicObject> object) : OR(object) { }
247 
248  P(Extern *symbol, int64_t off) : E(symbol, off) { }
249  P(Extern *symbol) : ER(symbol) { }
250 
251  P(ID<Func> func) : F(func) { }
252  P(Block *block) : B(block) { }
253  P(ID<SymbolicFrame> stack) : S(stack) { }
254  } v_;
255 };
256 
258 inline llvm::raw_ostream &operator<<(
259  llvm::raw_ostream &os,
260  const SymbolicAddress &address)
261 {
262  address.dump(os);
263  return os;
264 }
265 
266 
270 class SymbolicPointer final {
271 public:
272  using Ref = std::shared_ptr<SymbolicPointer>;
273 
274  using ObjectMap = std::unordered_map<int64_t, BitSet<SymbolicObject>>;
276  using ExternMap = std::unordered_map<Extern *, int64_t>;
277  using ExternRangeMap = std::unordered_set<Extern *>;
278  using FuncMap = BitSet<Func>;
279  using BlockMap = std::unordered_set<Block *>;
281 
282  class address_iterator : public std::iterator
283  < std::forward_iterator_tag
284  , SymbolicAddress
285  >
286  {
287  public:
288  address_iterator() : pointer_(nullptr) {}
289 
290  template <typename It>
291  address_iterator(It it, const SymbolicPointer *pointer)
292  : pointer_(pointer)
293  , it_(it)
294  , current_(SymbolicAddress(it))
295  {
296  }
297 
298  bool operator==(const address_iterator &that) const
299  {
300  return current_ == that.current_;
301  }
302  bool operator!=(const address_iterator &that) const
303  {
304  return !(*this == that);
305  }
306 
307  address_iterator &operator++();
308  address_iterator operator++(int)
309  {
310  auto tmp = *this;
311  ++*this;
312  return tmp;
313  }
314 
315  const SymbolicAddress &operator*() const { return *current_; }
316  const SymbolicAddress *operator->() const { return &operator*(); }
317 
318  private:
320  const SymbolicPointer *pointer_;
322  std::optional<SymbolicAddress> current_;
324  std::optional<std::variant<
325  std::pair<ObjectMap::const_iterator, BitSet<SymbolicObject>::iterator>,
326  ObjectRangeMap::iterator,
327  ExternMap::const_iterator,
328  ExternRangeMap::const_iterator,
329  FuncMap::iterator,
330  BlockMap::const_iterator,
331  StackMap::iterator
332  >> it_;
333  };
334 
335  using func_iterator = FuncMap::iterator;
336  using block_iterator = BlockMap::const_iterator;
337  using stack_iterator = StackMap::iterator;
338 
339 public:
340  SymbolicPointer();
341  SymbolicPointer(ID<SymbolicObject> object, int64_t offset);
342  SymbolicPointer(Extern *object, int64_t offset);
344  SymbolicPointer(Block *block);
346  ~SymbolicPointer();
347 
349  bool operator==(const SymbolicPointer &that) const;
350 
352  void Add(ID<SymbolicObject> object) { objectRanges_.Insert(object); }
354  void Add(ID<SymbolicObject> object, int64_t offset);
356  void Add(Extern *e, int64_t offset);
358  void Add(Extern *e) { externRanges_.insert(e); }
360  void Add(ID<Func> f) { funcPointers_.Insert(f); }
362  void Add(const BitSet<Func> &funcs) { funcPointers_.Union(funcs); }
364  void Add(Block *b) { blockPointers_.insert(b); }
366  void Add(ID<SymbolicFrame> frame) { stackPointers_.Insert(frame); }
368  void Add(const BitSet<SymbolicFrame> &frames) { stackPointers_.Union(frames); }
370  void Add(const BitSet<SymbolicObject> &range) { objectRanges_.Union(range); }
371 
373  Ref Offset(int64_t offset) const;
375  Ref Decay() const;
376 
378  void Merge(const Ref &that);
379 
381  [[nodiscard]] Ref LUB(const Ref &that) const
382  {
383  Ref lub = std::make_shared<SymbolicPointer>(*this);
384  lub->Merge(that);
385  return lub;
386  }
387 
389  void dump(llvm::raw_ostream &os) const;
390 
392  bool empty() const { return begin() == end(); }
394  address_iterator begin() const;
395  address_iterator end() const { return address_iterator(); }
396 
398  size_t func_size() const { return funcPointers_.Size(); }
399  func_iterator func_begin() const { return funcPointers_.begin(); }
400  func_iterator func_end() const { return funcPointers_.end(); }
401  llvm::iterator_range<func_iterator> funcs() const
402  {
403  return llvm::make_range(func_begin(), func_end());
404  }
405 
407  size_t block_size() const { return std::distance(block_begin(), block_end()); }
408  block_iterator block_begin() const { return blockPointers_.begin(); }
409  block_iterator block_end() const { return blockPointers_.end(); }
410  llvm::iterator_range<block_iterator> blocks() const
411  {
412  return llvm::make_range(block_begin(), block_end());
413  }
414 
416  size_t stack_size() const { return stackPointers_.Size(); }
417  stack_iterator stack_begin() const { return stackPointers_.begin(); }
418  stack_iterator stack_end() const { return stackPointers_.end(); }
419  llvm::iterator_range<stack_iterator> stacks() const
420  {
421  return llvm::make_range(stack_begin(), stack_end());
422  }
423 
424 private:
425  friend class address_iterator;
427  ObjectMap objectPointers_;
429  ObjectRangeMap objectRanges_;
431  ExternMap externPointers_;
433  ExternRangeMap externRanges_;
435  FuncMap funcPointers_;
437  BlockMap blockPointers_;
439  StackMap stackPointers_;
440 };
441 
443 inline llvm::raw_ostream &operator<<(
444  llvm::raw_ostream &os,
445  const SymbolicPointer &sym)
446 {
447  sym.dump(os);
448  return os;
449 }
SymbolicAddress::AddrObject::Object
ID< SymbolicObject > Object
Object symbol.
Definition: symbolic_pointer.h:51
SymbolicAddress::AddrStack::K
Kind K
Kind of the symbol.
Definition: symbolic_pointer.h:149
SymbolicAddress::AddrExternRange::K
Kind K
Kind of the symbol.
Definition: symbolic_pointer.h:104
SymbolicAddress::SymbolicAddress
SymbolicAddress(std::unordered_set< Block * >::const_iterator block)
Constructs an address to a block.
Definition: symbolic_pointer.h:190
SymbolicPointer
Definition: symbolic_pointer.h:270
SymbolicPointer::func_size
size_t func_size() const
Iterator over functions.
Definition: symbolic_pointer.h:398
Func
Definition: func.h:30
BitSet::Size
size_t Size() const
Returns the size of the document.
Definition: bitset.h:516
SymbolicAddress::SymbolicAddress
SymbolicAddress(std::unordered_set< Extern * >::const_iterator arg)
Construct an address to a specific location.
Definition: symbolic_pointer.h:180
SymbolicAddress::ToObjectRange
const AddrObjectRange * ToObjectRange() const
Attempt to convert to a global.
Definition: symbolic_pointer.h:222
SymbolicAddress::AddrExternRange::Symbol
Extern * Symbol
Extern symbol.
Definition: symbolic_pointer.h:106
SymbolicPointer::Add
void Add(ID< SymbolicFrame > frame)
Adds a stack frame to the pointer.
Definition: symbolic_pointer.h:366
SymbolicPointer::stack_size
size_t stack_size() const
Iterator over stacks.
Definition: symbolic_pointer.h:416
Atom
Definition: atom.h:23
BitSet::begin
iterator begin() const
Start iterator.
Definition: bitset.h:356
SymbolicAddress::operator==
bool operator==(const SymbolicAddress &that) const
Compares two sets of pointers for equality.
Definition: symbolic_pointer.cpp:16
SymbolicPointer::Add
void Add(ID< Func > f)
Add a function to the pointer.
Definition: symbolic_pointer.h:360
SymbolicPointer::block_size
size_t block_size() const
Iterator over blocks.
Definition: symbolic_pointer.h:407
SymbolicPointer::Add
void Add(const BitSet< SymbolicFrame > &frames)
Add a range of stack pointers.
Definition: symbolic_pointer.h:368
SymbolicAddress::Kind
Kind
Enumeration of address kinds.
Definition: symbolic_pointer.h:35
SymbolicObject
Definition: symbolic_object.h:26
SymbolicAddress::AddrObject::K
Kind K
Kind of the symbol.
Definition: symbolic_pointer.h:49
SymbolicAddress::ToObject
const AddrObject * ToObject() const
Attempt to convert to a global.
Definition: symbolic_pointer.h:216
SymbolicPointer::address_iterator
Definition: symbolic_pointer.h:282
BitSet::end
iterator end() const
End iterator.
Definition: bitset.h:362
ID< SymbolicObject >
SymbolicAddress::AddrExternRange
Range of an entire object.
Definition: symbolic_pointer.h:101
SymbolicAddress::IsPrecise
bool IsPrecise() const
Checks whether the pointer is precise.
Definition: symbolic_pointer.cpp:85
Object
Definition: object.h:43
SymbolicPointer::begin
address_iterator begin() const
Iterator over pointers contained in the set.
Definition: symbolic_pointer.cpp:472
SymbolicPointer::Add
void Add(Block *b)
Adds a block to the pointer.
Definition: symbolic_pointer.h:364
SymbolicAddress::AddrBlock::B
Block * B
Pointer to the function.
Definition: symbolic_pointer.h:137
SymbolicAddress::AddrFunc
Pointer to a function.
Definition: symbolic_pointer.h:118
SymbolicAddress::SymbolicAddress
SymbolicAddress(const std::pair< std::unordered_map< int64_t, BitSet< SymbolicObject >>::const_iterator, BitSet< SymbolicObject >::iterator > &arg)
Construct an address to a specific location.
Definition: symbolic_pointer.h:161
SymbolicAddress::AddrExtern::K
Kind K
Kind of the symbol.
Definition: symbolic_pointer.h:85
SymbolicAddress::AddrExtern::Symbol
Extern * Symbol
Extern symbol.
Definition: symbolic_pointer.h:87
BitSet< SymbolicObject >
SymbolicAddress::AsObject
const AddrObject & AsObject() const
Access the actual pointer kind.
Definition: symbolic_pointer.h:204
SymbolicAddress::AddrFunc::F
ID< Func > F
Pointer to the function.
Definition: symbolic_pointer.h:123
SymbolicAddress::dump
void dump(llvm::raw_ostream &os) const
Prints the address.
Definition: symbolic_pointer.cpp:49
SymbolicPointer::empty
bool empty() const
Checks whether the pointer points to anything.
Definition: symbolic_pointer.h:392
SymbolicPointer::LUB
Ref LUB(const Ref &that) const
Computes the least-upper-bound.
Definition: symbolic_pointer.h:381
SymbolicPointer::Add
void Add(const BitSet< SymbolicObject > &range)
Add a range of pointers.
Definition: symbolic_pointer.h:370
SymbolicAddress::SymbolicAddress
SymbolicAddress(BitSet< SymbolicFrame >::iterator stack)
Constructs an address to a stack frame.
Definition: symbolic_pointer.h:195
SymbolicAddress::AddrObjectRange::Object
ID< SymbolicObject > Object
Object symbol.
Definition: symbolic_pointer.h:70
SymbolicPointer::Add
void Add(ID< SymbolicObject > object)
Add a global to the pointer.
Definition: symbolic_pointer.h:352
BitSet::Insert
bool Insert(const ID< T > &item)
Inserts an item into the bitset.
Definition: bitset.h:391
SymbolicAddress::SymbolicAddress
SymbolicAddress(BitSet< Func >::iterator func)
Constructs an address to a frame object.
Definition: symbolic_pointer.h:185
SymbolicAddress::AddrBlock::K
Kind K
Kind of the symbol.
Definition: symbolic_pointer.h:135
SymbolicAddress::AddrFunc::K
Kind K
Kind of the symbol.
Definition: symbolic_pointer.h:121
SymbolicAddress::AddrObjectRange::K
Kind K
Kind of the symbol.
Definition: symbolic_pointer.h:68
Ref
Definition: ref.h:63
SymbolicPointer::operator==
bool operator==(const SymbolicPointer &that) const
Compares two sets of pointers for equality.
Definition: symbolic_pointer.cpp:500
SymbolicFrame
Definition: symbolic_frame.h:29
SymbolicPointer::Offset
Ref Offset(int64_t offset) const
Offset the pointer.
Definition: symbolic_pointer.cpp:326
SymbolicAddress::AddrExtern::Offset
int64_t Offset
Offset into the symbol.
Definition: symbolic_pointer.h:89
SymbolicAddress::GetKind
Kind GetKind() const
Returns the address kind.
Definition: symbolic_pointer.h:201
SymbolicAddress::AddrObject
Exact object address.
Definition: symbolic_pointer.h:46
Block
Definition: block.h:29
SymbolicAddress::AddrStack
Pointer to a stack frame.
Definition: symbolic_pointer.h:146
SymbolicAddress::SymbolicAddress
SymbolicAddress(BitSet< SymbolicObject >::iterator arg)
Construct an address to a specific location.
Definition: symbolic_pointer.h:170
BitSet::Union
unsigned Union(const BitSet &that)
Definition: bitset.h:434
SymbolicPointer::Merge
void Merge(const Ref &that)
Computes the least-upper-bound in place.
Definition: symbolic_pointer.cpp:358
SymbolicPointer::Decay
Ref Decay() const
Decays the pointer to ranges.
Definition: symbolic_pointer.cpp:342
SymbolicAddress::AddrObject::Offset
int64_t Offset
Offset into the symbol.
Definition: symbolic_pointer.h:53
Extern
Definition: extern.h:20
SymbolicAddress::AddrBlock
Pointer to a block.
Definition: symbolic_pointer.h:132
SymbolicPointer::Add
void Add(Extern *e)
Adds an extern to the pointer.
Definition: symbolic_pointer.h:358
SymbolicPointer::dump
void dump(llvm::raw_ostream &os) const
Dump the textual representation to a stream.
Definition: symbolic_pointer.cpp:454
SymbolicAddress::SymbolicAddress
SymbolicAddress(std::unordered_map< Extern *, int64_t >::const_iterator arg)
Construct an address to a specific location.
Definition: symbolic_pointer.h:175
SymbolicPointer::Add
void Add(const BitSet< Func > &funcs)
Add a range of functions to the pointer.
Definition: symbolic_pointer.h:362
SymbolicAddress
Definition: symbolic_pointer.h:32
SymbolicAddress::AddrExtern
Exact external address.
Definition: symbolic_pointer.h:82
SymbolicAddress::AddrStack::Frame
ID< SymbolicFrame > Frame
Index of the frame.
Definition: symbolic_pointer.h:151
SymbolicAddress::AddrObjectRange
Range of an entire object.
Definition: symbolic_pointer.h:65