]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/clang/lib/CodeGen/CGException.h
Merge libpcap-1.1.1.
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / clang / lib / CodeGen / CGException.h
1 //===-- CGException.h - Classes for exceptions 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 exceptions in
11 // C++ and Objective C.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #ifndef CLANG_CODEGEN_CGEXCEPTION_H
16 #define CLANG_CODEGEN_CGEXCEPTION_H
17
18 /// EHScopeStack is defined in CodeGenFunction.h, but its
19 /// implementation is in this file and in CGException.cpp.
20 #include "CodeGenFunction.h"
21
22 namespace llvm {
23   class Value;
24   class BasicBlock;
25 }
26
27 namespace clang {
28 namespace CodeGen {
29
30 /// The exceptions personality for a function.  When 
31 class EHPersonality {
32   const char *PersonalityFn;
33
34   // If this is non-null, this personality requires a non-standard
35   // function for rethrowing an exception after a catchall cleanup.
36   // This function must have prototype void(void*).
37   const char *CatchallRethrowFn;
38
39   EHPersonality(const char *PersonalityFn,
40                 const char *CatchallRethrowFn = 0)
41     : PersonalityFn(PersonalityFn),
42       CatchallRethrowFn(CatchallRethrowFn) {}
43
44 public:
45   static const EHPersonality &get(const LangOptions &Lang);
46   static const EHPersonality GNU_C;
47   static const EHPersonality GNU_ObjC;
48   static const EHPersonality NeXT_ObjC;
49   static const EHPersonality GNU_CPlusPlus;
50   static const EHPersonality GNU_CPlusPlus_SJLJ;
51
52   const char *getPersonalityFnName() const { return PersonalityFn; }
53   const char *getCatchallRethrowFnName() const { return CatchallRethrowFn; }
54 };
55
56 /// A protected scope for zero-cost EH handling.
57 class EHScope {
58   llvm::BasicBlock *CachedLandingPad;
59
60   unsigned K : 2;
61
62 protected:
63   enum { BitsRemaining = 30 };
64
65 public:
66   enum Kind { Cleanup, Catch, Terminate, Filter };
67
68   EHScope(Kind K) : CachedLandingPad(0), K(K) {}
69
70   Kind getKind() const { return static_cast<Kind>(K); }
71
72   llvm::BasicBlock *getCachedLandingPad() const {
73     return CachedLandingPad;
74   }
75
76   void setCachedLandingPad(llvm::BasicBlock *Block) {
77     CachedLandingPad = Block;
78   }
79 };
80
81 /// A scope which attempts to handle some, possibly all, types of
82 /// exceptions.
83 ///
84 /// Objective C @finally blocks are represented using a cleanup scope
85 /// after the catch scope.
86 class EHCatchScope : public EHScope {
87   unsigned NumHandlers : BitsRemaining;
88
89   // In effect, we have a flexible array member
90   //   Handler Handlers[0];
91   // But that's only standard in C99, not C++, so we have to do
92   // annoying pointer arithmetic instead.
93
94 public:
95   struct Handler {
96     /// A type info value, or null (C++ null, not an LLVM null pointer)
97     /// for a catch-all.
98     llvm::Value *Type;
99
100     /// The catch handler for this type.
101     llvm::BasicBlock *Block;
102
103     /// The unwind destination index for this handler.
104     unsigned Index;
105   };
106
107 private:
108   friend class EHScopeStack;
109
110   Handler *getHandlers() {
111     return reinterpret_cast<Handler*>(this+1);
112   }
113
114   const Handler *getHandlers() const {
115     return reinterpret_cast<const Handler*>(this+1);
116   }
117
118 public:
119   static size_t getSizeForNumHandlers(unsigned N) {
120     return sizeof(EHCatchScope) + N * sizeof(Handler);
121   }
122
123   EHCatchScope(unsigned NumHandlers)
124     : EHScope(Catch), NumHandlers(NumHandlers) {
125   }
126
127   unsigned getNumHandlers() const {
128     return NumHandlers;
129   }
130
131   void setCatchAllHandler(unsigned I, llvm::BasicBlock *Block) {
132     setHandler(I, /*catchall*/ 0, Block);
133   }
134
135   void setHandler(unsigned I, llvm::Value *Type, llvm::BasicBlock *Block) {
136     assert(I < getNumHandlers());
137     getHandlers()[I].Type = Type;
138     getHandlers()[I].Block = Block;
139   }
140
141   const Handler &getHandler(unsigned I) const {
142     assert(I < getNumHandlers());
143     return getHandlers()[I];
144   }
145
146   typedef const Handler *iterator;
147   iterator begin() const { return getHandlers(); }
148   iterator end() const { return getHandlers() + getNumHandlers(); }
149
150   static bool classof(const EHScope *Scope) {
151     return Scope->getKind() == Catch;
152   }
153 };
154
155 /// A cleanup scope which generates the cleanup blocks lazily.
156 class EHCleanupScope : public EHScope {
157   /// Whether this cleanup needs to be run along normal edges.
158   bool IsNormalCleanup : 1;
159
160   /// Whether this cleanup needs to be run along exception edges.
161   bool IsEHCleanup : 1;
162
163   /// Whether this cleanup was activated before all normal uses.
164   bool ActivatedBeforeNormalUse : 1;
165
166   /// Whether this cleanup was activated before all EH uses.
167   bool ActivatedBeforeEHUse : 1;
168
169   /// The amount of extra storage needed by the Cleanup.
170   /// Always a multiple of the scope-stack alignment.
171   unsigned CleanupSize : 12;
172
173   /// The number of fixups required by enclosing scopes (not including
174   /// this one).  If this is the top cleanup scope, all the fixups
175   /// from this index onwards belong to this scope.
176   unsigned FixupDepth : BitsRemaining - 16;
177
178   /// The nearest normal cleanup scope enclosing this one.
179   EHScopeStack::stable_iterator EnclosingNormal;
180
181   /// The nearest EH cleanup scope enclosing this one.
182   EHScopeStack::stable_iterator EnclosingEH;
183
184   /// The dual entry/exit block along the normal edge.  This is lazily
185   /// created if needed before the cleanup is popped.
186   llvm::BasicBlock *NormalBlock;
187
188   /// The dual entry/exit block along the EH edge.  This is lazily
189   /// created if needed before the cleanup is popped.
190   llvm::BasicBlock *EHBlock;
191
192   /// An optional i1 variable indicating whether this cleanup has been
193   /// activated yet.  This has one of three states:
194   ///   - it is null if the cleanup is inactive
195   ///   - it is activeSentinel() if the cleanup is active and was not
196   ///     required before activation
197   ///   - it points to a valid variable
198   llvm::AllocaInst *ActiveVar;
199
200   /// Extra information required for cleanups that have resolved
201   /// branches through them.  This has to be allocated on the side
202   /// because everything on the cleanup stack has be trivially
203   /// movable.
204   struct ExtInfo {
205     /// The destinations of normal branch-afters and branch-throughs.
206     llvm::SmallPtrSet<llvm::BasicBlock*, 4> Branches;
207
208     /// Normal branch-afters.
209     llvm::SmallVector<std::pair<llvm::BasicBlock*,llvm::ConstantInt*>, 4>
210       BranchAfters;
211
212     /// The destinations of EH branch-afters and branch-throughs.
213     /// TODO: optimize for the extremely common case of a single
214     /// branch-through.
215     llvm::SmallPtrSet<llvm::BasicBlock*, 4> EHBranches;
216
217     /// EH branch-afters.
218     llvm::SmallVector<std::pair<llvm::BasicBlock*,llvm::ConstantInt*>, 4>
219     EHBranchAfters;
220   };
221   mutable struct ExtInfo *ExtInfo;
222
223   struct ExtInfo &getExtInfo() {
224     if (!ExtInfo) ExtInfo = new struct ExtInfo();
225     return *ExtInfo;
226   }
227
228   const struct ExtInfo &getExtInfo() const {
229     if (!ExtInfo) ExtInfo = new struct ExtInfo();
230     return *ExtInfo;
231   }
232
233 public:
234   /// Gets the size required for a lazy cleanup scope with the given
235   /// cleanup-data requirements.
236   static size_t getSizeForCleanupSize(size_t Size) {
237     return sizeof(EHCleanupScope) + Size;
238   }
239
240   size_t getAllocatedSize() const {
241     return sizeof(EHCleanupScope) + CleanupSize;
242   }
243
244   EHCleanupScope(bool IsNormal, bool IsEH, bool IsActive,
245                  unsigned CleanupSize, unsigned FixupDepth,
246                  EHScopeStack::stable_iterator EnclosingNormal,
247                  EHScopeStack::stable_iterator EnclosingEH)
248     : EHScope(EHScope::Cleanup),
249       IsNormalCleanup(IsNormal), IsEHCleanup(IsEH),
250       ActivatedBeforeNormalUse(IsActive),
251       ActivatedBeforeEHUse(IsActive),
252       CleanupSize(CleanupSize), FixupDepth(FixupDepth),
253       EnclosingNormal(EnclosingNormal), EnclosingEH(EnclosingEH),
254       NormalBlock(0), EHBlock(0),
255       ActiveVar(IsActive ? activeSentinel() : 0),
256       ExtInfo(0)
257   {
258     assert(this->CleanupSize == CleanupSize && "cleanup size overflow");
259   }
260
261   ~EHCleanupScope() {
262     delete ExtInfo;
263   }
264
265   bool isNormalCleanup() const { return IsNormalCleanup; }
266   llvm::BasicBlock *getNormalBlock() const { return NormalBlock; }
267   void setNormalBlock(llvm::BasicBlock *BB) { NormalBlock = BB; }
268
269   bool isEHCleanup() const { return IsEHCleanup; }
270   llvm::BasicBlock *getEHBlock() const { return EHBlock; }
271   void setEHBlock(llvm::BasicBlock *BB) { EHBlock = BB; }
272
273   static llvm::AllocaInst *activeSentinel() {
274     return reinterpret_cast<llvm::AllocaInst*>(1);
275   }
276
277   bool isActive() const { return ActiveVar != 0; }
278   llvm::AllocaInst *getActiveVar() const { return ActiveVar; }
279   void setActiveVar(llvm::AllocaInst *Var) { ActiveVar = Var; }
280
281   bool wasActivatedBeforeNormalUse() const { return ActivatedBeforeNormalUse; }
282   void setActivatedBeforeNormalUse(bool B) { ActivatedBeforeNormalUse = B; }
283
284   bool wasActivatedBeforeEHUse() const { return ActivatedBeforeEHUse; }
285   void setActivatedBeforeEHUse(bool B) { ActivatedBeforeEHUse = B; }
286
287   unsigned getFixupDepth() const { return FixupDepth; }
288   EHScopeStack::stable_iterator getEnclosingNormalCleanup() const {
289     return EnclosingNormal;
290   }
291   EHScopeStack::stable_iterator getEnclosingEHCleanup() const {
292     return EnclosingEH;
293   }
294
295   size_t getCleanupSize() const { return CleanupSize; }
296   void *getCleanupBuffer() { return this + 1; }
297
298   EHScopeStack::Cleanup *getCleanup() {
299     return reinterpret_cast<EHScopeStack::Cleanup*>(getCleanupBuffer());
300   }
301
302   /// True if this cleanup scope has any branch-afters or branch-throughs.
303   bool hasBranches() const { return ExtInfo && !ExtInfo->Branches.empty(); }
304
305   /// Add a branch-after to this cleanup scope.  A branch-after is a
306   /// branch from a point protected by this (normal) cleanup to a
307   /// point in the normal cleanup scope immediately containing it.
308   /// For example,
309   ///   for (;;) { A a; break; }
310   /// contains a branch-after.
311   ///
312   /// Branch-afters each have their own destination out of the
313   /// cleanup, guaranteed distinct from anything else threaded through
314   /// it.  Therefore branch-afters usually force a switch after the
315   /// cleanup.
316   void addBranchAfter(llvm::ConstantInt *Index,
317                       llvm::BasicBlock *Block) {
318     struct ExtInfo &ExtInfo = getExtInfo();
319     if (ExtInfo.Branches.insert(Block))
320       ExtInfo.BranchAfters.push_back(std::make_pair(Block, Index));
321   }
322
323   /// Return the number of unique branch-afters on this scope.
324   unsigned getNumBranchAfters() const {
325     return ExtInfo ? ExtInfo->BranchAfters.size() : 0;
326   }
327
328   llvm::BasicBlock *getBranchAfterBlock(unsigned I) const {
329     assert(I < getNumBranchAfters());
330     return ExtInfo->BranchAfters[I].first;
331   }
332
333   llvm::ConstantInt *getBranchAfterIndex(unsigned I) const {
334     assert(I < getNumBranchAfters());
335     return ExtInfo->BranchAfters[I].second;
336   }
337
338   /// Add a branch-through to this cleanup scope.  A branch-through is
339   /// a branch from a scope protected by this (normal) cleanup to an
340   /// enclosing scope other than the immediately-enclosing normal
341   /// cleanup scope.
342   ///
343   /// In the following example, the branch through B's scope is a
344   /// branch-through, while the branch through A's scope is a
345   /// branch-after:
346   ///   for (;;) { A a; B b; break; }
347   ///
348   /// All branch-throughs have a common destination out of the
349   /// cleanup, one possibly shared with the fall-through.  Therefore
350   /// branch-throughs usually don't force a switch after the cleanup.
351   ///
352   /// \return true if the branch-through was new to this scope
353   bool addBranchThrough(llvm::BasicBlock *Block) {
354     return getExtInfo().Branches.insert(Block);
355   }
356
357   /// Determines if this cleanup scope has any branch throughs.
358   bool hasBranchThroughs() const {
359     if (!ExtInfo) return false;
360     return (ExtInfo->BranchAfters.size() != ExtInfo->Branches.size());
361   }
362
363   // Same stuff, only for EH branches instead of normal branches.
364   // It's quite possible that we could find a better representation
365   // for this.
366
367   bool hasEHBranches() const { return ExtInfo && !ExtInfo->EHBranches.empty(); }
368   void addEHBranchAfter(llvm::ConstantInt *Index,
369                         llvm::BasicBlock *Block) {
370     struct ExtInfo &ExtInfo = getExtInfo();
371     if (ExtInfo.EHBranches.insert(Block))
372       ExtInfo.EHBranchAfters.push_back(std::make_pair(Block, Index));
373   }
374
375   unsigned getNumEHBranchAfters() const {
376     return ExtInfo ? ExtInfo->EHBranchAfters.size() : 0;
377   }
378
379   llvm::BasicBlock *getEHBranchAfterBlock(unsigned I) const {
380     assert(I < getNumEHBranchAfters());
381     return ExtInfo->EHBranchAfters[I].first;
382   }
383
384   llvm::ConstantInt *getEHBranchAfterIndex(unsigned I) const {
385     assert(I < getNumEHBranchAfters());
386     return ExtInfo->EHBranchAfters[I].second;
387   }
388
389   bool addEHBranchThrough(llvm::BasicBlock *Block) {
390     return getExtInfo().EHBranches.insert(Block);
391   }
392
393   bool hasEHBranchThroughs() const {
394     if (!ExtInfo) return false;
395     return (ExtInfo->EHBranchAfters.size() != ExtInfo->EHBranches.size());
396   }
397
398   static bool classof(const EHScope *Scope) {
399     return (Scope->getKind() == Cleanup);
400   }
401 };
402
403 /// An exceptions scope which filters exceptions thrown through it.
404 /// Only exceptions matching the filter types will be permitted to be
405 /// thrown.
406 ///
407 /// This is used to implement C++ exception specifications.
408 class EHFilterScope : public EHScope {
409   unsigned NumFilters : BitsRemaining;
410
411   // Essentially ends in a flexible array member:
412   // llvm::Value *FilterTypes[0];
413
414   llvm::Value **getFilters() {
415     return reinterpret_cast<llvm::Value**>(this+1);
416   }
417
418   llvm::Value * const *getFilters() const {
419     return reinterpret_cast<llvm::Value* const *>(this+1);
420   }
421
422 public:
423   EHFilterScope(unsigned NumFilters) :
424     EHScope(Filter), NumFilters(NumFilters) {}
425
426   static size_t getSizeForNumFilters(unsigned NumFilters) {
427     return sizeof(EHFilterScope) + NumFilters * sizeof(llvm::Value*);
428   }
429
430   unsigned getNumFilters() const { return NumFilters; }
431
432   void setFilter(unsigned I, llvm::Value *FilterValue) {
433     assert(I < getNumFilters());
434     getFilters()[I] = FilterValue;
435   }
436
437   llvm::Value *getFilter(unsigned I) const {
438     assert(I < getNumFilters());
439     return getFilters()[I];
440   }
441
442   static bool classof(const EHScope *Scope) {
443     return Scope->getKind() == Filter;
444   }
445 };
446
447 /// An exceptions scope which calls std::terminate if any exception
448 /// reaches it.
449 class EHTerminateScope : public EHScope {
450   unsigned DestIndex : BitsRemaining;
451 public:
452   EHTerminateScope(unsigned Index) : EHScope(Terminate), DestIndex(Index) {}
453   static size_t getSize() { return sizeof(EHTerminateScope); }
454
455   unsigned getDestIndex() const { return DestIndex; }
456
457   static bool classof(const EHScope *Scope) {
458     return Scope->getKind() == Terminate;
459   }
460 };
461
462 /// A non-stable pointer into the scope stack.
463 class EHScopeStack::iterator {
464   char *Ptr;
465
466   friend class EHScopeStack;
467   explicit iterator(char *Ptr) : Ptr(Ptr) {}
468
469 public:
470   iterator() : Ptr(0) {}
471
472   EHScope *get() const { 
473     return reinterpret_cast<EHScope*>(Ptr);
474   }
475
476   EHScope *operator->() const { return get(); }
477   EHScope &operator*() const { return *get(); }
478
479   iterator &operator++() {
480     switch (get()->getKind()) {
481     case EHScope::Catch:
482       Ptr += EHCatchScope::getSizeForNumHandlers(
483           static_cast<const EHCatchScope*>(get())->getNumHandlers());
484       break;
485
486     case EHScope::Filter:
487       Ptr += EHFilterScope::getSizeForNumFilters(
488           static_cast<const EHFilterScope*>(get())->getNumFilters());
489       break;
490
491     case EHScope::Cleanup:
492       Ptr += static_cast<const EHCleanupScope*>(get())
493         ->getAllocatedSize();
494       break;
495
496     case EHScope::Terminate:
497       Ptr += EHTerminateScope::getSize();
498       break;
499     }
500
501     return *this;
502   }
503
504   iterator next() {
505     iterator copy = *this;
506     ++copy;
507     return copy;
508   }
509
510   iterator operator++(int) {
511     iterator copy = *this;
512     operator++();
513     return copy;
514   }
515
516   bool encloses(iterator other) const { return Ptr >= other.Ptr; }
517   bool strictlyEncloses(iterator other) const { return Ptr > other.Ptr; }
518
519   bool operator==(iterator other) const { return Ptr == other.Ptr; }
520   bool operator!=(iterator other) const { return Ptr != other.Ptr; }
521 };
522
523 inline EHScopeStack::iterator EHScopeStack::begin() const {
524   return iterator(StartOfData);
525 }
526
527 inline EHScopeStack::iterator EHScopeStack::end() const {
528   return iterator(EndOfBuffer);
529 }
530
531 inline void EHScopeStack::popCatch() {
532   assert(!empty() && "popping exception stack when not empty");
533
534   assert(isa<EHCatchScope>(*begin()));
535   StartOfData += EHCatchScope::getSizeForNumHandlers(
536                           cast<EHCatchScope>(*begin()).getNumHandlers());
537
538   if (empty()) NextEHDestIndex = FirstEHDestIndex;
539
540   assert(CatchDepth > 0 && "mismatched catch/terminate push/pop");
541   CatchDepth--;
542 }
543
544 inline void EHScopeStack::popTerminate() {
545   assert(!empty() && "popping exception stack when not empty");
546
547   assert(isa<EHTerminateScope>(*begin()));
548   StartOfData += EHTerminateScope::getSize();
549
550   if (empty()) NextEHDestIndex = FirstEHDestIndex;
551
552   assert(CatchDepth > 0 && "mismatched catch/terminate push/pop");
553   CatchDepth--;
554 }
555
556 inline EHScopeStack::iterator EHScopeStack::find(stable_iterator sp) const {
557   assert(sp.isValid() && "finding invalid savepoint");
558   assert(sp.Size <= stable_begin().Size && "finding savepoint after pop");
559   return iterator(EndOfBuffer - sp.Size);
560 }
561
562 inline EHScopeStack::stable_iterator
563 EHScopeStack::stabilize(iterator ir) const {
564   assert(StartOfData <= ir.Ptr && ir.Ptr <= EndOfBuffer);
565   return stable_iterator(EndOfBuffer - ir.Ptr);
566 }
567
568 inline EHScopeStack::stable_iterator
569 EHScopeStack::getInnermostActiveNormalCleanup() const {
570   for (EHScopeStack::stable_iterator
571          I = getInnermostNormalCleanup(), E = stable_end(); I != E; ) {
572     EHCleanupScope &S = cast<EHCleanupScope>(*find(I));
573     if (S.isActive()) return I;
574     I = S.getEnclosingNormalCleanup();
575   }
576   return stable_end();
577 }
578
579 inline EHScopeStack::stable_iterator
580 EHScopeStack::getInnermostActiveEHCleanup() const {
581   for (EHScopeStack::stable_iterator
582          I = getInnermostEHCleanup(), E = stable_end(); I != E; ) {
583     EHCleanupScope &S = cast<EHCleanupScope>(*find(I));
584     if (S.isActive()) return I;
585     I = S.getEnclosingEHCleanup();
586   }
587   return stable_end();
588 }
589
590 }
591 }
592
593 #endif