mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-04 00:55:49 +03:00
Move temporaries-related state from ToElemVisitor to FuncGen.
This commit is contained in:
parent
2304b52acb
commit
cf52b53888
5 changed files with 85 additions and 98 deletions
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
91
gen/toir.cpp
91
gen/toir.cpp
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue