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