Move temporaries-related state from ToElemVisitor to FuncGen.

This commit is contained in:
Martin 2015-07-14 22:38:00 +02:00
parent 2304b52acb
commit cf52b53888
5 changed files with 85 additions and 98 deletions

View file

@ -21,7 +21,6 @@
#include "ir/iraggr.h" #include "ir/iraggr.h"
#include "ir/irvar.h" #include "ir/irvar.h"
#include "gen/dibuilder.h" #include "gen/dibuilder.h"
#include "gen/llvmhelpers.h"
#include <deque> #include <deque>
#include <list> #include <list>
#include <set> #include <set>
@ -214,11 +213,11 @@ llvm::CallSite IRState::CreateCallOrInvoke(LLValue* Callee, const T &args, const
FuncGen& funcGen = *func()->gen; FuncGen& funcGen = *func()->gen;
LLFunction* fn = llvm::dyn_cast<LLFunction>(Callee); LLFunction* fn = llvm::dyn_cast<LLFunction>(Callee);
const bool haveTemporaries = haveTemporariesToDestruct(); const bool hasTemporaries = funcGen.hasTemporariesToDestruct();
// intrinsics don't support invoking and 'nounwind' functions don't need it. // intrinsics don't support invoking and 'nounwind' functions don't need it.
const bool doesNotThrow = (fn && (fn->isIntrinsic() || fn->doesNotThrow())); const bool doesNotThrow = (fn && (fn->isIntrinsic() || fn->doesNotThrow()));
if (doesNotThrow || (!haveTemporaries && funcGen.landingPad == NULL)) if (doesNotThrow || (!hasTemporaries && funcGen.landingPad == NULL))
{ {
llvm::CallInst* call = ir->CreateCall(Callee, args, Name); llvm::CallInst* call = ir->CreateCall(Callee, args, Name);
if (fn) if (fn)
@ -226,16 +225,16 @@ llvm::CallSite IRState::CreateCallOrInvoke(LLValue* Callee, const T &args, const
return call; return call;
} }
if (haveTemporaries) if (hasTemporaries)
prepareToDestructAllTemporariesOnThrow(); funcGen.prepareToDestructAllTemporariesOnThrow(this);
llvm::BasicBlock* oldend = scopeend(); llvm::BasicBlock* oldend = scopeend();
llvm::BasicBlock* postinvoke = llvm::BasicBlock::Create(gIR->context(), "postinvoke", topfunc(), oldend); llvm::BasicBlock* postinvoke = llvm::BasicBlock::Create(context(), "postinvoke", topfunc(), oldend);
llvm::InvokeInst* invoke = ir->CreateInvoke(Callee, postinvoke, funcGen.landingPad, args, Name); llvm::InvokeInst* invoke = ir->CreateInvoke(Callee, postinvoke, funcGen.landingPad, args, Name);
if (fn) if (fn)
invoke->setAttributes(fn->getAttributes()); invoke->setAttributes(fn->getAttributes());
if (haveTemporaries) if (hasTemporaries)
funcGen.landingPadInfo.pop(); funcGen.landingPadInfo.pop();
scope() = IRScope(postinvoke, oldend); scope() = IRScope(postinvoke, oldend);

View file

@ -239,7 +239,4 @@ DValue *toElem(Expression *e, bool tryGetLvalue);
DValue *toElemDtor(Expression *e); DValue *toElemDtor(Expression *e);
LLConstant *toConstElem(Expression *e, IRState *p); LLConstant *toConstElem(Expression *e, IRState *p);
bool haveTemporariesToDestruct();
void prepareToDestructAllTemporariesOnThrow();
#endif #endif

View file

@ -265,67 +265,16 @@ DValue* toElem(Expression* e, bool tryGetLvalue)
class ToElemVisitor : public Visitor class ToElemVisitor : public Visitor
{ {
// stack of declared temporaries which have yet to be destructed
// static because toElem() calls are re-entrant
static VarDeclarations temporariesWithDtor;
static Array<ToElemVisitor*> visitors;
IRState *p; IRState *p;
DValue *result; DValue *result;
//DValue *lvalue;
//////////////////////////////////////////////////////////////////////////////////////////
static void destructTemporaries(int numToKeep)
{
if (temporariesWithDtor.empty())
return;
// pop one temporary after the other from the temporariesWithDtor stack
// and evaluate its destructor expression
// so when an exception occurs in a destructor expression, all older
// temporaries (excl. the one which threw in its destructor) will be
// destructed in a landing pad
for (int i = temporariesWithDtor.size() - 1; i >= numToKeep; --i)
{
VarDeclaration* vd = temporariesWithDtor.pop();
toElem(vd->edtor);
}
}
//////////////////////////////////////////////////////////////////////////////////////////
public: public:
ToElemVisitor(IRState *p_) : p(p_), result(NULL) ToElemVisitor(IRState *p_) : p(p_), result(NULL) { p->func()->gen->pushToElemScope(); }
{ ~ToElemVisitor() { p->func()->gen->popToElemScope(); }
visitors.push(this);
}
~ToElemVisitor()
{
if (visitors.size() == 1) // outer-most toElem() call only
destructTemporaries(0);
visitors.pop();
}
DValue *getResult() { return result; } DValue *getResult() { return result; }
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
static bool hasTemporariesToDestruct() { return !temporariesWithDtor.empty(); }
static void destructAllTemporariesAndRestoreStack()
{
if (temporariesWithDtor.empty())
return;
VarDeclarations original = temporariesWithDtor;
destructTemporaries(0);
temporariesWithDtor = original;
}
//////////////////////////////////////////////////////////////////////////////////////////
// Import all functions from class Visitor // Import all functions from class Visitor
using Visitor::visit; using Visitor::visit;
@ -345,7 +294,7 @@ public:
{ {
VarDeclaration* vd = varValue->var; VarDeclaration* vd = varValue->var;
if (!vd->isDataseg() && vd->edtor && !vd->noscope) if (!vd->isDataseg() && vd->edtor && !vd->noscope)
temporariesWithDtor.push(vd); p->func()->gen->pushTemporaryToDestruct(vd);
} }
} }
} }
@ -3183,9 +3132,6 @@ public:
STUB(PowAssignExp) STUB(PowAssignExp)
}; };
VarDeclarations ToElemVisitor::temporariesWithDtor;
Array<ToElemVisitor*> ToElemVisitor::visitors;
////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////
DValue *toElem(Expression *e) DValue *toElem(Expression *e)
@ -3200,37 +3146,6 @@ DValue *toElemDtor(Expression *e)
return toElem(e); return toElem(e);
} }
bool haveTemporariesToDestruct()
{
return ToElemVisitor::hasTemporariesToDestruct();
}
void prepareToDestructAllTemporariesOnThrow()
{
if (!haveTemporariesToDestruct())
return;
class CallDestructors : public IRLandingPadCatchFinallyInfo
{
public:
void toIR(LLValue* /*eh_ptr*/ = NULL)
{
ToElemVisitor::destructAllTemporariesAndRestoreStack();
}
};
CallDestructors* callDestructors = new CallDestructors(); // leaks
// create landing pad
llvm::BasicBlock* landingpadbb = llvm::BasicBlock::Create(gIR->context(),
"temporariesLandingPad", gIR->topfunc(), gIR->scopeend());
// set up the landing pad
IRLandingPad& pad = gIR->func()->gen->landingPadInfo;
pad.addFinally(callDestructors);
pad.push(landingpadbb);
}
// FIXME: Implement & place in right module // FIXME: Implement & place in right module
Symbol *toModuleAssert(Module *m) Symbol *toModuleAssert(Module *m)
{ {

View file

@ -8,6 +8,8 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "gen/llvm.h" #include "gen/llvm.h"
#include "gen/llvmhelpers.h"
#include "gen/irstate.h"
#include "gen/tollvm.h" #include "gen/tollvm.h"
#include "ir/irdsymbol.h" #include "ir/irdsymbol.h"
#include "ir/irfunction.h" #include "ir/irfunction.h"
@ -17,6 +19,7 @@ FuncGen::FuncGen()
{ {
landingPad = NULL; landingPad = NULL;
nextUnique.push(0); nextUnique.push(0);
toElemScopeCounter = 0;
} }
std::string FuncGen::getScopedLabelName(const char* ident) std::string FuncGen::getScopedLabelName(const char* ident)
@ -44,6 +47,64 @@ void FuncGen::popLabelScope()
nextUnique.pop(); nextUnique.pop();
} }
void FuncGen::pushToElemScope() { ++toElemScopeCounter; }
void FuncGen::popToElemScope()
{
assert(toElemScopeCounter > 0);
if (toElemScopeCounter == 1) // popping outer-most toElem() scope?
destructAllTemporaries();
--toElemScopeCounter;
}
void FuncGen::pushTemporaryToDestruct(VarDeclaration* vd) { temporariesToDestruct.push(vd); }
bool FuncGen::hasTemporariesToDestruct() { return !temporariesToDestruct.empty(); }
void FuncGen::destructAllTemporaries()
{
// pop one temporary after the other from the temporariesToDestruct stack
// and evaluate its destructor expression
// so when an exception occurs in a destructor expression, all older
// temporaries (excl. the one which threw in its destructor) will be
// destructed in a landing pad
while (!temporariesToDestruct.empty())
{
VarDeclaration* vd = temporariesToDestruct.pop();
toElem(vd->edtor);
}
}
void FuncGen::destructAllTemporariesAndRestoreStack()
{
VarDeclarations original = temporariesToDestruct;
destructAllTemporaries();
temporariesToDestruct = original;
}
void FuncGen::prepareToDestructAllTemporariesOnThrow(IRState* irState)
{
class CallDestructors : public IRLandingPadCatchFinallyInfo
{
public:
FuncGen& funcGen;
CallDestructors(FuncGen& funcGen) : funcGen(funcGen) {}
void toIR(LLValue*)
{
funcGen.destructAllTemporariesAndRestoreStack();
}
};
CallDestructors* callDestructors = new CallDestructors(*this); // will leak
// create landing pad
llvm::BasicBlock* landingpadbb = llvm::BasicBlock::Create(irState->context(),
"temporariesLandingPad", irState->topfunc(), irState->scopeend());
// set up the landing pad
landingPadInfo.addFinally(callDestructors);
landingPadInfo.push(landingpadbb);
}
IrFunction::IrFunction(FuncDeclaration* fd) IrFunction::IrFunction(FuncDeclaration* fd)
{ {
decl = fd; decl = fd;

View file

@ -27,6 +27,7 @@
class Statement; class Statement;
struct EnclosingTryFinally; struct EnclosingTryFinally;
struct IRState;
// scope statements that can be target of jumps // scope statements that can be target of jumps
// includes loops, switch, case, labels // includes loops, switch, case, labels
@ -81,6 +82,17 @@ struct FuncGen
IRLandingPad landingPadInfo; IRLandingPad landingPadInfo;
llvm::BasicBlock* landingPad; llvm::BasicBlock* landingPad;
void pushToElemScope();
void popToElemScope();
void pushTemporaryToDestruct(VarDeclaration* vd);
bool hasTemporariesToDestruct();
void destructAllTemporaries();
void destructAllTemporariesAndRestoreStack();
// pushes a landing pad which needs to be popped after the
// following invoke instruction
void prepareToDestructAllTemporariesOnThrow(IRState* irState);
private: private:
// prefix for labels and gotos // prefix for labels and gotos
// used for allowing labels to be emitted twice // used for allowing labels to be emitted twice
@ -88,6 +100,9 @@ private:
// next unique id stack // next unique id stack
std::stack<int> nextUnique; std::stack<int> nextUnique;
int toElemScopeCounter;
VarDeclarations temporariesToDestruct;
}; };
// represents a function // represents a function