xref: /llvm-project/clang/lib/CodeGen/CGCleanup.h (revision 4424c44c8c4ec8e071f5c5999fba216d36fb92c9)
1 //===-- CGCleanup.h - Classes for cleanups IR generation --------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // These classes support the generation of LLVM IR for cleanups.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef LLVM_CLANG_LIB_CODEGEN_CGCLEANUP_H
14 #define LLVM_CLANG_LIB_CODEGEN_CGCLEANUP_H
15 
16 #include "EHScopeStack.h"
17 
18 #include "Address.h"
19 #include "llvm/ADT/STLExtras.h"
20 #include "llvm/ADT/SetVector.h"
21 #include "llvm/ADT/SmallPtrSet.h"
22 #include "llvm/ADT/SmallVector.h"
23 #include "llvm/IR/Instruction.h"
24 
25 namespace llvm {
26 class BasicBlock;
27 class Value;
28 class ConstantInt;
29 }
30 
31 namespace clang {
32 class FunctionDecl;
33 namespace CodeGen {
34 class CodeGenModule;
35 class CodeGenFunction;
36 
37 /// The MS C++ ABI needs a pointer to RTTI data plus some flags to describe the
38 /// type of a catch handler, so we use this wrapper.
39 struct CatchTypeInfo {
40   llvm::Constant *RTTI;
41   unsigned Flags;
42 };
43 
44 /// A protected scope for zero-cost EH handling.
45 class EHScope {
46 public:
47   enum Kind { Cleanup, Catch, Terminate, Filter };
48 
49 private:
50   llvm::BasicBlock *CachedLandingPad;
51   llvm::BasicBlock *CachedEHDispatchBlock;
52 
53   EHScopeStack::stable_iterator EnclosingEHScope;
54 
55   class CommonBitFields {
56     friend class EHScope;
57     LLVM_PREFERRED_TYPE(Kind)
58     unsigned Kind : 3;
59   };
60   enum { NumCommonBits = 3 };
61 
62 protected:
63   class CatchBitFields {
64     friend class EHCatchScope;
65     unsigned : NumCommonBits;
66 
67     unsigned NumHandlers : 32 - NumCommonBits;
68   };
69 
70   class CleanupBitFields {
71     friend class EHCleanupScope;
72     unsigned : NumCommonBits;
73 
74     /// Whether this cleanup needs to be run along normal edges.
75     LLVM_PREFERRED_TYPE(bool)
76     unsigned IsNormalCleanup : 1;
77 
78     /// Whether this cleanup needs to be run along exception edges.
79     LLVM_PREFERRED_TYPE(bool)
80     unsigned IsEHCleanup : 1;
81 
82     /// Whether this cleanup is currently active.
83     LLVM_PREFERRED_TYPE(bool)
84     unsigned IsActive : 1;
85 
86     /// Whether this cleanup is a lifetime marker
87     LLVM_PREFERRED_TYPE(bool)
88     unsigned IsLifetimeMarker : 1;
89 
90     /// Whether this cleanup is a fake use
91     LLVM_PREFERRED_TYPE(bool)
92     unsigned IsFakeUse : 1;
93 
94     /// Whether the normal cleanup should test the activation flag.
95     LLVM_PREFERRED_TYPE(bool)
96     unsigned TestFlagInNormalCleanup : 1;
97 
98     /// Whether the EH cleanup should test the activation flag.
99     LLVM_PREFERRED_TYPE(bool)
100     unsigned TestFlagInEHCleanup : 1;
101 
102     /// The amount of extra storage needed by the Cleanup.
103     /// Always a multiple of the scope-stack alignment.
104     unsigned CleanupSize : 12;
105   };
106 
107   class FilterBitFields {
108     friend class EHFilterScope;
109     unsigned : NumCommonBits;
110 
111     unsigned NumFilters : 32 - NumCommonBits;
112   };
113 
114   union {
115     CommonBitFields CommonBits;
116     CatchBitFields CatchBits;
117     CleanupBitFields CleanupBits;
118     FilterBitFields FilterBits;
119   };
120 
121 public:
122   EHScope(Kind kind, EHScopeStack::stable_iterator enclosingEHScope)
123     : CachedLandingPad(nullptr), CachedEHDispatchBlock(nullptr),
124       EnclosingEHScope(enclosingEHScope) {
125     CommonBits.Kind = kind;
126   }
127 
128   Kind getKind() const { return static_cast<Kind>(CommonBits.Kind); }
129 
130   llvm::BasicBlock *getCachedLandingPad() const {
131     return CachedLandingPad;
132   }
133 
134   void setCachedLandingPad(llvm::BasicBlock *block) {
135     CachedLandingPad = block;
136   }
137 
138   llvm::BasicBlock *getCachedEHDispatchBlock() const {
139     return CachedEHDispatchBlock;
140   }
141 
142   void setCachedEHDispatchBlock(llvm::BasicBlock *block) {
143     CachedEHDispatchBlock = block;
144   }
145 
146   bool hasEHBranches() const {
147     if (llvm::BasicBlock *block = getCachedEHDispatchBlock())
148       return !block->use_empty();
149     return false;
150   }
151 
152   EHScopeStack::stable_iterator getEnclosingEHScope() const {
153     return EnclosingEHScope;
154   }
155 };
156 
157 /// A scope which attempts to handle some, possibly all, types of
158 /// exceptions.
159 ///
160 /// Objective C \@finally blocks are represented using a cleanup scope
161 /// after the catch scope.
162 class EHCatchScope : public EHScope {
163   // In effect, we have a flexible array member
164   //   Handler Handlers[0];
165   // But that's only standard in C99, not C++, so we have to do
166   // annoying pointer arithmetic instead.
167 
168 public:
169   struct Handler {
170     /// A type info value, or null (C++ null, not an LLVM null pointer)
171     /// for a catch-all.
172     CatchTypeInfo Type;
173 
174     /// The catch handler for this type.
175     llvm::BasicBlock *Block;
176 
177     bool isCatchAll() const { return Type.RTTI == nullptr; }
178   };
179 
180 private:
181   friend class EHScopeStack;
182 
183   Handler *getHandlers() {
184     return reinterpret_cast<Handler*>(this+1);
185   }
186 
187   const Handler *getHandlers() const {
188     return reinterpret_cast<const Handler*>(this+1);
189   }
190 
191 public:
192   static size_t getSizeForNumHandlers(unsigned N) {
193     return sizeof(EHCatchScope) + N * sizeof(Handler);
194   }
195 
196   EHCatchScope(unsigned numHandlers,
197                EHScopeStack::stable_iterator enclosingEHScope)
198     : EHScope(Catch, enclosingEHScope) {
199     CatchBits.NumHandlers = numHandlers;
200     assert(CatchBits.NumHandlers == numHandlers && "NumHandlers overflow?");
201   }
202 
203   unsigned getNumHandlers() const {
204     return CatchBits.NumHandlers;
205   }
206 
207   void setCatchAllHandler(unsigned I, llvm::BasicBlock *Block) {
208     setHandler(I, CatchTypeInfo{nullptr, 0}, Block);
209   }
210 
211   void setHandler(unsigned I, llvm::Constant *Type, llvm::BasicBlock *Block) {
212     assert(I < getNumHandlers());
213     getHandlers()[I].Type = CatchTypeInfo{Type, 0};
214     getHandlers()[I].Block = Block;
215   }
216 
217   void setHandler(unsigned I, CatchTypeInfo Type, llvm::BasicBlock *Block) {
218     assert(I < getNumHandlers());
219     getHandlers()[I].Type = Type;
220     getHandlers()[I].Block = Block;
221   }
222 
223   const Handler &getHandler(unsigned I) const {
224     assert(I < getNumHandlers());
225     return getHandlers()[I];
226   }
227 
228   // Clear all handler blocks.
229   // FIXME: it's better to always call clearHandlerBlocks in DTOR and have a
230   // 'takeHandler' or some such function which removes ownership from the
231   // EHCatchScope object if the handlers should live longer than EHCatchScope.
232   void clearHandlerBlocks() {
233     for (unsigned I = 0, N = getNumHandlers(); I != N; ++I)
234       delete getHandler(I).Block;
235   }
236 
237   typedef const Handler *iterator;
238   iterator begin() const { return getHandlers(); }
239   iterator end() const { return getHandlers() + getNumHandlers(); }
240 
241   static bool classof(const EHScope *Scope) {
242     return Scope->getKind() == Catch;
243   }
244 };
245 
246 /// A cleanup scope which generates the cleanup blocks lazily.
247 class alignas(8) EHCleanupScope : public EHScope {
248   /// The nearest normal cleanup scope enclosing this one.
249   EHScopeStack::stable_iterator EnclosingNormal;
250 
251   /// The nearest EH scope enclosing this one.
252   EHScopeStack::stable_iterator EnclosingEH;
253 
254   /// The dual entry/exit block along the normal edge.  This is lazily
255   /// created if needed before the cleanup is popped.
256   llvm::BasicBlock *NormalBlock;
257 
258   /// An optional i1 variable indicating whether this cleanup has been
259   /// activated yet.
260   Address ActiveFlag;
261 
262   /// Extra information required for cleanups that have resolved
263   /// branches through them.  This has to be allocated on the side
264   /// because everything on the cleanup stack has be trivially
265   /// movable.
266   struct ExtInfo {
267     /// The destinations of normal branch-afters and branch-throughs.
268     llvm::SmallPtrSet<llvm::BasicBlock*, 4> Branches;
269 
270     /// Normal branch-afters.
271     SmallVector<std::pair<llvm::BasicBlock*,llvm::ConstantInt*>, 4>
272       BranchAfters;
273   };
274   mutable struct ExtInfo *ExtInfo;
275 
276   /// Erases auxillary allocas and their usages for an unused cleanup.
277   /// Cleanups should mark these allocas as 'used' if the cleanup is
278   /// emitted, otherwise these instructions would be erased.
279   struct AuxillaryAllocas {
280     SmallVector<llvm::Instruction *, 1> AuxAllocas;
281     bool used = false;
282 
283     // Records a potentially unused instruction to be erased later.
284     void Add(llvm::AllocaInst *Alloca) { AuxAllocas.push_back(Alloca); }
285 
286     // Mark all recorded instructions as used. These will not be erased later.
287     void MarkUsed() {
288       used = true;
289       AuxAllocas.clear();
290     }
291 
292     ~AuxillaryAllocas() {
293       if (used)
294         return;
295       llvm::SetVector<llvm::Instruction *> Uses;
296       for (auto *Inst : llvm::reverse(AuxAllocas))
297         CollectUses(Inst, Uses);
298       // Delete uses in the reverse order of insertion.
299       for (auto *I : llvm::reverse(Uses))
300         I->eraseFromParent();
301     }
302 
303   private:
304     void CollectUses(llvm::Instruction *I,
305                      llvm::SetVector<llvm::Instruction *> &Uses) {
306       if (!I || !Uses.insert(I))
307         return;
308       for (auto *User : I->users())
309         CollectUses(cast<llvm::Instruction>(User), Uses);
310     }
311   };
312   mutable struct AuxillaryAllocas *AuxAllocas;
313 
314   AuxillaryAllocas &getAuxillaryAllocas() {
315     if (!AuxAllocas) {
316       AuxAllocas = new struct AuxillaryAllocas();
317     }
318     return *AuxAllocas;
319   }
320 
321   /// The number of fixups required by enclosing scopes (not including
322   /// this one).  If this is the top cleanup scope, all the fixups
323   /// from this index onwards belong to this scope.
324   unsigned FixupDepth;
325 
326   struct ExtInfo &getExtInfo() {
327     if (!ExtInfo) ExtInfo = new struct ExtInfo();
328     return *ExtInfo;
329   }
330 
331   const struct ExtInfo &getExtInfo() const {
332     if (!ExtInfo) ExtInfo = new struct ExtInfo();
333     return *ExtInfo;
334   }
335 
336 public:
337   /// Gets the size required for a lazy cleanup scope with the given
338   /// cleanup-data requirements.
339   static size_t getSizeForCleanupSize(size_t Size) {
340     return sizeof(EHCleanupScope) + Size;
341   }
342 
343   size_t getAllocatedSize() const {
344     return sizeof(EHCleanupScope) + CleanupBits.CleanupSize;
345   }
346 
347   EHCleanupScope(bool isNormal, bool isEH, unsigned cleanupSize,
348                  unsigned fixupDepth,
349                  EHScopeStack::stable_iterator enclosingNormal,
350                  EHScopeStack::stable_iterator enclosingEH)
351       : EHScope(EHScope::Cleanup, enclosingEH),
352         EnclosingNormal(enclosingNormal), NormalBlock(nullptr),
353         ActiveFlag(Address::invalid()), ExtInfo(nullptr), AuxAllocas(nullptr),
354         FixupDepth(fixupDepth) {
355     CleanupBits.IsNormalCleanup = isNormal;
356     CleanupBits.IsEHCleanup = isEH;
357     CleanupBits.IsActive = true;
358     CleanupBits.IsLifetimeMarker = false;
359     CleanupBits.IsFakeUse = false;
360     CleanupBits.TestFlagInNormalCleanup = false;
361     CleanupBits.TestFlagInEHCleanup = false;
362     CleanupBits.CleanupSize = cleanupSize;
363 
364     assert(CleanupBits.CleanupSize == cleanupSize && "cleanup size overflow");
365   }
366 
367   void Destroy() {
368     if (AuxAllocas)
369       delete AuxAllocas;
370     delete ExtInfo;
371   }
372   void AddAuxAllocas(llvm::SmallVector<llvm::AllocaInst *> Allocas) {
373     for (auto *Alloca : Allocas)
374       getAuxillaryAllocas().Add(Alloca);
375   }
376   void MarkEmitted() { getAuxillaryAllocas().MarkUsed(); }
377   // Objects of EHCleanupScope are not destructed. Use Destroy().
378   ~EHCleanupScope() = delete;
379 
380   bool isNormalCleanup() const { return CleanupBits.IsNormalCleanup; }
381   llvm::BasicBlock *getNormalBlock() const { return NormalBlock; }
382   void setNormalBlock(llvm::BasicBlock *BB) { NormalBlock = BB; }
383 
384   bool isEHCleanup() const { return CleanupBits.IsEHCleanup; }
385 
386   bool isActive() const { return CleanupBits.IsActive; }
387   void setActive(bool A) { CleanupBits.IsActive = A; }
388 
389   bool isLifetimeMarker() const { return CleanupBits.IsLifetimeMarker; }
390   void setLifetimeMarker() { CleanupBits.IsLifetimeMarker = true; }
391 
392   bool isFakeUse() const { return CleanupBits.IsFakeUse; }
393   void setFakeUse() { CleanupBits.IsFakeUse = true; }
394 
395   bool hasActiveFlag() const { return ActiveFlag.isValid(); }
396   Address getActiveFlag() const {
397     return ActiveFlag;
398   }
399   void setActiveFlag(RawAddress Var) {
400     assert(Var.getAlignment().isOne());
401     ActiveFlag = Var;
402   }
403 
404   void setTestFlagInNormalCleanup() {
405     CleanupBits.TestFlagInNormalCleanup = true;
406   }
407   bool shouldTestFlagInNormalCleanup() const {
408     return CleanupBits.TestFlagInNormalCleanup;
409   }
410 
411   void setTestFlagInEHCleanup() {
412     CleanupBits.TestFlagInEHCleanup = true;
413   }
414   bool shouldTestFlagInEHCleanup() const {
415     return CleanupBits.TestFlagInEHCleanup;
416   }
417 
418   unsigned getFixupDepth() const { return FixupDepth; }
419   EHScopeStack::stable_iterator getEnclosingNormalCleanup() const {
420     return EnclosingNormal;
421   }
422 
423   size_t getCleanupSize() const { return CleanupBits.CleanupSize; }
424   void *getCleanupBuffer() { return this + 1; }
425 
426   EHScopeStack::Cleanup *getCleanup() {
427     return reinterpret_cast<EHScopeStack::Cleanup*>(getCleanupBuffer());
428   }
429 
430   /// True if this cleanup scope has any branch-afters or branch-throughs.
431   bool hasBranches() const { return ExtInfo && !ExtInfo->Branches.empty(); }
432 
433   /// Add a branch-after to this cleanup scope.  A branch-after is a
434   /// branch from a point protected by this (normal) cleanup to a
435   /// point in the normal cleanup scope immediately containing it.
436   /// For example,
437   ///   for (;;) { A a; break; }
438   /// contains a branch-after.
439   ///
440   /// Branch-afters each have their own destination out of the
441   /// cleanup, guaranteed distinct from anything else threaded through
442   /// it.  Therefore branch-afters usually force a switch after the
443   /// cleanup.
444   void addBranchAfter(llvm::ConstantInt *Index,
445                       llvm::BasicBlock *Block) {
446     struct ExtInfo &ExtInfo = getExtInfo();
447     if (ExtInfo.Branches.insert(Block).second)
448       ExtInfo.BranchAfters.push_back(std::make_pair(Block, Index));
449   }
450 
451   /// Return the number of unique branch-afters on this scope.
452   unsigned getNumBranchAfters() const {
453     return ExtInfo ? ExtInfo->BranchAfters.size() : 0;
454   }
455 
456   llvm::BasicBlock *getBranchAfterBlock(unsigned I) const {
457     assert(I < getNumBranchAfters());
458     return ExtInfo->BranchAfters[I].first;
459   }
460 
461   llvm::ConstantInt *getBranchAfterIndex(unsigned I) const {
462     assert(I < getNumBranchAfters());
463     return ExtInfo->BranchAfters[I].second;
464   }
465 
466   /// Add a branch-through to this cleanup scope.  A branch-through is
467   /// a branch from a scope protected by this (normal) cleanup to an
468   /// enclosing scope other than the immediately-enclosing normal
469   /// cleanup scope.
470   ///
471   /// In the following example, the branch through B's scope is a
472   /// branch-through, while the branch through A's scope is a
473   /// branch-after:
474   ///   for (;;) { A a; B b; break; }
475   ///
476   /// All branch-throughs have a common destination out of the
477   /// cleanup, one possibly shared with the fall-through.  Therefore
478   /// branch-throughs usually don't force a switch after the cleanup.
479   ///
480   /// \return true if the branch-through was new to this scope
481   bool addBranchThrough(llvm::BasicBlock *Block) {
482     return getExtInfo().Branches.insert(Block).second;
483   }
484 
485   /// Determines if this cleanup scope has any branch throughs.
486   bool hasBranchThroughs() const {
487     if (!ExtInfo) return false;
488     return (ExtInfo->BranchAfters.size() != ExtInfo->Branches.size());
489   }
490 
491   static bool classof(const EHScope *Scope) {
492     return (Scope->getKind() == Cleanup);
493   }
494 };
495 // NOTE: there's a bunch of different data classes tacked on after an
496 // EHCleanupScope. It is asserted (in EHScopeStack::pushCleanup*) that
497 // they don't require greater alignment than ScopeStackAlignment. So,
498 // EHCleanupScope ought to have alignment equal to that -- not more
499 // (would be misaligned by the stack allocator), and not less (would
500 // break the appended classes).
501 static_assert(alignof(EHCleanupScope) == EHScopeStack::ScopeStackAlignment,
502               "EHCleanupScope expected alignment");
503 
504 /// An exceptions scope which filters exceptions thrown through it.
505 /// Only exceptions matching the filter types will be permitted to be
506 /// thrown.
507 ///
508 /// This is used to implement C++ exception specifications.
509 class EHFilterScope : public EHScope {
510   // Essentially ends in a flexible array member:
511   // llvm::Value *FilterTypes[0];
512 
513   llvm::Value **getFilters() {
514     return reinterpret_cast<llvm::Value**>(this+1);
515   }
516 
517   llvm::Value * const *getFilters() const {
518     return reinterpret_cast<llvm::Value* const *>(this+1);
519   }
520 
521 public:
522   EHFilterScope(unsigned numFilters)
523     : EHScope(Filter, EHScopeStack::stable_end()) {
524     FilterBits.NumFilters = numFilters;
525     assert(FilterBits.NumFilters == numFilters && "NumFilters overflow");
526   }
527 
528   static size_t getSizeForNumFilters(unsigned numFilters) {
529     return sizeof(EHFilterScope) + numFilters * sizeof(llvm::Value*);
530   }
531 
532   unsigned getNumFilters() const { return FilterBits.NumFilters; }
533 
534   void setFilter(unsigned i, llvm::Value *filterValue) {
535     assert(i < getNumFilters());
536     getFilters()[i] = filterValue;
537   }
538 
539   llvm::Value *getFilter(unsigned i) const {
540     assert(i < getNumFilters());
541     return getFilters()[i];
542   }
543 
544   static bool classof(const EHScope *scope) {
545     return scope->getKind() == Filter;
546   }
547 };
548 
549 /// An exceptions scope which calls std::terminate if any exception
550 /// reaches it.
551 class EHTerminateScope : public EHScope {
552 public:
553   EHTerminateScope(EHScopeStack::stable_iterator enclosingEHScope)
554     : EHScope(Terminate, enclosingEHScope) {}
555   static size_t getSize() { return sizeof(EHTerminateScope); }
556 
557   static bool classof(const EHScope *scope) {
558     return scope->getKind() == Terminate;
559   }
560 };
561 
562 /// A non-stable pointer into the scope stack.
563 class EHScopeStack::iterator {
564   char *Ptr;
565 
566   friend class EHScopeStack;
567   explicit iterator(char *Ptr) : Ptr(Ptr) {}
568 
569 public:
570   iterator() : Ptr(nullptr) {}
571 
572   EHScope *get() const {
573     return reinterpret_cast<EHScope*>(Ptr);
574   }
575 
576   EHScope *operator->() const { return get(); }
577   EHScope &operator*() const { return *get(); }
578 
579   iterator &operator++() {
580     size_t Size;
581     switch (get()->getKind()) {
582     case EHScope::Catch:
583       Size = EHCatchScope::getSizeForNumHandlers(
584           static_cast<const EHCatchScope *>(get())->getNumHandlers());
585       break;
586 
587     case EHScope::Filter:
588       Size = EHFilterScope::getSizeForNumFilters(
589           static_cast<const EHFilterScope *>(get())->getNumFilters());
590       break;
591 
592     case EHScope::Cleanup:
593       Size = static_cast<const EHCleanupScope *>(get())->getAllocatedSize();
594       break;
595 
596     case EHScope::Terminate:
597       Size = EHTerminateScope::getSize();
598       break;
599     }
600     Ptr += llvm::alignTo(Size, ScopeStackAlignment);
601     return *this;
602   }
603 
604   iterator next() {
605     iterator copy = *this;
606     ++copy;
607     return copy;
608   }
609 
610   iterator operator++(int) {
611     iterator copy = *this;
612     operator++();
613     return copy;
614   }
615 
616   bool encloses(iterator other) const { return Ptr >= other.Ptr; }
617   bool strictlyEncloses(iterator other) const { return Ptr > other.Ptr; }
618 
619   bool operator==(iterator other) const { return Ptr == other.Ptr; }
620   bool operator!=(iterator other) const { return Ptr != other.Ptr; }
621 };
622 
623 inline EHScopeStack::iterator EHScopeStack::begin() const {
624   return iterator(StartOfData);
625 }
626 
627 inline EHScopeStack::iterator EHScopeStack::end() const {
628   return iterator(EndOfBuffer);
629 }
630 
631 inline void EHScopeStack::popCatch() {
632   assert(!empty() && "popping exception stack when not empty");
633 
634   EHCatchScope &scope = cast<EHCatchScope>(*begin());
635   InnermostEHScope = scope.getEnclosingEHScope();
636   deallocate(EHCatchScope::getSizeForNumHandlers(scope.getNumHandlers()));
637 }
638 
639 inline void EHScopeStack::popTerminate() {
640   assert(!empty() && "popping exception stack when not empty");
641 
642   EHTerminateScope &scope = cast<EHTerminateScope>(*begin());
643   InnermostEHScope = scope.getEnclosingEHScope();
644   deallocate(EHTerminateScope::getSize());
645 }
646 
647 inline EHScopeStack::iterator EHScopeStack::find(stable_iterator sp) const {
648   assert(sp.isValid() && "finding invalid savepoint");
649   assert(sp.Size <= stable_begin().Size && "finding savepoint after pop");
650   return iterator(EndOfBuffer - sp.Size);
651 }
652 
653 inline EHScopeStack::stable_iterator
654 EHScopeStack::stabilize(iterator ir) const {
655   assert(StartOfData <= ir.Ptr && ir.Ptr <= EndOfBuffer);
656   return stable_iterator(EndOfBuffer - ir.Ptr);
657 }
658 
659 /// The exceptions personality for a function.
660 struct EHPersonality {
661   const char *PersonalityFn;
662 
663   // If this is non-null, this personality requires a non-standard
664   // function for rethrowing an exception after a catchall cleanup.
665   // This function must have prototype void(void*).
666   const char *CatchallRethrowFn;
667 
668   static const EHPersonality &get(CodeGenModule &CGM, const FunctionDecl *FD);
669   static const EHPersonality &get(CodeGenFunction &CGF);
670 
671   static const EHPersonality GNU_C;
672   static const EHPersonality GNU_C_SJLJ;
673   static const EHPersonality GNU_C_SEH;
674   static const EHPersonality GNU_ObjC;
675   static const EHPersonality GNU_ObjC_SJLJ;
676   static const EHPersonality GNU_ObjC_SEH;
677   static const EHPersonality GNUstep_ObjC;
678   static const EHPersonality GNU_ObjCXX;
679   static const EHPersonality NeXT_ObjC;
680   static const EHPersonality GNU_CPlusPlus;
681   static const EHPersonality GNU_CPlusPlus_SJLJ;
682   static const EHPersonality GNU_CPlusPlus_SEH;
683   static const EHPersonality MSVC_except_handler;
684   static const EHPersonality MSVC_C_specific_handler;
685   static const EHPersonality MSVC_CxxFrameHandler3;
686   static const EHPersonality GNU_Wasm_CPlusPlus;
687   static const EHPersonality XL_CPlusPlus;
688   static const EHPersonality ZOS_CPlusPlus;
689 
690   /// Does this personality use landingpads or the family of pad instructions
691   /// designed to form funclets?
692   bool usesFuncletPads() const {
693     return isMSVCPersonality() || isWasmPersonality();
694   }
695 
696   bool isMSVCPersonality() const {
697     return this == &MSVC_except_handler || this == &MSVC_C_specific_handler ||
698            this == &MSVC_CxxFrameHandler3;
699   }
700 
701   bool isWasmPersonality() const { return this == &GNU_Wasm_CPlusPlus; }
702 
703   bool isMSVCXXPersonality() const { return this == &MSVC_CxxFrameHandler3; }
704 };
705 }
706 }
707 
708 #endif
709