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