diff options
author | John McCall <rjmccall@apple.com> | 2010-07-06 01:34:17 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2010-07-06 01:34:17 +0000 |
commit | f1549f66a8216a78112286e3978cea2c29d6334c (patch) | |
tree | abcabedb8b72594ef7ea106fc08684927d3a386b /lib/CodeGen/CodeGenFunction.h | |
parent | 6c47a9b9779216ef24526c064d5b6ab0db0b5009 (diff) |
Validated by nightly-test runs on x86 and x86-64 darwin, including after
self-host. Hopefully these results hold up on different platforms.
I tried to keep the GNU ObjC runtime happy, but it's hard for me to test.
Reimplement how clang generates IR for exceptions. Instead of creating new
invoke destinations which sequentially chain to the previous destination,
push a more semantic representation of *why* we need the cleanup/catch/filter
behavior, then collect that information into a single landing pad upon request.
Also reorganizes how normal cleanups (i.e. cleanups triggered by non-exceptional
control flow) are generated, since it's actually fairly closely tied in with
the former. Remove the need to track which cleanup scope a block is associated
with.
Document a lot of previously poorly-understood (by me, at least) behavior.
The new framework implements the Horrible Hack (tm), which requires every
landing pad to have a catch-all so that inlining will work. Clang no longer
requires the Horrible Hack just to make exceptions flow correctly within
a function, however. The HH is an unfortunate requirement of LLVM's EH IR.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@107631 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen/CodeGenFunction.h')
-rw-r--r-- | lib/CodeGen/CodeGenFunction.h | 580 |
1 files changed, 362 insertions, 218 deletions
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 18bd625ffd..850df7ee7c 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -37,6 +37,7 @@ namespace llvm { class SwitchInst; class Twine; class Value; + class CallSite; } namespace clang { @@ -69,12 +70,244 @@ namespace CodeGen { class CGRecordLayout; class CGBlockInfo; +/// A branch fixup. These are required when emitting a goto to a +/// label which hasn't been emitted yet. The goto is optimistically +/// emitted as a branch to the basic block for the label, and (if it +/// occurs in a scope with non-trivial cleanups) a fixup is added to +/// the innermost cleanup. When a (normal) cleanup is popped, any +/// unresolved fixups in that scope are threaded through the cleanup. +struct BranchFixup { + /// The origin of the branch. Any switch-index stores required by + /// cleanup threading are added before this instruction. + llvm::Instruction *Origin; + + /// The destination of the branch. + /// + /// This can be set to null to indicate that this fixup was + /// successfully resolved. + llvm::BasicBlock *Destination; + + /// The last branch of the fixup. It is an invariant that + /// LatestBranch->getSuccessor(LatestBranchIndex) == Destination. + /// + /// The branch is always either a BranchInst or a SwitchInst. + llvm::TerminatorInst *LatestBranch; + unsigned LatestBranchIndex; +}; + +/// A stack of scopes which respond to exceptions, including cleanups +/// and catch blocks. +class EHScopeStack { +public: + /// A saved depth on the scope stack. This is necessary because + /// pushing scopes onto the stack invalidates iterators. + class stable_iterator { + friend class EHScopeStack; + + /// Offset from StartOfData to EndOfBuffer. + ptrdiff_t Size; + + stable_iterator(ptrdiff_t Size) : Size(Size) {} + + public: + static stable_iterator invalid() { return stable_iterator(-1); } + stable_iterator() : Size(-1) {} + + bool isValid() const { return Size >= 0; } + + friend bool operator==(stable_iterator A, stable_iterator B) { + return A.Size == B.Size; + } + friend bool operator!=(stable_iterator A, stable_iterator B) { + return A.Size != B.Size; + } + }; + +private: + // The implementation for this class is in CGException.h and + // CGException.cpp; the definition is here because it's used as a + // member of CodeGenFunction. + + /// The start of the scope-stack buffer, i.e. the allocated pointer + /// for the buffer. All of these pointers are either simultaneously + /// null or simultaneously valid. + char *StartOfBuffer; + + /// The end of the buffer. + char *EndOfBuffer; + + /// The first valid entry in the buffer. + char *StartOfData; + + /// The innermost normal cleanup on the stack. + stable_iterator InnermostNormalCleanup; + + /// The innermost EH cleanup on the stack. + stable_iterator InnermostEHCleanup; + + /// The number of catches on the stack. + unsigned CatchDepth; + + /// The current set of branch fixups. A branch fixup is a jump to + /// an as-yet unemitted label, i.e. a label for which we don't yet + /// know the EH stack depth. Whenever we pop a cleanup, we have + /// to thread all the current branch fixups through it. + /// + /// Fixups are recorded as the Use of the respective branch or + /// switch statement. The use points to the final destination. + /// When popping out of a cleanup, these uses are threaded through + /// the cleanup and adjusted to point to the new cleanup. + /// + /// Note that branches are allowed to jump into protected scopes + /// in certain situations; e.g. the following code is legal: + /// struct A { ~A(); }; // trivial ctor, non-trivial dtor + /// goto foo; + /// A a; + /// foo: + /// bar(); + llvm::SmallVector<BranchFixup, 8> BranchFixups; + + char *allocate(size_t Size); + + void popNullFixups(); + +public: + EHScopeStack() : StartOfBuffer(0), EndOfBuffer(0), StartOfData(0), + InnermostNormalCleanup(stable_end()), + InnermostEHCleanup(stable_end()), + CatchDepth(0) {} + ~EHScopeStack() { delete[] StartOfBuffer; } + + /// Push a cleanup on the stack. + void pushCleanup(llvm::BasicBlock *NormalEntry, + llvm::BasicBlock *NormalExit, + llvm::BasicBlock *EHEntry, + llvm::BasicBlock *EHExit); + + /// Pops a cleanup scope off the stack. This should only be called + /// by CodeGenFunction::PopCleanupBlock. + void popCleanup(); + + /// Push a set of catch handlers on the stack. The catch is + /// uninitialized and will need to have the given number of handlers + /// set on it. + class EHCatchScope *pushCatch(unsigned NumHandlers); + + /// Pops a catch scope off the stack. + void popCatch(); + + /// Push an exceptions filter on the stack. + class EHFilterScope *pushFilter(unsigned NumFilters); + + /// Pops an exceptions filter off the stack. + void popFilter(); + + /// Push a terminate handler on the stack. + void pushTerminate(); + + /// Pops a terminate handler off the stack. + void popTerminate(); + + /// Determines whether the exception-scopes stack is empty. + bool empty() const { return StartOfData == EndOfBuffer; } + + bool requiresLandingPad() const { + return (CatchDepth || hasEHCleanups()); + } + + /// Determines whether there are any normal cleanups on the stack. + bool hasNormalCleanups() const { + return InnermostNormalCleanup != stable_end(); + } + + /// Returns the innermost normal cleanup on the stack, or + /// stable_end() if there are no normal cleanups. + stable_iterator getInnermostNormalCleanup() const { + return InnermostNormalCleanup; + } + + /// Determines whether there are any EH cleanups on the stack. + bool hasEHCleanups() const { + return InnermostEHCleanup != stable_end(); + } + + /// Returns the innermost EH cleanup on the stack, or stable_end() + /// if there are no EH cleanups. + stable_iterator getInnermostEHCleanup() const { + return InnermostEHCleanup; + } + + /// An unstable reference to a scope-stack depth. Invalidated by + /// pushes but not pops. + class iterator; + + /// Returns an iterator pointing to the innermost EH scope. + iterator begin() const; + + /// Returns an iterator pointing to the outermost EH scope. + iterator end() const; + + /// Create a stable reference to the top of the EH stack. The + /// returned reference is valid until that scope is popped off the + /// stack. + stable_iterator stable_begin() const { + return stable_iterator(EndOfBuffer - StartOfData); + } + + /// Create a stable reference to the bottom of the EH stack. + static stable_iterator stable_end() { + return stable_iterator(0); + } + + /// Translates an iterator into a stable_iterator. + stable_iterator stabilize(iterator it) const; + + /// Finds the nearest cleanup enclosing the given iterator. + /// Returns stable_iterator::invalid() if there are no such cleanups. + stable_iterator getEnclosingEHCleanup(iterator it) const; + + /// Turn a stable reference to a scope depth into a unstable pointer + /// to the EH stack. + iterator find(stable_iterator save) const; + + /// Removes the cleanup pointed to by the given stable_iterator. + void removeCleanup(stable_iterator save); + + /// Add a branch fixup to the current cleanup scope. + BranchFixup &addBranchFixup() { + assert(hasNormalCleanups() && "adding fixup in scope without cleanups"); + BranchFixups.push_back(BranchFixup()); + return BranchFixups.back(); + } + + unsigned getNumBranchFixups() const { return BranchFixups.size(); } + BranchFixup &getBranchFixup(unsigned I) { + assert(I < getNumBranchFixups()); + return BranchFixups[I]; + } + + /// Mark any branch fixups leading to the given block as resolved. + void resolveBranchFixups(llvm::BasicBlock *Dest); +}; + /// CodeGenFunction - This class organizes the per-function state that is used /// while generating LLVM code. class CodeGenFunction : public BlockFunction { CodeGenFunction(const CodeGenFunction&); // DO NOT IMPLEMENT void operator=(const CodeGenFunction&); // DO NOT IMPLEMENT public: + /// A jump destination is a pair of a basic block and a cleanup + /// depth. They are used to implement direct jumps across cleanup + /// scopes, e.g. goto, break, continue, and return. + struct JumpDest { + JumpDest() : Block(0), ScopeDepth() {} + JumpDest(llvm::BasicBlock *Block, EHScopeStack::stable_iterator Depth) + : Block(Block), ScopeDepth(Depth) {} + + llvm::BasicBlock *Block; + EHScopeStack::stable_iterator ScopeDepth; + }; + CodeGenModule &CGM; // Per-module state. const TargetInfo &Target; @@ -94,7 +327,8 @@ public: GlobalDecl CurGD; /// ReturnBlock - Unified return block. - llvm::BasicBlock *ReturnBlock; + JumpDest ReturnBlock; + /// ReturnValue - The temporary alloca to hold the return value. This is null /// iff the function has no return value. llvm::Value *ReturnValue; @@ -113,141 +347,99 @@ public: /// \brief A mapping from NRVO variables to the flags used to indicate /// when the NRVO has been applied to this variable. llvm::DenseMap<const VarDecl *, llvm::Value *> NRVOFlags; - -public: - /// ObjCEHValueStack - Stack of Objective-C exception values, used for - /// rethrows. - llvm::SmallVector<llvm::Value*, 8> ObjCEHValueStack; - - /// PushCleanupBlock - Push a new cleanup entry on the stack and set the - /// passed in block as the cleanup block. - void PushCleanupBlock(llvm::BasicBlock *CleanupEntryBlock, - llvm::BasicBlock *CleanupExitBlock, - llvm::BasicBlock *PreviousInvokeDest, - bool EHOnly = false); - void PushCleanupBlock(llvm::BasicBlock *CleanupEntryBlock) { - PushCleanupBlock(CleanupEntryBlock, 0, getInvokeDest(), false); - } - /// CleanupBlockInfo - A struct representing a popped cleanup block. - struct CleanupBlockInfo { - /// CleanupEntryBlock - the cleanup entry block - llvm::BasicBlock *CleanupBlock; + EHScopeStack EHStack; - /// SwitchBlock - the block (if any) containing the switch instruction used - /// for jumping to the final destination. - llvm::BasicBlock *SwitchBlock; + /// The exception slot. All landing pads write the current + /// exception pointer into this alloca. + llvm::Value *ExceptionSlot; - /// EndBlock - the default destination for the switch instruction. - llvm::BasicBlock *EndBlock; + /// Emits a landing pad for the current EH stack. + llvm::BasicBlock *EmitLandingPad(); - /// EHOnly - True iff this cleanup should only be performed on the - /// exceptional edge. - bool EHOnly; + llvm::BasicBlock *getInvokeDestImpl(); - CleanupBlockInfo(llvm::BasicBlock *cb, llvm::BasicBlock *sb, - llvm::BasicBlock *eb, bool ehonly = false) - : CleanupBlock(cb), SwitchBlock(sb), EndBlock(eb), EHOnly(ehonly) {} - }; +public: + /// ObjCEHValueStack - Stack of Objective-C exception values, used for + /// rethrows. + llvm::SmallVector<llvm::Value*, 8> ObjCEHValueStack; - /// EHCleanupBlock - RAII object that will create a cleanup block for the - /// exceptional edge and set the insert point to that block. When destroyed, - /// it creates the cleanup edge and sets the insert point to the previous - /// block. - class EHCleanupBlock { - CodeGenFunction& CGF; - llvm::BasicBlock *PreviousInsertionBlock; - llvm::BasicBlock *CleanupHandler; - llvm::BasicBlock *PreviousInvokeDest; - public: - EHCleanupBlock(CodeGenFunction &cgf) - : CGF(cgf), - PreviousInsertionBlock(CGF.Builder.GetInsertBlock()), - CleanupHandler(CGF.createBasicBlock("ehcleanup", CGF.CurFn)), - PreviousInvokeDest(CGF.getInvokeDest()) { - llvm::BasicBlock *TerminateHandler = CGF.getTerminateHandler(); - CGF.Builder.SetInsertPoint(CleanupHandler); - CGF.setInvokeDest(TerminateHandler); - } - ~EHCleanupBlock(); + // A struct holding information about a finally block's IR + // generation. For now, doesn't actually hold anything. + struct FinallyInfo { }; - /// PopCleanupBlock - Will pop the cleanup entry on the stack, process all - /// branch fixups and return a block info struct with the switch block and end - /// block. This will also reset the invoke handler to the previous value - /// from when the cleanup block was created. - CleanupBlockInfo PopCleanupBlock(); - - /// DelayedCleanupBlock - RAII object that will create a cleanup block and set - /// the insert point to that block. When destructed, it sets the insert point - /// to the previous block and pushes a new cleanup entry on the stack. - class DelayedCleanupBlock { - CodeGenFunction& CGF; - llvm::BasicBlock *CurBB; - llvm::BasicBlock *CleanupEntryBB; - llvm::BasicBlock *CleanupExitBB; - llvm::BasicBlock *CurInvokeDest; - bool EHOnly; + FinallyInfo EnterFinallyBlock(const Stmt *Stmt, + llvm::Constant *BeginCatchFn, + llvm::Constant *EndCatchFn, + llvm::Constant *RethrowFn); + void ExitFinallyBlock(FinallyInfo &FinallyInfo); + + enum CleanupKind { NormalAndEHCleanup, EHCleanup, NormalCleanup }; + + /// PushDestructorCleanup - Push a cleanup to call the + /// complete-object destructor of an object of the given type at the + /// given address. Does nothing if T is not a C++ class type with a + /// non-trivial destructor. + void PushDestructorCleanup(QualType T, llvm::Value *Addr); + + /// PopCleanupBlock - Will pop the cleanup entry on the stack and + /// process all branch fixups. + void PopCleanupBlock(); + + /// CleanupBlock - RAII object that will create a cleanup block and + /// set the insert point to that block. When destructed, it sets the + /// insert point to the previous block and pushes a new cleanup + /// entry on the stack. + class CleanupBlock { + CodeGenFunction &CGF; + CGBuilderTy::InsertPoint SavedIP; + llvm::BasicBlock *NormalCleanupEntryBB; + llvm::BasicBlock *NormalCleanupExitBB; + llvm::BasicBlock *EHCleanupEntryBB; public: - DelayedCleanupBlock(CodeGenFunction &cgf, bool ehonly = false) - : CGF(cgf), CurBB(CGF.Builder.GetInsertBlock()), - CleanupEntryBB(CGF.createBasicBlock("cleanup")), - CleanupExitBB(0), - CurInvokeDest(CGF.getInvokeDest()), - EHOnly(ehonly) { - CGF.Builder.SetInsertPoint(CleanupEntryBB); - } + CleanupBlock(CodeGenFunction &CGF, CleanupKind Kind); - llvm::BasicBlock *getCleanupExitBlock() { - if (!CleanupExitBB) - CleanupExitBB = CGF.createBasicBlock("cleanup.exit"); - return CleanupExitBB; - } + /// If we're currently writing a normal cleanup, tie that off and + /// start writing an EH cleanup. + void beginEHCleanup(); - ~DelayedCleanupBlock() { - CGF.PushCleanupBlock(CleanupEntryBB, CleanupExitBB, CurInvokeDest, - EHOnly); - // FIXME: This is silly, move this into the builder. - if (CurBB) - CGF.Builder.SetInsertPoint(CurBB); - else - CGF.Builder.ClearInsertionPoint(); - } + ~CleanupBlock(); }; - /// \brief Enters a new scope for capturing cleanups, all of which will be - /// executed once the scope is exited. - class CleanupScope { + /// \brief Enters a new scope for capturing cleanups, all of which + /// will be executed once the scope is exited. + class RunCleanupsScope { CodeGenFunction& CGF; - size_t CleanupStackDepth; + EHScopeStack::stable_iterator CleanupStackDepth; bool OldDidCallStackSave; bool PerformCleanup; - CleanupScope(const CleanupScope &); // DO NOT IMPLEMENT - CleanupScope &operator=(const CleanupScope &); // DO NOT IMPLEMENT + RunCleanupsScope(const RunCleanupsScope &); // DO NOT IMPLEMENT + RunCleanupsScope &operator=(const RunCleanupsScope &); // DO NOT IMPLEMENT public: /// \brief Enter a new cleanup scope. - explicit CleanupScope(CodeGenFunction &CGF) + explicit RunCleanupsScope(CodeGenFunction &CGF) : CGF(CGF), PerformCleanup(true) { - CleanupStackDepth = CGF.CleanupEntries.size(); + CleanupStackDepth = CGF.EHStack.stable_begin(); OldDidCallStackSave = CGF.DidCallStackSave; } /// \brief Exit this cleanup scope, emitting any accumulated /// cleanups. - ~CleanupScope() { + ~RunCleanupsScope() { if (PerformCleanup) { CGF.DidCallStackSave = OldDidCallStackSave; - CGF.EmitCleanupBlocks(CleanupStackDepth); + CGF.PopCleanupBlocks(CleanupStackDepth); } } /// \brief Determine whether this scope requires any cleanups. bool requiresCleanups() const { - return CGF.CleanupEntries.size() > CleanupStackDepth; + return CGF.EHStack.stable_begin() != CleanupStackDepth; } /// \brief Force the emission of cleanups now, instead of waiting @@ -255,42 +447,39 @@ public: void ForceCleanup() { assert(PerformCleanup && "Already forced cleanup"); CGF.DidCallStackSave = OldDidCallStackSave; - CGF.EmitCleanupBlocks(CleanupStackDepth); + CGF.PopCleanupBlocks(CleanupStackDepth); PerformCleanup = false; } }; - /// CXXTemporariesCleanupScope - Enters a new scope for catching live - /// temporaries, all of which will be popped once the scope is exited. - class CXXTemporariesCleanupScope { - CodeGenFunction &CGF; - size_t NumLiveTemporaries; - - // DO NOT IMPLEMENT - CXXTemporariesCleanupScope(const CXXTemporariesCleanupScope &); - CXXTemporariesCleanupScope &operator=(const CXXTemporariesCleanupScope &); - - public: - explicit CXXTemporariesCleanupScope(CodeGenFunction &CGF) - : CGF(CGF), NumLiveTemporaries(CGF.LiveTemporaries.size()) { } - - ~CXXTemporariesCleanupScope() { - while (CGF.LiveTemporaries.size() > NumLiveTemporaries) - CGF.PopCXXTemporary(); - } - }; + /// PopCleanupBlocks - Takes the old cleanup stack size and emits + /// the cleanup blocks that have been added. + void PopCleanupBlocks(EHScopeStack::stable_iterator OldCleanupStackSize); - /// EmitCleanupBlocks - Takes the old cleanup stack size and emits the cleanup - /// blocks that have been added. - void EmitCleanupBlocks(size_t OldCleanupStackSize); + /// The given basic block lies in the current EH scope, but may be a + /// target of a potentially scope-crossing jump; get a stable handle + /// to which we can perform this jump later. + JumpDest getJumpDestInCurrentScope(llvm::BasicBlock *Target) const { + return JumpDest(Target, EHStack.stable_begin()); + } - /// EmitBranchThroughCleanup - Emit a branch from the current insert block - /// through the cleanup handling code (if any) and then on to \arg Dest. - /// - /// FIXME: Maybe this should really be in EmitBranch? Don't we always want - /// this behavior for branches? - void EmitBranchThroughCleanup(llvm::BasicBlock *Dest); + /// The given basic block lies in the current EH scope, but may be a + /// target of a potentially scope-crossing jump; get a stable handle + /// to which we can perform this jump later. + JumpDest getJumpDestInCurrentScope(const char *Name = 0) { + return JumpDest(createBasicBlock(Name), EHStack.stable_begin()); + } + + /// EmitBranchThroughCleanup - Emit a branch from the current insert + /// block through the normal cleanup handling code (if any) and then + /// on to \arg Dest. + void EmitBranchThroughCleanup(JumpDest Dest); + + /// EmitBranchThroughEHCleanup - Emit a branch from the current + /// insert block through the EH cleanup handling code (if any) and + /// then on to \arg Dest. + void EmitBranchThroughEHCleanup(JumpDest Dest); /// BeginConditionalBranch - Should be called before a conditional part of an /// expression is emitted. For example, before the RHS of the expression below @@ -327,16 +516,16 @@ private: llvm::DenseMap<const Decl*, llvm::Value*> LocalDeclMap; /// LabelMap - This keeps track of the LLVM basic block for each C label. - llvm::DenseMap<const LabelStmt*, llvm::BasicBlock*> LabelMap; + llvm::DenseMap<const LabelStmt*, JumpDest> LabelMap; // BreakContinueStack - This keeps track of where break and continue // statements should jump to. struct BreakContinue { - BreakContinue(llvm::BasicBlock *bb, llvm::BasicBlock *cb) - : BreakBlock(bb), ContinueBlock(cb) {} + BreakContinue(JumpDest Break, JumpDest Continue) + : BreakBlock(Break), ContinueBlock(Continue) {} - llvm::BasicBlock *BreakBlock; - llvm::BasicBlock *ContinueBlock; + JumpDest BreakBlock; + JumpDest ContinueBlock; }; llvm::SmallVector<BreakContinue, 8> BreakContinueStack; @@ -364,44 +553,9 @@ private: /// calling llvm.stacksave for multiple VLAs in the same scope. bool DidCallStackSave; - struct CleanupEntry { - /// CleanupEntryBlock - The block of code that does the actual cleanup. - llvm::BasicBlock *CleanupEntryBlock; - - /// CleanupExitBlock - The cleanup exit block. - llvm::BasicBlock *CleanupExitBlock; - - /// Blocks - Basic blocks that were emitted in the current cleanup scope. - std::vector<llvm::BasicBlock *> Blocks; - - /// BranchFixups - Branch instructions to basic blocks that haven't been - /// inserted into the current function yet. - std::vector<llvm::BranchInst *> BranchFixups; - - /// PreviousInvokeDest - The invoke handler from the start of the cleanup - /// region. - llvm::BasicBlock *PreviousInvokeDest; - - /// EHOnly - Perform this only on the exceptional edge, not the main edge. - bool EHOnly; - - explicit CleanupEntry(llvm::BasicBlock *CleanupEntryBlock, - llvm::BasicBlock *CleanupExitBlock, - llvm::BasicBlock *PreviousInvokeDest, - bool ehonly) - : CleanupEntryBlock(CleanupEntryBlock), - CleanupExitBlock(CleanupExitBlock), - PreviousInvokeDest(PreviousInvokeDest), - EHOnly(ehonly) {} - }; - - /// CleanupEntries - Stack of cleanup entries. - llvm::SmallVector<CleanupEntry, 8> CleanupEntries; - - typedef llvm::DenseMap<llvm::BasicBlock*, size_t> BlockScopeMap; - - /// BlockScopes - Map of which "cleanup scope" scope basic blocks have. - BlockScopeMap BlockScopes; + /// A block containing a single 'unreachable' instruction. Created + /// lazily by getUnreachableBlock(). + llvm::BasicBlock *UnreachableBlock; /// CXXThisDecl - When generating code for a C++ member function, /// this will hold the implicit 'this' declaration. @@ -414,31 +568,6 @@ private: ImplicitParamDecl *CXXVTTDecl; llvm::Value *CXXVTTValue; - /// CXXLiveTemporaryInfo - Holds information about a live C++ temporary. - struct CXXLiveTemporaryInfo { - /// Temporary - The live temporary. - const CXXTemporary *Temporary; - - /// ThisPtr - The pointer to the temporary. - llvm::Value *ThisPtr; - - /// DtorBlock - The destructor block. - llvm::BasicBlock *DtorBlock; - - /// CondPtr - If this is a conditional temporary, this is the pointer to the - /// condition variable that states whether the destructor should be called - /// or not. - llvm::Value *CondPtr; - - CXXLiveTemporaryInfo(const CXXTemporary *temporary, - llvm::Value *thisptr, llvm::BasicBlock *dtorblock, - llvm::Value *condptr) - : Temporary(temporary), ThisPtr(thisptr), DtorBlock(dtorblock), - CondPtr(condptr) { } - }; - - llvm::SmallVector<CXXLiveTemporaryInfo, 4> LiveTemporaries; - /// ConditionalBranchLevel - Contains the nesting level of the current /// conditional branch. This is used so that we know if a temporary should be /// destroyed conditionally. @@ -454,6 +583,7 @@ private: /// number that holds the value. unsigned getByRefValueLLVMField(const ValueDecl *VD) const; + llvm::BasicBlock *TerminateLandingPad; llvm::BasicBlock *TerminateHandler; llvm::BasicBlock *TrapBB; @@ -463,8 +593,22 @@ public: ASTContext &getContext() const; CGDebugInfo *getDebugInfo() { return DebugInfo; } - llvm::BasicBlock *getInvokeDest() { return InvokeDest; } - void setInvokeDest(llvm::BasicBlock *B) { InvokeDest = B; } + /// Returns a pointer to the function's exception object slot, which + /// is assigned in every landing pad. + llvm::Value *getExceptionSlot(); + + llvm::BasicBlock *getUnreachableBlock() { + if (!UnreachableBlock) { + UnreachableBlock = createBasicBlock("unreachable"); + new llvm::UnreachableInst(getLLVMContext(), UnreachableBlock); + } + return UnreachableBlock; + } + + llvm::BasicBlock *getInvokeDest() { + if (!EHStack.requiresLandingPad()) return 0; + return getInvokeDestImpl(); + } llvm::LLVMContext &getLLVMContext() { return VMContext; } @@ -594,7 +738,12 @@ public: /// EmitEndEHSpec - Emit the end of the exception spec. void EmitEndEHSpec(const Decl *D); - /// getTerminateHandler - Return a handler that just calls terminate. + /// getTerminateLandingPad - Return a landing pad that just calls terminate. + llvm::BasicBlock *getTerminateLandingPad(); + + /// getTerminateHandler - Return a handler (not a landing pad, just + /// a catch handler) that just calls terminate. This is used when + /// a terminate scope encloses a try. llvm::BasicBlock *getTerminateHandler(); const llvm::Type *ConvertTypeForMem(QualType T); @@ -627,7 +776,7 @@ public: /// getBasicBlockForLabel - Return the LLVM basicblock that the specified /// label maps to. - llvm::BasicBlock *getBasicBlockForLabel(const LabelStmt *S); + JumpDest getJumpDestForLabel(const LabelStmt *S); /// SimplifyForwardingBlocks - If the given basic block is only a branch to /// another basic block, simplify it. This assumes that no other code could @@ -855,8 +1004,7 @@ public: void EmitNewArrayInitializer(const CXXNewExpr *E, llvm::Value *NewPtr, llvm::Value *NumElements); - void PushCXXTemporary(const CXXTemporary *Temporary, llvm::Value *Ptr); - void PopCXXTemporary(); + void EmitCXXTemporary(const CXXTemporary *Temporary, llvm::Value *Ptr); llvm::Value *EmitCXXNewExpr(const CXXNewExpr *E); void EmitCXXDeleteExpr(const CXXDeleteExpr *E); @@ -887,10 +1035,13 @@ public: /// This function can be called with a null (unreachable) insert point. void EmitBlockVarDecl(const VarDecl &D); + typedef void SpecialInitFn(CodeGenFunction &Init, const VarDecl &D, + llvm::Value *Address); + /// EmitLocalBlockVarDecl - Emit a local block variable declaration. /// /// This function can be called with a null (unreachable) insert point. - void EmitLocalBlockVarDecl(const VarDecl &D); + void EmitLocalBlockVarDecl(const VarDecl &D, SpecialInitFn *SpecialInit = 0); void EmitStaticBlockVarDecl(const VarDecl &D, llvm::GlobalValue::LinkageTypes Linkage); @@ -951,11 +1102,7 @@ public: void EmitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt &S); llvm::Constant *getUnwindResumeOrRethrowFn(); - struct CXXTryStmtInfo { - llvm::BasicBlock *SavedLandingPad; - llvm::BasicBlock *HandlerBlock; - llvm::BasicBlock *FinallyBlock; - }; + struct CXXTryStmtInfo {}; CXXTryStmtInfo EnterCXXTryStmt(const CXXTryStmt &S); void ExitCXXTryStmt(const CXXTryStmt &S, CXXTryStmtInfo Info); @@ -1128,6 +1275,11 @@ public: RValue EmitCallExpr(const CallExpr *E, ReturnValueSlot ReturnValue = ReturnValueSlot()); + llvm::CallSite EmitCallOrInvoke(llvm::Value *Callee, + llvm::Value * const *ArgBegin, + llvm::Value * const *ArgEnd, + const llvm::Twine &Name = ""); + llvm::Value *BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *This, const llvm::Type *Ty); llvm::Value *BuildVirtualCall(const CXXDestructorDecl *DD, CXXDtorType Type, @@ -1331,7 +1483,6 @@ public: RValue EmitDelegateCallArg(const VarDecl *Param); private: - void EmitReturnOfRValue(RValue RV, QualType Ty); /// ExpandTypeFromArgs - Reconstruct a structure of type \arg Ty @@ -1354,13 +1505,6 @@ private: const TargetInfo::ConstraintInfo &Info, const Expr *InputExpr, std::string &ConstraintStr); - /// EmitCleanupBlock - emits a single cleanup block. - void EmitCleanupBlock(); - - /// AddBranchFixup - adds a branch instruction to the list of fixups for the - /// current cleanup scope. - void AddBranchFixup(llvm::BranchInst *BI); - /// EmitCallArgs - Emit call arguments for a function. /// The CallArgTypeInfo parameter is used for iterating over the known /// argument types of the function being called. |