Reorganize EnclosingHandlers to require less changes to the frontend and allow us to

implement the synchronized storage class for functions.
This commit is contained in:
Christian Kamm
2009-03-24 21:18:18 +01:00
parent a0d93e699a
commit 671c7791e3
12 changed files with 217 additions and 228 deletions

View File

@@ -444,8 +444,8 @@ assert(0);
AsmBlockStatement::AsmBlockStatement(Loc loc, Statements* s)
: CompoundStatement(loc, s)
{
enclosinghandler = NULL;
tf = NULL;
enclosingFinally = NULL;
enclosingScopeExit = NULL;
abiret = NULL;
}
@@ -772,7 +772,7 @@ void AsmBlockStatement::toIR(IRState* p)
sw->addCase(llvm::ConstantInt::get(llvm::IntegerType::get(32), it->second), casebb);
p->scope() = IRScope(casebb,bb);
DtoGoto(&loc, it->first, enclosinghandler, tf);
DtoGoto(loc, it->first);
}
p->scope() = IRScope(bb,oldend);
@@ -803,8 +803,8 @@ Statement *AsmBlockStatement::syntaxCopy()
// necessary for in-asm branches
Statement *AsmBlockStatement::semantic(Scope *sc)
{
enclosinghandler = sc->tfOfTry;
tf = sc->tf;
enclosingFinally = sc->enclosingFinally;
enclosingScopeExit = sc->enclosingScopeExit;
return CompoundStatement::semantic(sc);
}

View File

@@ -34,18 +34,16 @@ IRScope::IRScope(llvm::BasicBlock* b, llvm::BasicBlock* e)
}
//////////////////////////////////////////////////////////////////////////////////////////
IRLoopScope::IRLoopScope()
IRTargetScope::IRTargetScope()
{
}
IRLoopScope::IRLoopScope(Statement* s, EnclosingHandler* enclosinghandler, llvm::BasicBlock* b, llvm::BasicBlock* e, bool isSwitch)
IRTargetScope::IRTargetScope(Statement* s, EnclosingHandler* enclosinghandler, llvm::BasicBlock* continueTarget, llvm::BasicBlock* breakTarget)
{
begin = b;
end = e;
//builder.SetInsertPoint(b);
this->s = s;
this->enclosinghandler = enclosinghandler;
this->isSwitch = isSwitch;
this->breakTarget = breakTarget;
this->continueTarget = continueTarget;
}
//////////////////////////////////////////////////////////////////////////////////////////

View File

@@ -51,19 +51,21 @@ struct IRScope
IRScope(llvm::BasicBlock* b, llvm::BasicBlock* e);
};
// scope for loops
struct IRLoopScope : IRScope
// scope statements that can be target of jumps
// includes loops, switch, case, labels
struct IRTargetScope
{
// generating statement
Statement* s;
// the try of a TryFinally that encloses the loop
EnclosingHandler* enclosinghandler;
// if it is a switch, we are a possible target for break
// but not for continue
bool isSwitch;
llvm::BasicBlock* breakTarget;
llvm::BasicBlock* continueTarget;
IRLoopScope();
IRLoopScope(Statement* s, EnclosingHandler* enclosinghandler, llvm::BasicBlock* b, llvm::BasicBlock* e, bool isSwitch = false);
IRTargetScope();
IRTargetScope(Statement* s, EnclosingHandler* enclosinghandler, llvm::BasicBlock* continueTarget, llvm::BasicBlock* breakTarget);
};
struct IRBuilderHelper
@@ -158,8 +160,8 @@ struct IRState
llvm::CallSite CreateCallOrInvoke4(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, LLValue* Arg3, LLValue* Arg4, const char* Name="");
// loop blocks
typedef std::vector<IRLoopScope> LoopScopeVec;
LoopScopeVec loopbbs;
typedef std::vector<IRTargetScope> TargetScopeVec;
TargetScopeVec targetScopes;
// this holds the array being indexed or sliced so $ will work
// might be a better way but it works. problem is I only get a

View File

@@ -110,7 +110,7 @@ llvm::AllocaInst* DtoAlloca(const LLType* lltype, LLValue* arraysize, const std:
// ASSERT HELPER
////////////////////////////////////////////////////////////////////////////////////////*/
void DtoAssert(Module* M, Loc* loc, DValue* msg)
void DtoAssert(Module* M, Loc loc, DValue* msg)
{
std::vector<LLValue*> args;
@@ -133,7 +133,7 @@ void DtoAssert(Module* M, Loc* loc, DValue* msg)
args.push_back(DtoLoad(M->ir.irModule->fileName));
// line param
LLConstant* c = DtoConstUint(loc->linnum);
LLConstant* c = DtoConstUint(loc.linnum);
args.push_back(c);
// call
@@ -172,19 +172,19 @@ LabelStatement* DtoLabelStatement(Identifier* ident)
/*////////////////////////////////////////////////////////////////////////////////////////
// GOTO HELPER
////////////////////////////////////////////////////////////////////////////////////////*/
void DtoGoto(Loc* loc, Identifier* target, EnclosingHandler* enclosinghandler, TryFinallyStatement* sourcetf)
void DtoGoto(Loc loc, Identifier* target)
{
assert(!gIR->scopereturned());
LabelStatement* lblstmt = DtoLabelStatement(target);
if(!lblstmt) {
error(*loc, "the label %s does not exist", target->toChars());
error(loc, "the label %s does not exist", target->toChars());
fatal();
}
// if the target label is inside inline asm, error
if(lblstmt->asmLabel) {
error(*loc, "cannot goto to label %s inside an inline asm block", target->toChars());
error(loc, "cannot goto to label %s inside an inline asm block", target->toChars());
fatal();
}
@@ -194,25 +194,16 @@ void DtoGoto(Loc* loc, Identifier* target, EnclosingHandler* enclosinghandler, T
if (targetBB == NULL)
targetBB = llvm::BasicBlock::Create("label_" + labelname, gIR->topfunc());
// find finallys between goto and label
EnclosingHandler* endfinally = enclosinghandler;
while(endfinally != NULL && endfinally != lblstmt->enclosinghandler) {
endfinally = endfinally->getEnclosing();
}
// error if didn't find tf statement of label
if(endfinally != lblstmt->enclosinghandler)
error(*loc, "cannot goto into try block");
// emit code for finallys between goto and label
DtoEnclosingHandlers(loc, lblstmt);
// goto into finally blocks is forbidden by the spec
// though it should not be problematic to implement
// but should work fine
/*
if(lblstmt->tf != sourcetf) {
error(*loc, "spec disallows goto into finally block");
error(loc, "spec disallows goto into finally block");
fatal();
}
// emit code for finallys between goto and label
DtoEnclosingHandlers(enclosinghandler, endfinally);
}*/
llvm::BranchInst::Create(targetBB, gIR->scopebb());
}
@@ -225,16 +216,11 @@ void DtoGoto(Loc* loc, Identifier* target, EnclosingHandler* enclosinghandler, T
void EnclosingSynchro::emitCode(IRState * p)
{
if (s->exp)
DtoLeaveMonitor(s->llsync);
DtoLeaveMonitor(s->exp->toElem(p)->getRVal());
else
DtoLeaveCritical(s->llsync);
}
EnclosingHandler* EnclosingSynchro::getEnclosing()
{
return s->enclosinghandler;
}
////////////////////////////////////////////////////////////////////////////////////////
void EnclosingVolatile::emitCode(IRState * p)
@@ -243,11 +229,6 @@ void EnclosingVolatile::emitCode(IRState * p)
DtoMemoryBarrier(false, false, true, false);
}
EnclosingHandler* EnclosingVolatile::getEnclosing()
{
return v->enclosinghandler;
}
////////////////////////////////////////////////////////////////////////////////////////
void EnclosingTryFinally::emitCode(IRState * p)
@@ -256,34 +237,43 @@ void EnclosingTryFinally::emitCode(IRState * p)
tf->finalbody->toIR(p);
}
EnclosingHandler* EnclosingTryFinally::getEnclosing()
{
return tf->enclosinghandler;
}
////////////////////////////////////////////////////////////////////////////////////////
void DtoEnclosingHandlers(EnclosingHandler* start, EnclosingHandler* end)
void DtoEnclosingHandlers(Loc loc, Statement* target)
{
// verify that end encloses start
EnclosingHandler* endfinally = start;
while(endfinally != NULL && endfinally != end) {
endfinally = endfinally->getEnclosing();
}
assert(endfinally == end);
// labels are a special case: they are not required to enclose the current scope
// for them we use the enclosing scope handler as a reference point
LabelStatement* lblstmt = dynamic_cast<LabelStatement*>(target);
if (lblstmt)
target = lblstmt->enclosingScopeExit;
// figure out up until what handler we need to emit
IRState::TargetScopeVec::reverse_iterator targetit;
for (targetit = gIR->targetScopes.rbegin(); targetit != gIR->targetScopes.rend(); ++targetit) {
if (targetit->s == target) {
break;
}
}
if (target && targetit == gIR->targetScopes.rend()) {
if (lblstmt)
error(loc, "cannot goto into try, volatile or synchronized statement at %s", target->loc.toChars());
else
error(loc, "internal error, cannot find jump path to statement at %s", target->loc.toChars());
return;
}
//
// emit code for finallys between start and end
// emit code for enclosing handlers
//
// since the labelstatements possibly inside are private
// and might already exist push a label scope
gIR->func()->pushUniqueLabelScope("enclosing");
EnclosingHandler* tf = start;
while(tf != end) {
tf->emitCode(gIR);
tf = tf->getEnclosing();
IRState::TargetScopeVec::reverse_iterator it;
for (it = gIR->targetScopes.rbegin(); it != targetit; ++it) {
if (it->enclosinghandler)
it->enclosinghandler->emitCode(gIR);
}
gIR->func()->popLabelScope();
}

View File

@@ -4,6 +4,31 @@
#include "gen/llvm.h"
#include "statement.h"
// this is used for tracking try-finally, synchronized and volatile scopes
struct EnclosingHandler
{
virtual void emitCode(IRState* p) = 0;
};
struct EnclosingTryFinally : EnclosingHandler
{
TryFinallyStatement* tf;
void emitCode(IRState* p);
EnclosingTryFinally(TryFinallyStatement* _tf) : tf(_tf) {}
};
struct EnclosingVolatile : EnclosingHandler
{
VolatileStatement* v;
void emitCode(IRState* p);
EnclosingVolatile(VolatileStatement* _tf) : v(_tf) {}
};
struct EnclosingSynchro : EnclosingHandler
{
SynchronizedStatement* s;
void emitCode(IRState* p);
EnclosingSynchro(SynchronizedStatement* _tf) : s(_tf) {}
};
// dynamic memory helpers
LLValue* DtoNew(Type* newtype);
void DtoDeleteMemory(LLValue* ptr);
@@ -16,17 +41,16 @@ llvm::AllocaInst* DtoAlloca(const LLType* lltype, const std::string& name = "");
llvm::AllocaInst* DtoAlloca(const LLType* lltype, LLValue* arraysize, const std::string& name = "");
// assertion generator
void DtoAssert(Module* M, Loc* loc, DValue* msg);
void DtoAssert(Module* M, Loc loc, DValue* msg);
// return the LabelStatement from the current function with the given identifier or NULL if not found
LabelStatement* DtoLabelStatement(Identifier* ident);
// emit goto
void DtoGoto(Loc* loc, Identifier* target, EnclosingHandler* enclosingtryfinally, TryFinallyStatement* sourcetf);
void DtoGoto(Loc loc, Identifier* target);
// generates IR for finally blocks between the 'start' and 'end' statements
// will begin with the finally block belonging to 'start' and does not include
// the finally block of 'end'
void DtoEnclosingHandlers(EnclosingHandler* start, EnclosingHandler* end);
// Generates IR for enclosing handlers between the current state and
// the scope created by the 'target' statement.
void DtoEnclosingHandlers(Loc loc, Statement* target);
// enters a critical section
void DtoEnterCritical(LLValue* g);

View File

@@ -76,7 +76,7 @@ void ReturnStatement::toIR(IRState* p)
DtoAssign(loc, rvar, e);
// emit scopes
DtoEnclosingHandlers(enclosinghandler, NULL);
DtoEnclosingHandlers(loc, NULL);
// emit dbg end function
if (global.params.symdebug) DtoDwarfFuncEnd(f->decl);
@@ -122,7 +122,7 @@ void ReturnStatement::toIR(IRState* p)
Logger::cout() << "return value after cast: " << *v << '\n';
}
DtoEnclosingHandlers(enclosinghandler, NULL);
DtoEnclosingHandlers(loc, NULL);
if (global.params.symdebug) DtoDwarfFuncEnd(p->func()->decl);
llvm::ReturnInst::Create(v, p->scopebb());
@@ -132,7 +132,7 @@ void ReturnStatement::toIR(IRState* p)
else
{
assert(p->topfunc()->getReturnType() == LLType::VoidTy);
DtoEnclosingHandlers(enclosinghandler, NULL);
DtoEnclosingHandlers(loc, NULL);
if (global.params.symdebug) DtoDwarfFuncEnd(p->func()->decl);
llvm::ReturnInst::Create(p->scopebb());
@@ -296,9 +296,9 @@ void WhileStatement::toIR(IRState* p)
gIR->scope() = IRScope(whilebodybb,endbb);
// while body code
p->loopbbs.push_back(IRLoopScope(this,enclosinghandler,whilebb,endbb));
p->targetScopes.push_back(IRTargetScope(this,NULL,whilebb,endbb));
body->toIR(p);
p->loopbbs.pop_back();
p->targetScopes.pop_back();
// loop
if (!gIR->scopereturned())
@@ -332,9 +332,9 @@ void DoStatement::toIR(IRState* p)
gIR->scope() = IRScope(dowhilebb,condbb);
// do-while body code
p->loopbbs.push_back(IRLoopScope(this,enclosinghandler,condbb,endbb));
p->targetScopes.push_back(IRTargetScope(this,NULL,condbb,endbb));
body->toIR(p);
p->loopbbs.pop_back();
p->targetScopes.pop_back();
// branch to condition block
llvm::BranchInst::Create(condbb, gIR->scopebb());
@@ -377,7 +377,7 @@ void ForStatement::toIR(IRState* p)
assert(!gIR->scopereturned());
llvm::BranchInst::Create(forbb, gIR->scopebb());
p->loopbbs.push_back(IRLoopScope(this,enclosinghandler,forincbb,endbb));
p->targetScopes.push_back(IRTargetScope(this,NULL,forincbb,endbb));
// replace current scope
gIR->scope() = IRScope(forbb,forbodybb);
@@ -420,7 +420,7 @@ void ForStatement::toIR(IRState* p)
if (!gIR->scopereturned())
llvm::BranchInst::Create(forbb, gIR->scopebb());
p->loopbbs.pop_back();
p->targetScopes.pop_back();
// rewrite the scope
gIR->scope() = IRScope(endbb,oldend);
@@ -444,7 +444,7 @@ void BreakStatement::toIR(IRState* p)
if (ident != 0) {
Logger::println("ident = %s", ident->toChars());
DtoEnclosingHandlers(enclosinghandler, target->enclosinghandler);
DtoEnclosingHandlers(loc, target);
// get the loop statement the label refers to
Statement* targetLoopStatement = target->statement;
@@ -454,10 +454,10 @@ void BreakStatement::toIR(IRState* p)
// find the right break block and jump there
bool found = false;
IRState::LoopScopeVec::reverse_iterator it;
for(it = p->loopbbs.rbegin(); it != p->loopbbs.rend(); ++it) {
IRState::TargetScopeVec::reverse_iterator it;
for(it = p->targetScopes.rbegin(); it != p->targetScopes.rend(); ++it) {
if(it->s == targetLoopStatement) {
llvm::BranchInst::Create(it->end, p->scopebb());
llvm::BranchInst::Create(it->breakTarget, p->scopebb());
found = true;
break;
}
@@ -465,8 +465,15 @@ void BreakStatement::toIR(IRState* p)
assert(found);
}
else {
DtoEnclosingHandlers(enclosinghandler, p->loopbbs.back().enclosinghandler);
llvm::BranchInst::Create(p->loopbbs.back().end, p->scopebb());
// find closest scope with a break target
IRState::TargetScopeVec::reverse_iterator it;
for(it = gIR->targetScopes.rbegin(); it != gIR->targetScopes.rend(); ++it) {
if(it->breakTarget) {
break;
}
}
DtoEnclosingHandlers(loc, it->s);
llvm::BranchInst::Create(it->breakTarget, gIR->scopebb());
}
// the break terminated this basicblock, start a new one
@@ -488,7 +495,7 @@ void ContinueStatement::toIR(IRState* p)
if (ident != 0) {
Logger::println("ident = %s", ident->toChars());
DtoEnclosingHandlers(enclosinghandler, target->enclosinghandler);
DtoEnclosingHandlers(loc, target);
// get the loop statement the label refers to
Statement* targetLoopStatement = target->statement;
@@ -498,10 +505,10 @@ void ContinueStatement::toIR(IRState* p)
// find the right continue block and jump there
bool found = false;
IRState::LoopScopeVec::reverse_iterator it;
for(it = gIR->loopbbs.rbegin(); it != gIR->loopbbs.rend(); ++it) {
IRState::TargetScopeVec::reverse_iterator it;
for(it = gIR->targetScopes.rbegin(); it != gIR->targetScopes.rend(); ++it) {
if(it->s == targetLoopStatement) {
llvm::BranchInst::Create(it->begin, gIR->scopebb());
llvm::BranchInst::Create(it->continueTarget, gIR->scopebb());
found = true;
break;
}
@@ -509,15 +516,15 @@ void ContinueStatement::toIR(IRState* p)
assert(found);
}
else {
// can't 'continue' within switch, so omit them
IRState::LoopScopeVec::reverse_iterator it;
for(it = gIR->loopbbs.rbegin(); it != gIR->loopbbs.rend(); ++it) {
if(!it->isSwitch) {
// find closest scope with a continue target
IRState::TargetScopeVec::reverse_iterator it;
for(it = gIR->targetScopes.rbegin(); it != gIR->targetScopes.rend(); ++it) {
if(it->continueTarget) {
break;
}
}
DtoEnclosingHandlers(enclosinghandler, it->enclosinghandler);
llvm::BranchInst::Create(it->begin, gIR->scopebb());
DtoEnclosingHandlers(loc, it->s);
llvm::BranchInst::Create(it->continueTarget, gIR->scopebb());
}
// the continue terminated this basicblock, start a new one
@@ -586,7 +593,9 @@ void TryFinallyStatement::toIR(IRState* p)
p->scope() = IRScope(trybb,finallybb);
assert(body);
p->targetScopes.push_back(IRTargetScope(this,new EnclosingTryFinally(this),NULL,NULL));
body->toIR(p);
p->targetScopes.pop_back();
// terminate try BB
if (!p->scopereturned())
@@ -842,9 +851,9 @@ void SwitchStatement::toIR(IRState* p)
assert(body);
p->scope() = IRScope(bodybb, endbb);
p->loopbbs.push_back(IRLoopScope(this,enclosinghandler,p->scopebb(),endbb,true));
p->targetScopes.push_back(IRTargetScope(this,NULL,NULL,endbb));
body->toIR(p);
p->loopbbs.pop_back();
p->targetScopes.pop_back();
if (!p->scopereturned())
llvm::BranchInst::Create(endbb, p->scopebb());
@@ -963,13 +972,13 @@ void UnrolledLoopStatement::toIR(IRState* p)
// push loop scope
// continue goes to next statement, break goes to end
p->loopbbs.push_back(IRLoopScope(this,enclosinghandler,nextbb,endbb));
p->targetScopes.push_back(IRTargetScope(this,NULL,nextbb,endbb));
// do statement
s->toIR(p);
// pop loop scope
p->loopbbs.pop_back();
p->targetScopes.pop_back();
// next stmt
if (!p->scopereturned())
@@ -1086,10 +1095,10 @@ void ForeachStatement::toIR(IRState* p)
}
// emit body
p->loopbbs.push_back(IRLoopScope(this,enclosinghandler,nextbb,endbb));
p->targetScopes.push_back(IRTargetScope(this,NULL,nextbb,endbb));
if(body)
body->toIR(p);
p->loopbbs.pop_back();
p->targetScopes.pop_back();
if (!p->scopereturned())
llvm::BranchInst::Create(nextbb, p->scopebb());
@@ -1182,10 +1191,10 @@ void ForeachRangeStatement::toIR(IRState* p)
}
// emit body
p->loopbbs.push_back(IRLoopScope(this,enclosinghandler,nextbb,endbb));
p->targetScopes.push_back(IRTargetScope(this,NULL,nextbb,endbb));
if (body)
body->toIR(p);
p->loopbbs.pop_back();
p->targetScopes.pop_back();
// jump to next iteration
if (!p->scopereturned())
@@ -1251,8 +1260,11 @@ void LabelStatement::toIR(IRState* p)
p->scope() = IRScope(labelBB,oldend);
}
if (statement)
if (statement) {
p->targetScopes.push_back(IRTargetScope(this,NULL,NULL,NULL));
statement->toIR(p);
p->targetScopes.pop_back();
}
}
//////////////////////////////////////////////////////////////////////////////
@@ -1268,7 +1280,7 @@ void GotoStatement::toIR(IRState* p)
llvm::BasicBlock* oldend = gIR->scopeend();
llvm::BasicBlock* bb = llvm::BasicBlock::Create("aftergoto", p->topfunc(), oldend);
DtoGoto(&loc, label->ident, enclosinghandler, tf);
DtoGoto(loc, label->ident);
p->scope() = IRScope(bb,oldend);
}
@@ -1289,7 +1301,7 @@ void GotoDefaultStatement::toIR(IRState* p)
assert(!p->scopereturned());
assert(sw->sdefault->bodyBB);
DtoEnclosingHandlers(enclosinghandler, sw->enclosinghandler);
DtoEnclosingHandlers(loc, sw);
llvm::BranchInst::Create(sw->sdefault->bodyBB, p->scopebb());
p->scope() = IRScope(bb,oldend);
@@ -1314,7 +1326,7 @@ void GotoCaseStatement::toIR(IRState* p)
cs->bodyBB = llvm::BasicBlock::Create("goto_case", p->topfunc(), p->scopeend());
}
DtoEnclosingHandlers(enclosinghandler, sw->enclosinghandler);
DtoEnclosingHandlers(loc, sw);
llvm::BranchInst::Create(cs->bodyBB, p->scopebb());
p->scope() = IRScope(bb,oldend);
@@ -1373,7 +1385,9 @@ void SynchronizedStatement::toIR(IRState* p)
}
// emit body
p->targetScopes.push_back(IRTargetScope(this,new EnclosingSynchro(this),NULL,NULL));
body->toIR(p);
p->targetScopes.pop_back();
// exit lock
// no point in a unreachable unlock, terminating statements must insert this themselves.
@@ -1405,7 +1419,9 @@ void VolatileStatement::toIR(IRState* p)
DtoMemoryBarrier(false, true, false, false);
// do statement
p->targetScopes.push_back(IRTargetScope(this,new EnclosingVolatile(this),NULL,NULL));
statement->toIR(p);
p->targetScopes.pop_back();
// no point in a unreachable barrier, terminating statements must insert this themselves.
if (statement->blockExit() & BEfallthru)

View File

@@ -1783,7 +1783,7 @@ DValue* AssertExp::toElem(IRState* p)
// call assert runtime functions
p->scope() = IRScope(assertbb,endbb);
DtoAssert(p->func()->decl->getModule(), &loc, msg ? msg->toElem(p) : NULL);
DtoAssert(p->func()->decl->getModule(), loc, msg ? msg->toElem(p) : NULL);
// rewrite the scope
p->scope() = IRScope(endbb,oldend);
@@ -1958,7 +1958,7 @@ DValue* HaltExp::toElem(IRState* p)
// FIXME: DMD inserts a trap here... we probably should as well !?!
#if 1
DtoAssert(p->func()->decl->getModule(), &loc, NULL);
DtoAssert(p->func()->decl->getModule(), loc, NULL);
#else
// call the new (?) trap intrinsic
p->ir->CreateCall(GET_INTRINSIC_DECL(trap),"");