Home | History | Annotate | Download | only in CodeGen
      1 //===-- CGCleanup.h - Classes for cleanups IR generation --------*- C++ -*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // These classes support the generation of LLVM IR for cleanups.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #ifndef CLANG_CODEGEN_CGCLEANUP_H
     15 #define CLANG_CODEGEN_CGCLEANUP_H
     16 
     17 /// EHScopeStack is defined in CodeGenFunction.h, but its
     18 /// implementation is in this file and in CGCleanup.cpp.
     19 #include "CodeGenFunction.h"
     20 
     21 namespace llvm {
     22   class Value;
     23   class BasicBlock;
     24 }
     25 
     26 namespace clang {
     27 namespace CodeGen {
     28 
     29 /// A protected scope for zero-cost EH handling.
     30 class EHScope {
     31   llvm::BasicBlock *CachedLandingPad;
     32   llvm::BasicBlock *CachedEHDispatchBlock;
     33 
     34   EHScopeStack::stable_iterator EnclosingEHScope;
     35 
     36   class CommonBitFields {
     37     friend class EHScope;
     38     unsigned Kind : 2;
     39   };
     40   enum { NumCommonBits = 2 };
     41 
     42 protected:
     43   class CatchBitFields {
     44     friend class EHCatchScope;
     45     unsigned : NumCommonBits;
     46 
     47     unsigned NumHandlers : 32 - NumCommonBits;
     48   };
     49 
     50   class CleanupBitFields {
     51     friend class EHCleanupScope;
     52     unsigned : NumCommonBits;
     53 
     54     /// Whether this cleanup needs to be run along normal edges.
     55     unsigned IsNormalCleanup : 1;
     56 
     57     /// 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 
     93 public:
     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.
    136 class 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 
    142 public:
    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 
    154 private:
    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 
    165 public:
    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.
    205 class 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 
    244 public:
    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.
    387 class 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 
    399 public:
    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.
    428 class EHTerminateScope : public EHScope {
    429 public:
    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.
    440 class EHScopeStack::iterator {
    441   char *Ptr;
    442 
    443   friend class EHScopeStack;
    444   explicit iterator(char *Ptr) : Ptr(Ptr) {}
    445 
    446 public:
    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 
    500 inline EHScopeStack::iterator EHScopeStack::begin() const {
    501   return iterator(StartOfData);
    502 }
    503 
    504 inline EHScopeStack::iterator EHScopeStack::end() const {
    505   return iterator(EndOfBuffer);
    506 }
    507 
    508 inline 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 
    516 inline 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 
    524 inline 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 
    530 inline EHScopeStack::stable_iterator
    531 EHScopeStack::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