changeset 774:9688da40cd4d

Fixed problem with continue/break in unrolled loop statements.
author tomas@myhost
date Wed, 19 Nov 2008 14:40:24 +0100
parents 5696a7167b21
children 0375841e3175
files gen/statements.cpp
diffstat 1 files changed, 49 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/gen/statements.cpp	Tue Nov 18 18:07:57 2008 +0100
+++ b/gen/statements.cpp	Wed Nov 19 14:40:24 2008 +0100
@@ -889,24 +889,66 @@
     Logger::println("UnrolledLoopStatement::toIR(): %s", loc.toChars());
     LOG_SCOPE;
 
+    // if no statements, there's nothing to do
+    if (!statements || !statements->dim)
+        return;
+
     if (global.params.symdebug)
         DtoDwarfStopPoint(loc.linnum);
 
+    // DMD doesn't fold stuff like continue/break, and since this isn't really a loop
+    // we have to keep track of each statement and jump to next the next/end on continue/break
+
     llvm::BasicBlock* oldend = gIR->scopeend();
+
+    // create a block for each statement
+    size_t nstmt = statements->dim;
+    LLSmallVector<llvm::BasicBlock*, 4> blocks(nstmt, NULL);
+
+    for (size_t i=0; i<nstmt; i++)
+    {
+        blocks[i] = llvm::BasicBlock::Create("unrolledstmt", p->topfunc(), oldend);
+    }
+
+    // create end block
     llvm::BasicBlock* endbb = llvm::BasicBlock::Create("unrolledend", p->topfunc(), oldend);
 
-    p->scope() = IRScope(p->scopebb(),endbb);
-    p->loopbbs.push_back(IRLoopScope(this,enclosinghandler,p->scopebb(),endbb));
+    // enter first stmt
+    if (!p->scopereturned())
+        p->ir->CreateBr(blocks[0]);
 
-    for (int i=0; i<statements->dim; ++i)
+    // do statements
+    Statement** stmts = (Statement**)statements->data;
+
+    for (int i=0; i<nstmt; i++)
     {
-        Statement* s = (Statement*)statements->data[i];
+        Statement* s = stmts[i];
+
+        // get blocks
+        llvm::BasicBlock* thisbb = blocks[i];
+        llvm::BasicBlock* nextbb = (i+1 == nstmt) ? endbb : blocks[i+1];
+
+        // update scope
+        p->scope() = IRScope(thisbb,nextbb);
+
+        // push loop scope
+        // continue goes to next statement, break goes to end
+        p->loopbbs.push_back(IRLoopScope(this,enclosinghandler,nextbb,endbb));
+
+        // do statement
         s->toIR(p);
+
+        // pop loop scope
+        p->loopbbs.pop_back();
+
+        // next stmt
+        if (!p->scopereturned())
+            p->ir->CreateBr(nextbb);
     }
 
-    p->loopbbs.pop_back();
-
-    llvm::BranchInst::Create(endbb, p->scopebb());
+    // finish scope
+    if (!p->scopereturned())
+        p->ir->CreateBr(endbb);
     p->scope() = IRScope(endbb,oldend);
 }