summaryrefslogtreecommitdiffstats
path: root/source/slang/emit.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/slang/emit.cpp')
-rw-r--r--source/slang/emit.cpp33
1 files changed, 28 insertions, 5 deletions
diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp
index 2b7030897..039aea27d 100644
--- a/source/slang/emit.cpp
+++ b/source/slang/emit.cpp
@@ -97,6 +97,8 @@ struct SharedEmitContext
Dictionary<IRValue*, UInt> mapIRValueToID;
HashSet<Decl*> irDeclsVisited;
+
+ Dictionary<IRBlock*, IRBlock*> irMapContinueTargetToLoopHead;
};
struct EmitContext
@@ -5555,10 +5557,10 @@ emitDeclImpl(decl, nullptr);
emit("for(;;)\n{\n");
- // TODO: Okay, we *said* we'd do this special
- // handling of the `continue` sites, but
- // we aren't actually setting anything up here...
- //
+ // Register information so that `continue` sites
+ // can do the right thing:
+ ctx->shared->irMapContinueTargetToLoopHead.Add(continueBlock, targetBlock);
+
emitIRStmtsForBlocks(
ctx,
@@ -5579,7 +5581,28 @@ emitDeclImpl(decl, nullptr);
return;
case kIROp_continue:
- emit("continue;\n");
+ // With out current strategy for outputting loops,
+ // just outputting an AST-level `continue` here won't
+ // actually execute the statements in the continue block.
+ //
+ // Instead, we have to manually output those statements
+ // directly here, and *then* do an AST-level `continue`.
+ //
+ // This leads to code duplication when we have multiple
+ // `continue` sites in the original program, but it avoids
+ // introducing additional temporaries for control flow.
+ {
+ auto continueInst = (IRContinue*) terminator;
+ auto targetBlock = continueInst->getTargetBlock();
+ IRBlock* loopHead = nullptr;
+ ctx->shared->irMapContinueTargetToLoopHead.TryGetValue(targetBlock, loopHead);
+ SLANG_ASSERT(loopHead);
+ emitIRStmtsForBlocks(
+ ctx,
+ targetBlock,
+ loopHead);
+ emit("continue;\n");
+ }
return;
case kIROp_loopTest: