|  | //===--- 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::Value *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. | 
|  | llvm::StoreInst *SI = | 
|  | new llvm::StoreInst(llvm::ConstantInt::getFalse(VMContext), CondPtr); | 
|  | llvm::BasicBlock *Block = AllocaInsertPt->getParent(); | 
|  | Block->getInstList().insertAfter((llvm::Instruction *)AllocaInsertPt, SI); | 
|  |  | 
|  | // 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, 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, 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; | 
|  |  | 
|  | unsigned OldNumLiveTemporaries = LiveTemporaries.size(); | 
|  |  | 
|  | RValue RV = EmitAnyExpr(E->getSubExpr(), AggLoc, IsAggLocVolatile, | 
|  | /*IgnoreResult=*/false, IsInitializer); | 
|  |  | 
|  | // Pop temporaries. | 
|  | while (LiveTemporaries.size() > OldNumLiveTemporaries) | 
|  | PopCXXTemporary(); | 
|  |  | 
|  | 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; | 
|  | } |