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