Skip to content

Commit

Permalink
SpirvShader: Implement OpSwitch
Browse files Browse the repository at this point in the history
Tests: dEQP-VK.spirv_assembly.instruction.compute.*
Tests: dEQP-VK.spirv_assembly.instruction.graphics.*
Bug: b/128527271
Change-Id: I7ba31ca504a582a4d36d25ef2747fb1c1607bade
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/27775
Presubmit-Ready: Ben Clayton <bclayton@google.com>
Tested-by: Ben Clayton <bclayton@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
  • Loading branch information
ben-clayton committed Mar 26, 2019
1 parent 9fd02e0 commit 213a8ce
Show file tree
Hide file tree
Showing 3 changed files with 491 additions and 0 deletions.
38 changes: 38 additions & 0 deletions src/Pipeline/SpirvShader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1179,6 +1179,8 @@ namespace sw
case Block::Simple:
case Block::StructuredBranchConditional:
case Block::UnstructuredBranchConditional:
case Block::StructuredSwitch:
case Block::UnstructuredSwitch:
if (id != mainBlockId)
{
// Emit all preceeding blocks and set the activeLaneMask.
Expand Down Expand Up @@ -1404,6 +1406,9 @@ namespace sw
case spv::OpBranchConditional:
return EmitBranchConditional(insn, state);

case spv::OpSwitch:
return EmitSwitch(insn, state);

case spv::OpUnreachable:
return EmitUnreachable(insn, state);

Expand Down Expand Up @@ -2638,6 +2643,39 @@ namespace sw
return EmitResult::Terminator;
}

SpirvShader::EmitResult SpirvShader::EmitSwitch(InsnIterator insn, EmitState *state) const
{
auto block = getBlock(state->currentBlock);
ASSERT(block.branchInstruction == insn);

auto selId = Object::ID(block.branchInstruction.word(1));

auto sel = GenericValue(this, state->routine, selId);
ASSERT_MSG(getType(getObject(selId).type).sizeInComponents == 1, "Selector must be a scalar");

auto numCases = (block.branchInstruction.wordCount() - 3) / 2;

// TODO: Optimize for case where all lanes take same path.

SIMD::Int defaultLaneMask = state->activeLaneMask();

// Gather up the case label matches and calculate defaultLaneMask.
std::vector<RValue<SIMD::Int>> caseLabelMatches;
caseLabelMatches.reserve(numCases);
for (uint32_t i = 0; i < numCases; i++)
{
auto label = block.branchInstruction.word(i * 2 + 3);
auto caseBlockId = Block::ID(block.branchInstruction.word(i * 2 + 4));
auto caseLabelMatch = CmpEQ(sel.Int(0), SIMD::Int(label));
state->addOutputActiveLaneMaskEdge(caseBlockId, caseLabelMatch);
defaultLaneMask &= ~caseLabelMatch;
}

auto defaultBlockId = Block::ID(block.branchInstruction.word(2));
state->addOutputActiveLaneMaskEdge(defaultBlockId, defaultLaneMask);

return EmitResult::Terminator;
}

SpirvShader::EmitResult SpirvShader::EmitUnreachable(InsnIterator insn, EmitState *state) const
{
Expand Down
1 change: 1 addition & 0 deletions src/Pipeline/SpirvShader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,7 @@ namespace sw
EmitResult EmitAll(InsnIterator insn, EmitState *state) const;
EmitResult EmitBranch(InsnIterator insn, EmitState *state) const;
EmitResult EmitBranchConditional(InsnIterator insn, EmitState *state) const;
EmitResult EmitSwitch(InsnIterator insn, EmitState *state) const;
EmitResult EmitUnreachable(InsnIterator insn, EmitState *state) const;
EmitResult EmitReturn(InsnIterator insn, EmitState *state) const;
EmitResult EmitPhi(InsnIterator insn, EmitState *state) const;
Expand Down
Loading

0 comments on commit 213a8ce

Please sign in to comment.