| //===--- 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; |
| } |