1259701Sdim//===-- EHScopeStack.h - Stack for cleanup IR generation --------*- C++ -*-===// 2259701Sdim// 3259701Sdim// The LLVM Compiler Infrastructure 4259701Sdim// 5259701Sdim// This file is distributed under the University of Illinois Open Source 6259701Sdim// License. See LICENSE.TXT for details. 7259701Sdim// 8259701Sdim//===----------------------------------------------------------------------===// 9259701Sdim// 10259701Sdim// These classes should be the minimum interface required for other parts of 11259701Sdim// CodeGen to emit cleanups. The implementation is in CGCleanup.cpp and other 12259701Sdim// implemenentation details that are not widely needed are in CGCleanup.h. 13259701Sdim// 14259701Sdim//===----------------------------------------------------------------------===// 15259701Sdim 16259701Sdim#ifndef CLANG_CODEGEN_EHSCOPESTACK_H 17259701Sdim#define CLANG_CODEGEN_EHSCOPESTACK_H 18259701Sdim 19259701Sdim#include "clang/Basic/LLVM.h" 20259701Sdim#include "llvm/ADT/SmallVector.h" 21259701Sdim#include "llvm/IR/BasicBlock.h" 22259701Sdim#include "llvm/IR/Value.h" 23259701Sdim#include "llvm/IR/Instructions.h" 24259701Sdim 25259701Sdimnamespace clang { 26259701Sdimnamespace CodeGen { 27259701Sdim 28259701Sdimclass CodeGenFunction; 29259701Sdim 30259701Sdim/// A branch fixup. These are required when emitting a goto to a 31259701Sdim/// label which hasn't been emitted yet. The goto is optimistically 32259701Sdim/// emitted as a branch to the basic block for the label, and (if it 33259701Sdim/// occurs in a scope with non-trivial cleanups) a fixup is added to 34259701Sdim/// the innermost cleanup. When a (normal) cleanup is popped, any 35259701Sdim/// unresolved fixups in that scope are threaded through the cleanup. 36259701Sdimstruct BranchFixup { 37259701Sdim /// The block containing the terminator which needs to be modified 38259701Sdim /// into a switch if this fixup is resolved into the current scope. 39259701Sdim /// If null, LatestBranch points directly to the destination. 40259701Sdim llvm::BasicBlock *OptimisticBranchBlock; 41259701Sdim 42259701Sdim /// The ultimate destination of the branch. 43259701Sdim /// 44259701Sdim /// This can be set to null to indicate that this fixup was 45259701Sdim /// successfully resolved. 46259701Sdim llvm::BasicBlock *Destination; 47259701Sdim 48259701Sdim /// The destination index value. 49259701Sdim unsigned DestinationIndex; 50259701Sdim 51259701Sdim /// The initial branch of the fixup. 52259701Sdim llvm::BranchInst *InitialBranch; 53259701Sdim}; 54259701Sdim 55259701Sdimtemplate <class T> struct InvariantValue { 56259701Sdim typedef T type; 57259701Sdim typedef T saved_type; 58259701Sdim static bool needsSaving(type value) { return false; } 59259701Sdim static saved_type save(CodeGenFunction &CGF, type value) { return value; } 60259701Sdim static type restore(CodeGenFunction &CGF, saved_type value) { return value; } 61259701Sdim}; 62259701Sdim 63259701Sdim/// A metaprogramming class for ensuring that a value will dominate an 64259701Sdim/// arbitrary position in a function. 65259701Sdimtemplate <class T> struct DominatingValue : InvariantValue<T> {}; 66259701Sdim 67259701Sdimtemplate <class T, bool mightBeInstruction = 68259701Sdim llvm::is_base_of<llvm::Value, T>::value && 69259701Sdim !llvm::is_base_of<llvm::Constant, T>::value && 70259701Sdim !llvm::is_base_of<llvm::BasicBlock, T>::value> 71259701Sdimstruct DominatingPointer; 72259701Sdimtemplate <class T> struct DominatingPointer<T,false> : InvariantValue<T*> {}; 73259701Sdim// template <class T> struct DominatingPointer<T,true> at end of file 74259701Sdim 75259701Sdimtemplate <class T> struct DominatingValue<T*> : DominatingPointer<T> {}; 76259701Sdim 77259701Sdimenum CleanupKind { 78259701Sdim EHCleanup = 0x1, 79259701Sdim NormalCleanup = 0x2, 80259701Sdim NormalAndEHCleanup = EHCleanup | NormalCleanup, 81259701Sdim 82259701Sdim InactiveCleanup = 0x4, 83259701Sdim InactiveEHCleanup = EHCleanup | InactiveCleanup, 84259701Sdim InactiveNormalCleanup = NormalCleanup | InactiveCleanup, 85259701Sdim InactiveNormalAndEHCleanup = NormalAndEHCleanup | InactiveCleanup 86259701Sdim}; 87259701Sdim 88259701Sdim/// A stack of scopes which respond to exceptions, including cleanups 89259701Sdim/// and catch blocks. 90259701Sdimclass EHScopeStack { 91259701Sdimpublic: 92259701Sdim /// A saved depth on the scope stack. This is necessary because 93259701Sdim /// pushing scopes onto the stack invalidates iterators. 94259701Sdim class stable_iterator { 95259701Sdim friend class EHScopeStack; 96259701Sdim 97259701Sdim /// Offset from StartOfData to EndOfBuffer. 98259701Sdim ptrdiff_t Size; 99259701Sdim 100259701Sdim stable_iterator(ptrdiff_t Size) : Size(Size) {} 101259701Sdim 102259701Sdim public: 103259701Sdim static stable_iterator invalid() { return stable_iterator(-1); } 104259701Sdim stable_iterator() : Size(-1) {} 105259701Sdim 106259701Sdim bool isValid() const { return Size >= 0; } 107259701Sdim 108259701Sdim /// Returns true if this scope encloses I. 109259701Sdim /// Returns false if I is invalid. 110259701Sdim /// This scope must be valid. 111259701Sdim bool encloses(stable_iterator I) const { return Size <= I.Size; } 112259701Sdim 113259701Sdim /// Returns true if this scope strictly encloses I: that is, 114259701Sdim /// if it encloses I and is not I. 115259701Sdim /// Returns false is I is invalid. 116259701Sdim /// This scope must be valid. 117259701Sdim bool strictlyEncloses(stable_iterator I) const { return Size < I.Size; } 118259701Sdim 119259701Sdim friend bool operator==(stable_iterator A, stable_iterator B) { 120259701Sdim return A.Size == B.Size; 121259701Sdim } 122259701Sdim friend bool operator!=(stable_iterator A, stable_iterator B) { 123259701Sdim return A.Size != B.Size; 124259701Sdim } 125259701Sdim }; 126259701Sdim 127259701Sdim /// Information for lazily generating a cleanup. Subclasses must be 128259701Sdim /// POD-like: cleanups will not be destructed, and they will be 129259701Sdim /// allocated on the cleanup stack and freely copied and moved 130259701Sdim /// around. 131259701Sdim /// 132259701Sdim /// Cleanup implementations should generally be declared in an 133259701Sdim /// anonymous namespace. 134259701Sdim class Cleanup { 135259701Sdim // Anchor the construction vtable. 136259701Sdim virtual void anchor(); 137259701Sdim public: 138259701Sdim /// Generation flags. 139259701Sdim class Flags { 140259701Sdim enum { 141259701Sdim F_IsForEH = 0x1, 142259701Sdim F_IsNormalCleanupKind = 0x2, 143259701Sdim F_IsEHCleanupKind = 0x4 144259701Sdim }; 145259701Sdim unsigned flags; 146259701Sdim 147259701Sdim public: 148259701Sdim Flags() : flags(0) {} 149259701Sdim 150259701Sdim /// isForEH - true if the current emission is for an EH cleanup. 151259701Sdim bool isForEHCleanup() const { return flags & F_IsForEH; } 152259701Sdim bool isForNormalCleanup() const { return !isForEHCleanup(); } 153259701Sdim void setIsForEHCleanup() { flags |= F_IsForEH; } 154259701Sdim 155259701Sdim bool isNormalCleanupKind() const { return flags & F_IsNormalCleanupKind; } 156259701Sdim void setIsNormalCleanupKind() { flags |= F_IsNormalCleanupKind; } 157259701Sdim 158259701Sdim /// isEHCleanupKind - true if the cleanup was pushed as an EH 159259701Sdim /// cleanup. 160259701Sdim bool isEHCleanupKind() const { return flags & F_IsEHCleanupKind; } 161259701Sdim void setIsEHCleanupKind() { flags |= F_IsEHCleanupKind; } 162259701Sdim }; 163259701Sdim 164259701Sdim // Provide a virtual destructor to suppress a very common warning 165259701Sdim // that unfortunately cannot be suppressed without this. Cleanups 166259701Sdim // should not rely on this destructor ever being called. 167259701Sdim virtual ~Cleanup() {} 168259701Sdim 169259701Sdim /// Emit the cleanup. For normal cleanups, this is run in the 170259701Sdim /// same EH context as when the cleanup was pushed, i.e. the 171259701Sdim /// immediately-enclosing context of the cleanup scope. For 172259701Sdim /// EH cleanups, this is run in a terminate context. 173259701Sdim /// 174259701Sdim // \param flags cleanup kind. 175259701Sdim virtual void Emit(CodeGenFunction &CGF, Flags flags) = 0; 176259701Sdim }; 177259701Sdim 178259701Sdim /// ConditionalCleanupN stores the saved form of its N parameters, 179259701Sdim /// then restores them and performs the cleanup. 180259701Sdim template <class T, class A0> 181259701Sdim class ConditionalCleanup1 : public Cleanup { 182259701Sdim typedef typename DominatingValue<A0>::saved_type A0_saved; 183259701Sdim A0_saved a0_saved; 184259701Sdim 185259701Sdim void Emit(CodeGenFunction &CGF, Flags flags) { 186259701Sdim A0 a0 = DominatingValue<A0>::restore(CGF, a0_saved); 187259701Sdim T(a0).Emit(CGF, flags); 188259701Sdim } 189259701Sdim 190259701Sdim public: 191259701Sdim ConditionalCleanup1(A0_saved a0) 192259701Sdim : a0_saved(a0) {} 193259701Sdim }; 194259701Sdim 195259701Sdim template <class T, class A0, class A1> 196259701Sdim class ConditionalCleanup2 : public Cleanup { 197259701Sdim typedef typename DominatingValue<A0>::saved_type A0_saved; 198259701Sdim typedef typename DominatingValue<A1>::saved_type A1_saved; 199259701Sdim A0_saved a0_saved; 200259701Sdim A1_saved a1_saved; 201259701Sdim 202259701Sdim void Emit(CodeGenFunction &CGF, Flags flags) { 203259701Sdim A0 a0 = DominatingValue<A0>::restore(CGF, a0_saved); 204259701Sdim A1 a1 = DominatingValue<A1>::restore(CGF, a1_saved); 205259701Sdim T(a0, a1).Emit(CGF, flags); 206259701Sdim } 207259701Sdim 208259701Sdim public: 209259701Sdim ConditionalCleanup2(A0_saved a0, A1_saved a1) 210259701Sdim : a0_saved(a0), a1_saved(a1) {} 211259701Sdim }; 212259701Sdim 213259701Sdim template <class T, class A0, class A1, class A2> 214259701Sdim class ConditionalCleanup3 : public Cleanup { 215259701Sdim typedef typename DominatingValue<A0>::saved_type A0_saved; 216259701Sdim typedef typename DominatingValue<A1>::saved_type A1_saved; 217259701Sdim typedef typename DominatingValue<A2>::saved_type A2_saved; 218259701Sdim A0_saved a0_saved; 219259701Sdim A1_saved a1_saved; 220259701Sdim A2_saved a2_saved; 221259701Sdim 222259701Sdim void Emit(CodeGenFunction &CGF, Flags flags) { 223259701Sdim A0 a0 = DominatingValue<A0>::restore(CGF, a0_saved); 224259701Sdim A1 a1 = DominatingValue<A1>::restore(CGF, a1_saved); 225259701Sdim A2 a2 = DominatingValue<A2>::restore(CGF, a2_saved); 226259701Sdim T(a0, a1, a2).Emit(CGF, flags); 227259701Sdim } 228259701Sdim 229259701Sdim public: 230259701Sdim ConditionalCleanup3(A0_saved a0, A1_saved a1, A2_saved a2) 231259701Sdim : a0_saved(a0), a1_saved(a1), a2_saved(a2) {} 232259701Sdim }; 233259701Sdim 234259701Sdim template <class T, class A0, class A1, class A2, class A3> 235259701Sdim class ConditionalCleanup4 : public Cleanup { 236259701Sdim typedef typename DominatingValue<A0>::saved_type A0_saved; 237259701Sdim typedef typename DominatingValue<A1>::saved_type A1_saved; 238259701Sdim typedef typename DominatingValue<A2>::saved_type A2_saved; 239259701Sdim typedef typename DominatingValue<A3>::saved_type A3_saved; 240259701Sdim A0_saved a0_saved; 241259701Sdim A1_saved a1_saved; 242259701Sdim A2_saved a2_saved; 243259701Sdim A3_saved a3_saved; 244259701Sdim 245259701Sdim void Emit(CodeGenFunction &CGF, Flags flags) { 246259701Sdim A0 a0 = DominatingValue<A0>::restore(CGF, a0_saved); 247259701Sdim A1 a1 = DominatingValue<A1>::restore(CGF, a1_saved); 248259701Sdim A2 a2 = DominatingValue<A2>::restore(CGF, a2_saved); 249259701Sdim A3 a3 = DominatingValue<A3>::restore(CGF, a3_saved); 250259701Sdim T(a0, a1, a2, a3).Emit(CGF, flags); 251259701Sdim } 252259701Sdim 253259701Sdim public: 254259701Sdim ConditionalCleanup4(A0_saved a0, A1_saved a1, A2_saved a2, A3_saved a3) 255259701Sdim : a0_saved(a0), a1_saved(a1), a2_saved(a2), a3_saved(a3) {} 256259701Sdim }; 257259701Sdim 258259701Sdimprivate: 259259701Sdim // The implementation for this class is in CGException.h and 260259701Sdim // CGException.cpp; the definition is here because it's used as a 261259701Sdim // member of CodeGenFunction. 262259701Sdim 263259701Sdim /// The start of the scope-stack buffer, i.e. the allocated pointer 264259701Sdim /// for the buffer. All of these pointers are either simultaneously 265259701Sdim /// null or simultaneously valid. 266259701Sdim char *StartOfBuffer; 267259701Sdim 268259701Sdim /// The end of the buffer. 269259701Sdim char *EndOfBuffer; 270259701Sdim 271259701Sdim /// The first valid entry in the buffer. 272259701Sdim char *StartOfData; 273259701Sdim 274259701Sdim /// The innermost normal cleanup on the stack. 275259701Sdim stable_iterator InnermostNormalCleanup; 276259701Sdim 277259701Sdim /// The innermost EH scope on the stack. 278259701Sdim stable_iterator InnermostEHScope; 279259701Sdim 280259701Sdim /// The current set of branch fixups. A branch fixup is a jump to 281259701Sdim /// an as-yet unemitted label, i.e. a label for which we don't yet 282259701Sdim /// know the EH stack depth. Whenever we pop a cleanup, we have 283259701Sdim /// to thread all the current branch fixups through it. 284259701Sdim /// 285259701Sdim /// Fixups are recorded as the Use of the respective branch or 286259701Sdim /// switch statement. The use points to the final destination. 287259701Sdim /// When popping out of a cleanup, these uses are threaded through 288259701Sdim /// the cleanup and adjusted to point to the new cleanup. 289259701Sdim /// 290259701Sdim /// Note that branches are allowed to jump into protected scopes 291259701Sdim /// in certain situations; e.g. the following code is legal: 292259701Sdim /// struct A { ~A(); }; // trivial ctor, non-trivial dtor 293259701Sdim /// goto foo; 294259701Sdim /// A a; 295259701Sdim /// foo: 296259701Sdim /// bar(); 297259701Sdim SmallVector<BranchFixup, 8> BranchFixups; 298259701Sdim 299259701Sdim char *allocate(size_t Size); 300259701Sdim 301259701Sdim void *pushCleanup(CleanupKind K, size_t DataSize); 302259701Sdim 303259701Sdimpublic: 304259701Sdim EHScopeStack() : StartOfBuffer(0), EndOfBuffer(0), StartOfData(0), 305259701Sdim InnermostNormalCleanup(stable_end()), 306259701Sdim InnermostEHScope(stable_end()) {} 307259701Sdim ~EHScopeStack() { delete[] StartOfBuffer; } 308259701Sdim 309259701Sdim // Variadic templates would make this not terrible. 310259701Sdim 311259701Sdim /// Push a lazily-created cleanup on the stack. 312259701Sdim template <class T> 313259701Sdim void pushCleanup(CleanupKind Kind) { 314259701Sdim void *Buffer = pushCleanup(Kind, sizeof(T)); 315259701Sdim Cleanup *Obj = new(Buffer) T(); 316259701Sdim (void) Obj; 317259701Sdim } 318259701Sdim 319259701Sdim /// Push a lazily-created cleanup on the stack. 320259701Sdim template <class T, class A0> 321259701Sdim void pushCleanup(CleanupKind Kind, A0 a0) { 322259701Sdim void *Buffer = pushCleanup(Kind, sizeof(T)); 323259701Sdim Cleanup *Obj = new(Buffer) T(a0); 324259701Sdim (void) Obj; 325259701Sdim } 326259701Sdim 327259701Sdim /// Push a lazily-created cleanup on the stack. 328259701Sdim template <class T, class A0, class A1> 329259701Sdim void pushCleanup(CleanupKind Kind, A0 a0, A1 a1) { 330259701Sdim void *Buffer = pushCleanup(Kind, sizeof(T)); 331259701Sdim Cleanup *Obj = new(Buffer) T(a0, a1); 332259701Sdim (void) Obj; 333259701Sdim } 334259701Sdim 335259701Sdim /// Push a lazily-created cleanup on the stack. 336259701Sdim template <class T, class A0, class A1, class A2> 337259701Sdim void pushCleanup(CleanupKind Kind, A0 a0, A1 a1, A2 a2) { 338259701Sdim void *Buffer = pushCleanup(Kind, sizeof(T)); 339259701Sdim Cleanup *Obj = new(Buffer) T(a0, a1, a2); 340259701Sdim (void) Obj; 341259701Sdim } 342259701Sdim 343259701Sdim /// Push a lazily-created cleanup on the stack. 344259701Sdim template <class T, class A0, class A1, class A2, class A3> 345259701Sdim void pushCleanup(CleanupKind Kind, A0 a0, A1 a1, A2 a2, A3 a3) { 346259701Sdim void *Buffer = pushCleanup(Kind, sizeof(T)); 347259701Sdim Cleanup *Obj = new(Buffer) T(a0, a1, a2, a3); 348259701Sdim (void) Obj; 349259701Sdim } 350259701Sdim 351259701Sdim /// Push a lazily-created cleanup on the stack. 352259701Sdim template <class T, class A0, class A1, class A2, class A3, class A4> 353259701Sdim void pushCleanup(CleanupKind Kind, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { 354259701Sdim void *Buffer = pushCleanup(Kind, sizeof(T)); 355259701Sdim Cleanup *Obj = new(Buffer) T(a0, a1, a2, a3, a4); 356259701Sdim (void) Obj; 357259701Sdim } 358259701Sdim 359259701Sdim // Feel free to add more variants of the following: 360259701Sdim 361259701Sdim /// Push a cleanup with non-constant storage requirements on the 362259701Sdim /// stack. The cleanup type must provide an additional static method: 363259701Sdim /// static size_t getExtraSize(size_t); 364259701Sdim /// The argument to this method will be the value N, which will also 365259701Sdim /// be passed as the first argument to the constructor. 366259701Sdim /// 367259701Sdim /// The data stored in the extra storage must obey the same 368259701Sdim /// restrictions as normal cleanup member data. 369259701Sdim /// 370259701Sdim /// The pointer returned from this method is valid until the cleanup 371259701Sdim /// stack is modified. 372259701Sdim template <class T, class A0, class A1, class A2> 373259701Sdim T *pushCleanupWithExtra(CleanupKind Kind, size_t N, A0 a0, A1 a1, A2 a2) { 374259701Sdim void *Buffer = pushCleanup(Kind, sizeof(T) + T::getExtraSize(N)); 375259701Sdim return new (Buffer) T(N, a0, a1, a2); 376259701Sdim } 377259701Sdim 378259701Sdim void pushCopyOfCleanup(CleanupKind Kind, const void *Cleanup, size_t Size) { 379259701Sdim void *Buffer = pushCleanup(Kind, Size); 380259701Sdim std::memcpy(Buffer, Cleanup, Size); 381259701Sdim } 382259701Sdim 383259701Sdim /// Pops a cleanup scope off the stack. This is private to CGCleanup.cpp. 384259701Sdim void popCleanup(); 385259701Sdim 386259701Sdim /// Push a set of catch handlers on the stack. The catch is 387259701Sdim /// uninitialized and will need to have the given number of handlers 388259701Sdim /// set on it. 389259701Sdim class EHCatchScope *pushCatch(unsigned NumHandlers); 390259701Sdim 391259701Sdim /// Pops a catch scope off the stack. This is private to CGException.cpp. 392259701Sdim void popCatch(); 393259701Sdim 394259701Sdim /// Push an exceptions filter on the stack. 395259701Sdim class EHFilterScope *pushFilter(unsigned NumFilters); 396259701Sdim 397259701Sdim /// Pops an exceptions filter off the stack. 398259701Sdim void popFilter(); 399259701Sdim 400259701Sdim /// Push a terminate handler on the stack. 401259701Sdim void pushTerminate(); 402259701Sdim 403259701Sdim /// Pops a terminate handler off the stack. 404259701Sdim void popTerminate(); 405259701Sdim 406259701Sdim /// Determines whether the exception-scopes stack is empty. 407259701Sdim bool empty() const { return StartOfData == EndOfBuffer; } 408259701Sdim 409259701Sdim bool requiresLandingPad() const { 410259701Sdim return InnermostEHScope != stable_end(); 411259701Sdim } 412259701Sdim 413259701Sdim /// Determines whether there are any normal cleanups on the stack. 414259701Sdim bool hasNormalCleanups() const { 415259701Sdim return InnermostNormalCleanup != stable_end(); 416259701Sdim } 417259701Sdim 418259701Sdim /// Returns the innermost normal cleanup on the stack, or 419259701Sdim /// stable_end() if there are no normal cleanups. 420259701Sdim stable_iterator getInnermostNormalCleanup() const { 421259701Sdim return InnermostNormalCleanup; 422259701Sdim } 423259701Sdim stable_iterator getInnermostActiveNormalCleanup() const; 424259701Sdim 425259701Sdim stable_iterator getInnermostEHScope() const { 426259701Sdim return InnermostEHScope; 427259701Sdim } 428259701Sdim 429259701Sdim stable_iterator getInnermostActiveEHScope() const; 430259701Sdim 431259701Sdim /// An unstable reference to a scope-stack depth. Invalidated by 432259701Sdim /// pushes but not pops. 433259701Sdim class iterator; 434259701Sdim 435259701Sdim /// Returns an iterator pointing to the innermost EH scope. 436259701Sdim iterator begin() const; 437259701Sdim 438259701Sdim /// Returns an iterator pointing to the outermost EH scope. 439259701Sdim iterator end() const; 440259701Sdim 441259701Sdim /// Create a stable reference to the top of the EH stack. The 442259701Sdim /// returned reference is valid until that scope is popped off the 443259701Sdim /// stack. 444259701Sdim stable_iterator stable_begin() const { 445259701Sdim return stable_iterator(EndOfBuffer - StartOfData); 446259701Sdim } 447259701Sdim 448259701Sdim /// Create a stable reference to the bottom of the EH stack. 449259701Sdim static stable_iterator stable_end() { 450259701Sdim return stable_iterator(0); 451259701Sdim } 452259701Sdim 453259701Sdim /// Translates an iterator into a stable_iterator. 454259701Sdim stable_iterator stabilize(iterator it) const; 455259701Sdim 456259701Sdim /// Turn a stable reference to a scope depth into a unstable pointer 457259701Sdim /// to the EH stack. 458259701Sdim iterator find(stable_iterator save) const; 459259701Sdim 460259701Sdim /// Removes the cleanup pointed to by the given stable_iterator. 461259701Sdim void removeCleanup(stable_iterator save); 462259701Sdim 463259701Sdim /// Add a branch fixup to the current cleanup scope. 464259701Sdim BranchFixup &addBranchFixup() { 465259701Sdim assert(hasNormalCleanups() && "adding fixup in scope without cleanups"); 466259701Sdim BranchFixups.push_back(BranchFixup()); 467259701Sdim return BranchFixups.back(); 468259701Sdim } 469259701Sdim 470259701Sdim unsigned getNumBranchFixups() const { return BranchFixups.size(); } 471259701Sdim BranchFixup &getBranchFixup(unsigned I) { 472259701Sdim assert(I < getNumBranchFixups()); 473259701Sdim return BranchFixups[I]; 474259701Sdim } 475259701Sdim 476259701Sdim /// Pops lazily-removed fixups from the end of the list. This 477259701Sdim /// should only be called by procedures which have just popped a 478259701Sdim /// cleanup or resolved one or more fixups. 479259701Sdim void popNullFixups(); 480259701Sdim 481259701Sdim /// Clears the branch-fixups list. This should only be called by 482259701Sdim /// ResolveAllBranchFixups. 483259701Sdim void clearFixups() { BranchFixups.clear(); } 484259701Sdim}; 485259701Sdim 486259701Sdim} // namespace CodeGen 487259701Sdim} // namespace clang 488259701Sdim 489259701Sdim#endif 490