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