diff options
| author | Yong He <yonghe@outlook.com> | 2025-02-06 22:02:43 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-02-06 22:02:43 -0800 |
| commit | bae87afb20f95f9f27c64c4955bbc4464c576509 (patch) | |
| tree | 44d079bd76002d69be20efdbd03ac6ff62ef8caf /source/slang/slang-lower-to-ir.cpp | |
| parent | 075b10e69055acc6536d74c1cb3399e0fe75338d (diff) | |
Support stage_switch. (#6311)
* Support stage_switch.
* Update proposal status.
* Fix gl_InstanceID.
* Fix.
Diffstat (limited to 'source/slang/slang-lower-to-ir.cpp')
| -rw-r--r-- | source/slang/slang-lower-to-ir.cpp | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp index 36003dcb2..06cdf430b 100644 --- a/source/slang/slang-lower-to-ir.cpp +++ b/source/slang/slang-lower-to-ir.cpp @@ -6719,6 +6719,102 @@ struct StmtLoweringVisitor : StmtVisitor<StmtLoweringVisitor> } } + void visitStageSwitchStmt(StageSwitchStmt* stmt) + { + if (!stmt->targetCases.getCount()) + return; + + // We will lower stage switch as a normal switch statement, so they can participate in all + // optimizations. + auto builder = getBuilder(); + startBlockIfNeeded(stmt); + + // First emit code to get the current stage to switch on: + auto conditionVal = builder->emitGetCurrentStage(); + + // Remember the initial block so that we can add to it + // after we've collected all the `case`s + auto initialBlock = builder->getBlock(); + + // Next, create a block to use as the target for any `break` statements + auto breakLabel = createBlock(); + + // Register the `break` label so + // that we can find it for nested statements. + context->shared->breakLabels.add(stmt, breakLabel); + + builder->setInsertInto(initialBlock->getParent()); + + // Iterate over the body of the statement, looking + // for `case` or `default` statements: + SwitchStmtInfo info; + info.initialBlock = initialBlock; + info.defaultLabel = nullptr; + + Dictionary<Stmt*, IRBlock*> mapCaseStmtToBlock; + for (auto targetCase : stmt->targetCases) + { + IRBlock* caseBlock = nullptr; + if (!mapCaseStmtToBlock.tryGetValue(targetCase->body, caseBlock)) + { + caseBlock = builder->emitBlock(); + lowerStmt(context, targetCase->body); + mapCaseStmtToBlock.add(targetCase->body, caseBlock); + if (!builder->getBlock()->getTerminator()) + builder->emitBranch(breakLabel); + } + if (targetCase->capability == 0) + { + info.defaultLabel = caseBlock; + } + else + { + auto stage = getStageFromAtom((CapabilityAtom)targetCase->capability); + info.cases.add(builder->getIntValue(builder->getIntType(), (IRIntegerValue)stage)); + info.cases.add(caseBlock); + } + } + + // If the current block (the end of the last + // `case`) is not terminated, then terminate with a + // `break` operation. + // + // Double check that we aren't in the initial + // block, so we don't get tripped up on an + // empty `switch`. + auto curBlock = builder->getBlock(); + if (curBlock != initialBlock) + { + // Is the block already terminated? + if (!curBlock->getTerminator()) + { + // Not terminated, so add one. + builder->emitBreak(breakLabel); + } + } + + // If there was no `default` statement, then the + // default case will just branch directly to the end. + auto defaultLabel = info.defaultLabel ? info.defaultLabel : breakLabel; + + // Now that we've collected the cases, we are + // prepared to emit the `switch` instruction + // itself. + builder->setInsertInto(initialBlock); + builder->emitSwitch( + conditionVal, + breakLabel, + defaultLabel, + info.cases.getCount(), + info.cases.getBuffer()); + + // Finally we insert the label that a `break` will jump to + // (and that control flow will fall through to otherwise). + // This is the block that subsequent code will go into. + insertBlock(breakLabel); + context->shared->breakLabels.remove(stmt); + } + void visitTargetSwitchStmt(TargetSwitchStmt* stmt) { if (!stmt->targetCases.getCount()) |
