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.cpp250
1 files changed, 144 insertions, 106 deletions
diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp
index eaabd520c..0a71c7fa9 100644
--- a/source/slang/emit.cpp
+++ b/source/slang/emit.cpp
@@ -109,8 +109,6 @@ struct SharedEmitContext
HashSet<String> irDeclsVisited;
- Dictionary<IRBlock*, IRBlock*> irMapContinueTargetToLoopHead;
-
HashSet<String> irTupleTypes;
};
@@ -1095,17 +1093,14 @@ struct EmitVisitor
UNEXPECTED(PtrType);
#undef UNEXPECTED
+
void visitNamedExpressionType(NamedExpressionType* type, TypeEmitArg const& arg)
{
- // Named types are valid for GLSL
- if (context->shared->target == CodeGenTarget::GLSL)
- {
- emitTypeImpl(GetType(type->declRef), arg.declarator);
- return;
- }
+ // We will always emit the actual type referenced by
+ // a named type declaration, rather than try to produce
+ // equivalent `typedef` declarations in the output.
- EmitDeclRef(type->declRef);
- EmitDeclarator(arg.declarator);
+ emitTypeImpl(GetType(type->declRef), arg.declarator);
}
void visitBasicExpressionType(BasicExpressionType* basicType, TypeEmitArg const& arg)
@@ -4808,7 +4803,7 @@ emitDeclImpl(decl, nullptr);
break;
case kIROp_FloatLit:
- emit(((IRConstant*) inst)->u.floatVal);
+ Emit(((IRConstant*) inst)->u.floatVal);
break;
case kIROp_boolConst:
@@ -6241,6 +6236,21 @@ emitDeclImpl(decl, nullptr);
}
}
+ enum LabelOp
+ {
+ kLabelOp_break,
+ kLabelOp_continue,
+
+ kLabelOpCount,
+ };
+
+ struct LabelStack
+ {
+ LabelStack* parent;
+ IRBlock* block;
+ LabelOp op;
+ };
+
// We want to emit a range of code in the IR, represented
// by the blocks that are logically in the interval [begin, end)
// which we consider as a single-entry multiple-exit region.
@@ -6253,11 +6263,69 @@ emitDeclImpl(decl, nullptr);
void emitIRStmtsForBlocks(
EmitContext* ctx,
IRBlock* begin,
- IRBlock* end)
+ IRBlock* end,
+
+ // Labels to use at the start
+ LabelStack* initialLabels,
+
+ // Labels to switch to after emitting first basic block
+ LabelStack* labels = nullptr)
{
+ if(!labels)
+ labels = initialLabels;
+
+ auto useLabels = initialLabels;
+
IRBlock* block = begin;
while(block != end)
{
+ // If the block we are trying to emit has been registered as a
+ // destination label (e.g. for a loop or `switch`) then we
+ // may need to emit a `break` or `continue` as needed.
+ //
+ // TODO: we eventually need to handle the possibility of
+ // multi-level break/continue targets, which could be challenging.
+
+ // First, figure out which block has been registered as
+ // the current `break` and `continue` target.
+ IRBlock* registeredBlock[kLabelOpCount] = {};
+ for( auto ll = labels; ll; ll = ll->parent )
+ {
+ if(!registeredBlock[ll->op])
+ {
+ registeredBlock[ll->op] = ll->block;
+ }
+ }
+
+ // Next, search in the active labels we are allowed to use,
+ // and see if the block we are trying to branch to is an
+ // available break/continue target.
+ for(auto ll = useLabels; ll; ll = ll->parent)
+ {
+ if(ll->block == block)
+ {
+ // We are trying to go to a block that has been regsitered as a label.
+
+ if(block != registeredBlock[ll->op])
+ {
+ // ERROR: need support for multi-level break/continue to pull this one off!
+ }
+
+ switch(ll->op)
+ {
+ case kLabelOp_break:
+ emit("break;\n");
+ break;
+
+ case kLabelOp_continue:
+ emit("continue;\n");
+ break;
+ }
+
+ return;
+ }
+ }
+
// Start by emitting the non-terminator instructions in the block.
auto terminator = block->getLastInst();
assert(isTerminatorInst(terminator));
@@ -6285,28 +6353,6 @@ emitDeclImpl(decl, nullptr);
emitIRInst(ctx, terminator);
return;
- case kIROp_if:
- {
- // One-sided `if` statement
- auto t = (IRIf*)terminator;
-
- auto trueBlock = t->getTrueBlock();
- auto afterBlock = t->getAfterBlock();
-
- emit("if(");
- emitIROperand(ctx, t->getCondition());
- emit(")\n{\n");
- emitIRStmtsForBlocks(
- ctx,
- trueBlock,
- afterBlock);
- emit("}\n");
-
- // Continue with the block after the `if`
- block = afterBlock;
- }
- break;
-
case kIROp_ifElse:
{
// Two-sided `if` statement
@@ -6316,19 +6362,31 @@ emitDeclImpl(decl, nullptr);
auto falseBlock = t->getFalseBlock();
auto afterBlock = t->getAfterBlock();
+ // TODO: consider simplifying the code in
+ // the case where `trueBlock == afterBlock`
+ // so that we output `if(!cond) { falseBlock }`
+ // instead of the current `if(cond) {} else {falseBlock}`
+
emit("if(");
emitIROperand(ctx, t->getCondition());
emit(")\n{\n");
emitIRStmtsForBlocks(
ctx,
trueBlock,
- afterBlock);
- emit("}\nelse\n{\n");
- emitIRStmtsForBlocks(
- ctx,
- falseBlock,
- afterBlock);
+ afterBlock,
+ labels);
emit("}\n");
+ // Don't emit the false block if it would be empty
+ if(falseBlock != afterBlock)
+ {
+ emit("else\n{\n");
+ emitIRStmtsForBlocks(
+ ctx,
+ falseBlock,
+ afterBlock,
+ labels);
+ emit("}\n");
+ }
// Continue with the block after the `if`
block = afterBlock;
@@ -6342,7 +6400,6 @@ emitDeclImpl(decl, nullptr);
auto targetBlock = t->getTargetBlock();
auto breakBlock = t->getBreakBlock();
- auto continueBlock = t->getContinueBlock();
UInt argCount = t->getArgCount();
static const UInt kFixedArgCount = 3;
@@ -6352,6 +6409,25 @@ emitDeclImpl(decl, nullptr);
t->getArgs() + kFixedArgCount,
targetBlock);
+ // Set up entries on our label stack for break/continue
+
+ LabelStack subBreakLabel;
+ subBreakLabel.parent = labels;
+ subBreakLabel.block = breakBlock;
+ subBreakLabel.op = kLabelOp_break;
+
+ // Note: when forming the `continue` label, we don't
+ // actually point at the "continue block" from the loop
+ // statement, because we aren't actually going to
+ // generate an ordinary continue caluse in a `for` loop.
+ //
+ // Instead, our `continue` label will always be the
+ // loop header.
+ LabelStack subContinueLabel;
+ subContinueLabel.parent = &subBreakLabel;
+ subContinueLabel.block = targetBlock;
+ subContinueLabel.op = kLabelOp_continue;
+
if (auto loopControlDecoration = t->findDecoration<IRLoopControlDecoration>())
{
switch (loopControlDecoration->mode)
@@ -6365,75 +6441,25 @@ emitDeclImpl(decl, nullptr);
}
}
- // The challenging case for a loop is when
- // there is a `continue` block that we
- // need to deal with.
- //
- if (continueBlock == targetBlock)
- {
- // There is no continue block, so
- // we only need to emit an endless
- // loop and then manually `break`
- // out of it in the right place(s)
- emit("for(;;)\n{\n");
+ emit("for(;;)\n{\n");
- emitIRStmtsForBlocks(
- ctx,
- targetBlock,
- nullptr);
-
- emit("}\n");
- }
- else
- {
- // Okay, we've got a `continue` block,
- // which means we really want to emit
- // something akin to:
- //
- // for(;; <continueBlock>) { <bodyBlock> }
- //
- // In principle this isn't so bad, since the
- // first case is just interVal [`continueBlock`, `targetBlock`)
- // and the latter is the interval [`targetBlock`, `continueBlock`).
- //
- // The challenge of course is that a `for` statement
- // only supports *expressions* in the continue part,
- // and we might have expanded things into multiple
- // instructions (especially if we inlined or desugared anything).
- //
- // There are a variety of ways we can support lowering this,
- // but for now we are going to do something expedient
- // that mimics what `fxc` seems to do:
- //
- // - Output loop body as `for(;;) { <bodyBlock> <continueBlock> }`
- // - At any `continue` site, output `{ <continueBlock>; continue; }`
- //
- // This isn't ideal because it leads to code duplication, but
- // it matches what `fxc` does so hopefully it will be the
- // best option for our tests.
- //
-
- emit("for(;;)\n{\n");
-
- // Register information so that `continue` sites
- // can do the right thing:
- ctx->shared->irMapContinueTargetToLoopHead.Add(continueBlock, targetBlock);
-
-
- emitIRStmtsForBlocks(
- ctx,
- targetBlock,
- nullptr);
-
- emit("}\n");
+ emitIRStmtsForBlocks(
+ ctx,
+ targetBlock,
+ nullptr,
+ // For the first block, we only want the `break` label active
+ &subBreakLabel,
+ // After the first block, we can safely use the `continue` label too
+ &subContinueLabel);
- }
+ emit("}\n");
// Continue with the block after the loop
block = breakBlock;
}
break;
+#if 0
case kIROp_break:
{
auto t = (IRBreak*)terminator;
@@ -6506,6 +6532,7 @@ emitDeclImpl(decl, nullptr);
block = afterBlock;
}
break;
+#endif
case kIROp_unconditionalBranch:
{
@@ -6561,6 +6588,12 @@ emitDeclImpl(decl, nullptr);
auto breakLabel = t->getBreakLabel();
auto defaultLabel = t->getDefaultLabel();
+ // Register the block to be used for our `break` target
+ LabelStack subLabels;
+ subLabels.parent = labels;
+ subLabels.op = kLabelOp_break;
+ subLabels.block = breakLabel;
+
// We need to track whether we've dealt with
// the `default` case already.
bool defaultLabelHandled = false;
@@ -6645,7 +6678,7 @@ emitDeclImpl(decl, nullptr);
// Now emit the statements for this case.
emit("{\n");
- emitIRStmtsForBlocks(ctx, caseLabel, caseEndLabel);
+ emitIRStmtsForBlocks(ctx, caseLabel, caseEndLabel, &subLabels);
emit("}\n");
}
@@ -6656,7 +6689,7 @@ emitDeclImpl(decl, nullptr);
{
emit("default:\n");
emit("{\n");
- emitIRStmtsForBlocks(ctx, defaultLabel, breakLabel);
+ emitIRStmtsForBlocks(ctx, defaultLabel, breakLabel, &subLabels);
emit("break;\n");
emit("}\n");
}
@@ -6668,6 +6701,11 @@ emitDeclImpl(decl, nullptr);
break;
}
+ // After we've emitted the first block, we are safe from accidental
+ // cases where we'd emit an entire loop body as a single `continue`,
+ // so we can safely switch in whatever labels are intended to be used.
+ useLabels = labels;
+
// If we reach this point, then we've emitted
// one block, and we have a new block where
// control flow continues.
@@ -6928,7 +6966,7 @@ emitDeclImpl(decl, nullptr);
// Need to emit the operations in the blocks of the function
- emitIRStmtsForBlocks(ctx, func->getFirstBlock(), nullptr);
+ emitIRStmtsForBlocks(ctx, func->getFirstBlock(), nullptr, nullptr);
emit("}\n");
}
@@ -7612,7 +7650,7 @@ emitDeclImpl(decl, nullptr);
initFuncName.append("_init");
emitIRType(ctx, varType, initFuncName);
Emit("()\n{\n");
- emitIRStmtsForBlocks(ctx, varDecl->firstBlock, nullptr);
+ emitIRStmtsForBlocks(ctx, varDecl->firstBlock, nullptr, nullptr);
Emit("}\n");
}