diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/CodeGen/CGTemporaries.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/CodeGen/CGTemporaries.cpp | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGTemporaries.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGTemporaries.cpp new file mode 100644 index 0000000..a8f0467 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGTemporaries.cpp @@ -0,0 +1,160 @@ +//===--- CGTemporaries.cpp - Emit LLVM Code for C++ temporaries -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This contains code dealing with C++ code generation of temporaries +// +//===----------------------------------------------------------------------===// + +#include "CodeGenFunction.h" +using namespace clang; +using namespace CodeGen; + +void CodeGenFunction::PushCXXTemporary(const CXXTemporary *Temporary, + llvm::Value *Ptr) { + assert((LiveTemporaries.empty() || + LiveTemporaries.back().ThisPtr != Ptr || + ConditionalBranchLevel) && + "Pushed the same temporary twice; AST is likely wrong"); + llvm::BasicBlock *DtorBlock = createBasicBlock("temp.dtor"); + + llvm::AllocaInst *CondPtr = 0; + + // Check if temporaries need to be conditional. If so, we'll create a + // condition boolean, initialize it to 0 and + if (ConditionalBranchLevel != 0) { + CondPtr = CreateTempAlloca(llvm::Type::getInt1Ty(VMContext), "cond"); + + // Initialize it to false. This initialization takes place right after + // the alloca insert point. + InitTempAlloca(CondPtr, llvm::ConstantInt::getFalse(VMContext)); + + // Now set it to true. + Builder.CreateStore(llvm::ConstantInt::getTrue(VMContext), CondPtr); + } + + LiveTemporaries.push_back(CXXLiveTemporaryInfo(Temporary, Ptr, DtorBlock, + CondPtr)); + + PushCleanupBlock(DtorBlock); + + if (Exceptions) { + const CXXLiveTemporaryInfo& Info = LiveTemporaries.back(); + llvm::BasicBlock *CondEnd = 0; + + EHCleanupBlock Cleanup(*this); + + // If this is a conditional temporary, we need to check the condition + // boolean and only call the destructor if it's true. + if (Info.CondPtr) { + llvm::BasicBlock *CondBlock = createBasicBlock("cond.dtor.call"); + CondEnd = createBasicBlock("cond.dtor.end"); + + llvm::Value *Cond = Builder.CreateLoad(Info.CondPtr); + Builder.CreateCondBr(Cond, CondBlock, CondEnd); + EmitBlock(CondBlock); + } + + EmitCXXDestructorCall(Info.Temporary->getDestructor(), + Dtor_Complete, /*ForVirtualBase=*/false, + Info.ThisPtr); + + if (CondEnd) { + // Reset the condition. to false. + Builder.CreateStore(llvm::ConstantInt::getFalse(VMContext), Info.CondPtr); + EmitBlock(CondEnd); + } + } +} + +void CodeGenFunction::PopCXXTemporary() { + const CXXLiveTemporaryInfo& Info = LiveTemporaries.back(); + + CleanupBlockInfo CleanupInfo = PopCleanupBlock(); + assert(CleanupInfo.CleanupBlock == Info.DtorBlock && + "Cleanup block mismatch!"); + assert(!CleanupInfo.SwitchBlock && + "Should not have a switch block for temporary cleanup!"); + assert(!CleanupInfo.EndBlock && + "Should not have an end block for temporary cleanup!"); + + llvm::BasicBlock *CurBB = Builder.GetInsertBlock(); + if (CurBB && !CurBB->getTerminator() && + Info.DtorBlock->getNumUses() == 0) { + CurBB->getInstList().splice(CurBB->end(), Info.DtorBlock->getInstList()); + delete Info.DtorBlock; + } else + EmitBlock(Info.DtorBlock); + + llvm::BasicBlock *CondEnd = 0; + + // If this is a conditional temporary, we need to check the condition + // boolean and only call the destructor if it's true. + if (Info.CondPtr) { + llvm::BasicBlock *CondBlock = createBasicBlock("cond.dtor.call"); + CondEnd = createBasicBlock("cond.dtor.end"); + + llvm::Value *Cond = Builder.CreateLoad(Info.CondPtr); + Builder.CreateCondBr(Cond, CondBlock, CondEnd); + EmitBlock(CondBlock); + } + + EmitCXXDestructorCall(Info.Temporary->getDestructor(), + Dtor_Complete, /*ForVirtualBase=*/false, Info.ThisPtr); + + if (CondEnd) { + // Reset the condition. to false. + Builder.CreateStore(llvm::ConstantInt::getFalse(VMContext), Info.CondPtr); + EmitBlock(CondEnd); + } + + LiveTemporaries.pop_back(); +} + +RValue +CodeGenFunction::EmitCXXExprWithTemporaries(const CXXExprWithTemporaries *E, + llvm::Value *AggLoc, + bool IsAggLocVolatile, + bool IsInitializer) { + // Keep track of the current cleanup stack depth. + size_t CleanupStackDepth = CleanupEntries.size(); + (void) CleanupStackDepth; + + RValue RV; + + { + CXXTemporariesCleanupScope Scope(*this); + + RV = EmitAnyExpr(E->getSubExpr(), AggLoc, IsAggLocVolatile, + /*IgnoreResult=*/false, IsInitializer); + } + assert(CleanupEntries.size() == CleanupStackDepth && + "Cleanup size mismatch!"); + + return RV; +} + +LValue CodeGenFunction::EmitCXXExprWithTemporariesLValue( + const CXXExprWithTemporaries *E) { + // Keep track of the current cleanup stack depth. + size_t CleanupStackDepth = CleanupEntries.size(); + (void) CleanupStackDepth; + + unsigned OldNumLiveTemporaries = LiveTemporaries.size(); + + LValue LV = EmitLValue(E->getSubExpr()); + + // Pop temporaries. + while (LiveTemporaries.size() > OldNumLiveTemporaries) + PopCXXTemporary(); + + assert(CleanupEntries.size() == CleanupStackDepth && + "Cleanup size mismatch!"); + + return LV; +} |