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