CGCleanup.h revision 226890
10Sduke//===-- CGCleanup.h - Classes for cleanups IR generation --------*- C++ -*-===//
23581Sjjg//
30Sduke//                     The LLVM Compiler Infrastructure
40Sduke//
50Sduke// This file is distributed under the University of Illinois Open Source
60Sduke// License. See LICENSE.TXT for details.
70Sduke//
80Sduke//===----------------------------------------------------------------------===//
90Sduke//
100Sduke// These classes support the generation of LLVM IR for cleanups.
110Sduke//
120Sduke//===----------------------------------------------------------------------===//
130Sduke
140Sduke#ifndef CLANG_CODEGEN_CGCLEANUP_H
150Sduke#define CLANG_CODEGEN_CGCLEANUP_H
160Sduke
170Sduke/// EHScopeStack is defined in CodeGenFunction.h, but its
180Sduke/// implementation is in this file and in CGCleanup.cpp.
19553Sohair#include "CodeGenFunction.h"
20553Sohair
21553Sohairnamespace llvm {
220Sduke  class Value;
230Sduke  class BasicBlock;
240Sduke}
250Sduke
260Sdukenamespace clang {
270Sdukenamespace CodeGen {
280Sduke
292933Sakulyakh/// A protected scope for zero-cost EH handling.
303581Sjjgclass EHScope {
310Sduke  llvm::BasicBlock *CachedLandingPad;
320Sduke  llvm::BasicBlock *CachedEHDispatchBlock;
330Sduke
340Sduke  EHScopeStack::stable_iterator EnclosingEHScope;
350Sduke
360Sduke  class CommonBitFields {
373581Sjjg    friend class EHScope;
380Sduke    unsigned Kind : 2;
393581Sjjg  };
400Sduke  enum { NumCommonBits = 2 };
410Sduke
420Sdukeprotected:
430Sduke  class CatchBitFields {
440Sduke    friend class EHCatchScope;
450Sduke    unsigned : NumCommonBits;
460Sduke
470Sduke    unsigned NumHandlers : 32 - NumCommonBits;
480Sduke  };
490Sduke
500Sduke  class CleanupBitFields {
510Sduke    friend class EHCleanupScope;
520Sduke    unsigned : NumCommonBits;
530Sduke
540Sduke    /// Whether this cleanup needs to be run along normal edges.
550Sduke    unsigned IsNormalCleanup : 1;
560Sduke
570Sduke    /// Whether this cleanup needs to be run along exception edges.
58    unsigned IsEHCleanup : 1;
59
60    /// Whether this cleanup is currently active.
61    unsigned IsActive : 1;
62
63    /// Whether the normal cleanup should test the activation flag.
64    unsigned TestFlagInNormalCleanup : 1;
65
66    /// Whether the EH cleanup should test the activation flag.
67    unsigned TestFlagInEHCleanup : 1;
68
69    /// The amount of extra storage needed by the Cleanup.
70    /// Always a multiple of the scope-stack alignment.
71    unsigned CleanupSize : 12;
72
73    /// The number of fixups required by enclosing scopes (not including
74    /// this one).  If this is the top cleanup scope, all the fixups
75    /// from this index onwards belong to this scope.
76    unsigned FixupDepth : 32 - 17 - NumCommonBits; // currently 13
77  };
78
79  class FilterBitFields {
80    friend class EHFilterScope;
81    unsigned : NumCommonBits;
82
83    unsigned NumFilters : 32 - NumCommonBits;
84  };
85
86  union {
87    CommonBitFields CommonBits;
88    CatchBitFields CatchBits;
89    CleanupBitFields CleanupBits;
90    FilterBitFields FilterBits;
91  };
92
93public:
94  enum Kind { Cleanup, Catch, Terminate, Filter };
95
96  EHScope(Kind kind, EHScopeStack::stable_iterator enclosingEHScope)
97    : CachedLandingPad(0), CachedEHDispatchBlock(0),
98      EnclosingEHScope(enclosingEHScope) {
99    CommonBits.Kind = kind;
100  }
101
102  Kind getKind() const { return static_cast<Kind>(CommonBits.Kind); }
103
104  llvm::BasicBlock *getCachedLandingPad() const {
105    return CachedLandingPad;
106  }
107
108  void setCachedLandingPad(llvm::BasicBlock *block) {
109    CachedLandingPad = block;
110  }
111
112  llvm::BasicBlock *getCachedEHDispatchBlock() const {
113    return CachedEHDispatchBlock;
114  }
115
116  void setCachedEHDispatchBlock(llvm::BasicBlock *block) {
117    CachedEHDispatchBlock = block;
118  }
119
120  bool hasEHBranches() const {
121    if (llvm::BasicBlock *block = getCachedEHDispatchBlock())
122      return !block->use_empty();
123    return false;
124  }
125
126  EHScopeStack::stable_iterator getEnclosingEHScope() const {
127    return EnclosingEHScope;
128  }
129};
130
131/// A scope which attempts to handle some, possibly all, types of
132/// exceptions.
133///
134/// Objective C @finally blocks are represented using a cleanup scope
135/// after the catch scope.
136class EHCatchScope : public EHScope {
137  // In effect, we have a flexible array member
138  //   Handler Handlers[0];
139  // But that's only standard in C99, not C++, so we have to do
140  // annoying pointer arithmetic instead.
141
142public:
143  struct Handler {
144    /// A type info value, or null (C++ null, not an LLVM null pointer)
145    /// for a catch-all.
146    llvm::Value *Type;
147
148    /// The catch handler for this type.
149    llvm::BasicBlock *Block;
150
151    bool isCatchAll() const { return Type == 0; }
152  };
153
154private:
155  friend class EHScopeStack;
156
157  Handler *getHandlers() {
158    return reinterpret_cast<Handler*>(this+1);
159  }
160
161  const Handler *getHandlers() const {
162    return reinterpret_cast<const Handler*>(this+1);
163  }
164
165public:
166  static size_t getSizeForNumHandlers(unsigned N) {
167    return sizeof(EHCatchScope) + N * sizeof(Handler);
168  }
169
170  EHCatchScope(unsigned numHandlers,
171               EHScopeStack::stable_iterator enclosingEHScope)
172    : EHScope(Catch, enclosingEHScope) {
173    CatchBits.NumHandlers = numHandlers;
174  }
175
176  unsigned getNumHandlers() const {
177    return CatchBits.NumHandlers;
178  }
179
180  void setCatchAllHandler(unsigned I, llvm::BasicBlock *Block) {
181    setHandler(I, /*catchall*/ 0, Block);
182  }
183
184  void setHandler(unsigned I, llvm::Value *Type, llvm::BasicBlock *Block) {
185    assert(I < getNumHandlers());
186    getHandlers()[I].Type = Type;
187    getHandlers()[I].Block = Block;
188  }
189
190  const Handler &getHandler(unsigned I) const {
191    assert(I < getNumHandlers());
192    return getHandlers()[I];
193  }
194
195  typedef const Handler *iterator;
196  iterator begin() const { return getHandlers(); }
197  iterator end() const { return getHandlers() + getNumHandlers(); }
198
199  static bool classof(const EHScope *Scope) {
200    return Scope->getKind() == Catch;
201  }
202};
203
204/// A cleanup scope which generates the cleanup blocks lazily.
205class EHCleanupScope : public EHScope {
206  /// The nearest normal cleanup scope enclosing this one.
207  EHScopeStack::stable_iterator EnclosingNormal;
208
209  /// The nearest EH scope enclosing this one.
210  EHScopeStack::stable_iterator EnclosingEH;
211
212  /// The dual entry/exit block along the normal edge.  This is lazily
213  /// created if needed before the cleanup is popped.
214  llvm::BasicBlock *NormalBlock;
215
216  /// An optional i1 variable indicating whether this cleanup has been
217  /// activated yet.
218  llvm::AllocaInst *ActiveFlag;
219
220  /// Extra information required for cleanups that have resolved
221  /// branches through them.  This has to be allocated on the side
222  /// because everything on the cleanup stack has be trivially
223  /// movable.
224  struct ExtInfo {
225    /// The destinations of normal branch-afters and branch-throughs.
226    llvm::SmallPtrSet<llvm::BasicBlock*, 4> Branches;
227
228    /// Normal branch-afters.
229    SmallVector<std::pair<llvm::BasicBlock*,llvm::ConstantInt*>, 4>
230      BranchAfters;
231  };
232  mutable struct ExtInfo *ExtInfo;
233
234  struct ExtInfo &getExtInfo() {
235    if (!ExtInfo) ExtInfo = new struct ExtInfo();
236    return *ExtInfo;
237  }
238
239  const struct ExtInfo &getExtInfo() const {
240    if (!ExtInfo) ExtInfo = new struct ExtInfo();
241    return *ExtInfo;
242  }
243
244public:
245  /// Gets the size required for a lazy cleanup scope with the given
246  /// cleanup-data requirements.
247  static size_t getSizeForCleanupSize(size_t Size) {
248    return sizeof(EHCleanupScope) + Size;
249  }
250
251  size_t getAllocatedSize() const {
252    return sizeof(EHCleanupScope) + CleanupBits.CleanupSize;
253  }
254
255  EHCleanupScope(bool isNormal, bool isEH, bool isActive,
256                 unsigned cleanupSize, unsigned fixupDepth,
257                 EHScopeStack::stable_iterator enclosingNormal,
258                 EHScopeStack::stable_iterator enclosingEH)
259    : EHScope(EHScope::Cleanup, enclosingEH), EnclosingNormal(enclosingNormal),
260      NormalBlock(0), ActiveFlag(0), ExtInfo(0) {
261    CleanupBits.IsNormalCleanup = isNormal;
262    CleanupBits.IsEHCleanup = isEH;
263    CleanupBits.IsActive = isActive;
264    CleanupBits.TestFlagInNormalCleanup = false;
265    CleanupBits.TestFlagInEHCleanup = false;
266    CleanupBits.CleanupSize = cleanupSize;
267    CleanupBits.FixupDepth = fixupDepth;
268
269    assert(CleanupBits.CleanupSize == cleanupSize && "cleanup size overflow");
270  }
271
272  ~EHCleanupScope() {
273    delete ExtInfo;
274  }
275
276  bool isNormalCleanup() const { return CleanupBits.IsNormalCleanup; }
277  llvm::BasicBlock *getNormalBlock() const { return NormalBlock; }
278  void setNormalBlock(llvm::BasicBlock *BB) { NormalBlock = BB; }
279
280  bool isEHCleanup() const { return CleanupBits.IsEHCleanup; }
281  llvm::BasicBlock *getEHBlock() const { return getCachedEHDispatchBlock(); }
282  void setEHBlock(llvm::BasicBlock *BB) { setCachedEHDispatchBlock(BB); }
283
284  bool isActive() const { return CleanupBits.IsActive; }
285  void setActive(bool A) { CleanupBits.IsActive = A; }
286
287  llvm::AllocaInst *getActiveFlag() const { return ActiveFlag; }
288  void setActiveFlag(llvm::AllocaInst *Var) { ActiveFlag = Var; }
289
290  void setTestFlagInNormalCleanup() {
291    CleanupBits.TestFlagInNormalCleanup = true;
292  }
293  bool shouldTestFlagInNormalCleanup() const {
294    return CleanupBits.TestFlagInNormalCleanup;
295  }
296
297  void setTestFlagInEHCleanup() {
298    CleanupBits.TestFlagInEHCleanup = true;
299  }
300  bool shouldTestFlagInEHCleanup() const {
301    return CleanupBits.TestFlagInEHCleanup;
302  }
303
304  unsigned getFixupDepth() const { return CleanupBits.FixupDepth; }
305  EHScopeStack::stable_iterator getEnclosingNormalCleanup() const {
306    return EnclosingNormal;
307  }
308
309  size_t getCleanupSize() const { return CleanupBits.CleanupSize; }
310  void *getCleanupBuffer() { return this + 1; }
311
312  EHScopeStack::Cleanup *getCleanup() {
313    return reinterpret_cast<EHScopeStack::Cleanup*>(getCleanupBuffer());
314  }
315
316  /// True if this cleanup scope has any branch-afters or branch-throughs.
317  bool hasBranches() const { return ExtInfo && !ExtInfo->Branches.empty(); }
318
319  /// Add a branch-after to this cleanup scope.  A branch-after is a
320  /// branch from a point protected by this (normal) cleanup to a
321  /// point in the normal cleanup scope immediately containing it.
322  /// For example,
323  ///   for (;;) { A a; break; }
324  /// contains a branch-after.
325  ///
326  /// Branch-afters each have their own destination out of the
327  /// cleanup, guaranteed distinct from anything else threaded through
328  /// it.  Therefore branch-afters usually force a switch after the
329  /// cleanup.
330  void addBranchAfter(llvm::ConstantInt *Index,
331                      llvm::BasicBlock *Block) {
332    struct ExtInfo &ExtInfo = getExtInfo();
333    if (ExtInfo.Branches.insert(Block))
334      ExtInfo.BranchAfters.push_back(std::make_pair(Block, Index));
335  }
336
337  /// Return the number of unique branch-afters on this scope.
338  unsigned getNumBranchAfters() const {
339    return ExtInfo ? ExtInfo->BranchAfters.size() : 0;
340  }
341
342  llvm::BasicBlock *getBranchAfterBlock(unsigned I) const {
343    assert(I < getNumBranchAfters());
344    return ExtInfo->BranchAfters[I].first;
345  }
346
347  llvm::ConstantInt *getBranchAfterIndex(unsigned I) const {
348    assert(I < getNumBranchAfters());
349    return ExtInfo->BranchAfters[I].second;
350  }
351
352  /// Add a branch-through to this cleanup scope.  A branch-through is
353  /// a branch from a scope protected by this (normal) cleanup to an
354  /// enclosing scope other than the immediately-enclosing normal
355  /// cleanup scope.
356  ///
357  /// In the following example, the branch through B's scope is a
358  /// branch-through, while the branch through A's scope is a
359  /// branch-after:
360  ///   for (;;) { A a; B b; break; }
361  ///
362  /// All branch-throughs have a common destination out of the
363  /// cleanup, one possibly shared with the fall-through.  Therefore
364  /// branch-throughs usually don't force a switch after the cleanup.
365  ///
366  /// \return true if the branch-through was new to this scope
367  bool addBranchThrough(llvm::BasicBlock *Block) {
368    return getExtInfo().Branches.insert(Block);
369  }
370
371  /// Determines if this cleanup scope has any branch throughs.
372  bool hasBranchThroughs() const {
373    if (!ExtInfo) return false;
374    return (ExtInfo->BranchAfters.size() != ExtInfo->Branches.size());
375  }
376
377  static bool classof(const EHScope *Scope) {
378    return (Scope->getKind() == Cleanup);
379  }
380};
381
382/// An exceptions scope which filters exceptions thrown through it.
383/// Only exceptions matching the filter types will be permitted to be
384/// thrown.
385///
386/// This is used to implement C++ exception specifications.
387class EHFilterScope : public EHScope {
388  // Essentially ends in a flexible array member:
389  // llvm::Value *FilterTypes[0];
390
391  llvm::Value **getFilters() {
392    return reinterpret_cast<llvm::Value**>(this+1);
393  }
394
395  llvm::Value * const *getFilters() const {
396    return reinterpret_cast<llvm::Value* const *>(this+1);
397  }
398
399public:
400  EHFilterScope(unsigned numFilters)
401    : EHScope(Filter, EHScopeStack::stable_end()) {
402    FilterBits.NumFilters = numFilters;
403  }
404
405  static size_t getSizeForNumFilters(unsigned numFilters) {
406    return sizeof(EHFilterScope) + numFilters * sizeof(llvm::Value*);
407  }
408
409  unsigned getNumFilters() const { return FilterBits.NumFilters; }
410
411  void setFilter(unsigned i, llvm::Value *filterValue) {
412    assert(i < getNumFilters());
413    getFilters()[i] = filterValue;
414  }
415
416  llvm::Value *getFilter(unsigned i) const {
417    assert(i < getNumFilters());
418    return getFilters()[i];
419  }
420
421  static bool classof(const EHScope *scope) {
422    return scope->getKind() == Filter;
423  }
424};
425
426/// An exceptions scope which calls std::terminate if any exception
427/// reaches it.
428class EHTerminateScope : public EHScope {
429public:
430  EHTerminateScope(EHScopeStack::stable_iterator enclosingEHScope)
431    : EHScope(Terminate, enclosingEHScope) {}
432  static size_t getSize() { return sizeof(EHTerminateScope); }
433
434  static bool classof(const EHScope *scope) {
435    return scope->getKind() == Terminate;
436  }
437};
438
439/// A non-stable pointer into the scope stack.
440class EHScopeStack::iterator {
441  char *Ptr;
442
443  friend class EHScopeStack;
444  explicit iterator(char *Ptr) : Ptr(Ptr) {}
445
446public:
447  iterator() : Ptr(0) {}
448
449  EHScope *get() const {
450    return reinterpret_cast<EHScope*>(Ptr);
451  }
452
453  EHScope *operator->() const { return get(); }
454  EHScope &operator*() const { return *get(); }
455
456  iterator &operator++() {
457    switch (get()->getKind()) {
458    case EHScope::Catch:
459      Ptr += EHCatchScope::getSizeForNumHandlers(
460          static_cast<const EHCatchScope*>(get())->getNumHandlers());
461      break;
462
463    case EHScope::Filter:
464      Ptr += EHFilterScope::getSizeForNumFilters(
465          static_cast<const EHFilterScope*>(get())->getNumFilters());
466      break;
467
468    case EHScope::Cleanup:
469      Ptr += static_cast<const EHCleanupScope*>(get())
470        ->getAllocatedSize();
471      break;
472
473    case EHScope::Terminate:
474      Ptr += EHTerminateScope::getSize();
475      break;
476    }
477
478    return *this;
479  }
480
481  iterator next() {
482    iterator copy = *this;
483    ++copy;
484    return copy;
485  }
486
487  iterator operator++(int) {
488    iterator copy = *this;
489    operator++();
490    return copy;
491  }
492
493  bool encloses(iterator other) const { return Ptr >= other.Ptr; }
494  bool strictlyEncloses(iterator other) const { return Ptr > other.Ptr; }
495
496  bool operator==(iterator other) const { return Ptr == other.Ptr; }
497  bool operator!=(iterator other) const { return Ptr != other.Ptr; }
498};
499
500inline EHScopeStack::iterator EHScopeStack::begin() const {
501  return iterator(StartOfData);
502}
503
504inline EHScopeStack::iterator EHScopeStack::end() const {
505  return iterator(EndOfBuffer);
506}
507
508inline void EHScopeStack::popCatch() {
509  assert(!empty() && "popping exception stack when not empty");
510
511  EHCatchScope &scope = cast<EHCatchScope>(*begin());
512  InnermostEHScope = scope.getEnclosingEHScope();
513  StartOfData += EHCatchScope::getSizeForNumHandlers(scope.getNumHandlers());
514}
515
516inline void EHScopeStack::popTerminate() {
517  assert(!empty() && "popping exception stack when not empty");
518
519  EHTerminateScope &scope = cast<EHTerminateScope>(*begin());
520  InnermostEHScope = scope.getEnclosingEHScope();
521  StartOfData += EHTerminateScope::getSize();
522}
523
524inline EHScopeStack::iterator EHScopeStack::find(stable_iterator sp) const {
525  assert(sp.isValid() && "finding invalid savepoint");
526  assert(sp.Size <= stable_begin().Size && "finding savepoint after pop");
527  return iterator(EndOfBuffer - sp.Size);
528}
529
530inline EHScopeStack::stable_iterator
531EHScopeStack::stabilize(iterator ir) const {
532  assert(StartOfData <= ir.Ptr && ir.Ptr <= EndOfBuffer);
533  return stable_iterator(EndOfBuffer - ir.Ptr);
534}
535
536}
537}
538
539#endif
540