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