Commit c0cf68ba by Ben Clayton

SpirvShader: Add EmitState

As we implement more complex control flow, we need to emit blocks with different active lane masks, and have finer control over block generation. Bug: b/128527271 Change-Id: Ica51bbea196b87ab442b394f0915e9a2cd375ac0 Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/27770 Presubmit-Ready: Ben Clayton <bclayton@google.com> Kokoro-Presubmit: kokoro <noreply+kokoro@google.com> Tested-by: 's avatarBen Clayton <bclayton@google.com> Reviewed-by: 's avatarChris Forbes <chrisforbes@google.com> Reviewed-by: 's avatarNicolas Capens <nicolascapens@google.com>
parent 3246ca29
......@@ -119,7 +119,7 @@ namespace sw
auto localInvocationIndex = SIMD::Int(subgroupIndex * SIMD::Width) + SIMD::Int(0, 1, 2, 3);
// Disable lanes where (invocationIDs >= numInvocations)
routine.activeLaneMask = CmpLT(localInvocationIndex, SIMD::Int(numInvocations));
auto activeLaneMask = CmpLT(localInvocationIndex, SIMD::Int(numInvocations));
SIMD::Int localInvocationID[3];
{
......@@ -162,7 +162,7 @@ namespace sw
});
// Process numLanes of the workgroup.
shader->emit(&routine);
shader->emit(&routine, activeLaneMask);
}
}
......
......@@ -33,7 +33,8 @@ namespace sw
routine.pushConstants = data + OFFSET(DrawData, pushConstants);
spirvShader->emit(&routine);
auto activeLaneMask = SIMD::Int(0xFFFFFFFF); // TODO: Control this.
spirvShader->emit(&routine, activeLaneMask);
spirvShader->emitEpilog(&routine);
for(int i = 0; i < RENDERTARGETS; i++)
......
......@@ -32,6 +32,7 @@ namespace sw
SpirvID() : id(0) {}
SpirvID(uint32_t id) : id(id) {}
bool operator == (const SpirvID<T>& rhs) const { return id == rhs.id; }
bool operator != (const SpirvID<T>& rhs) const { return id != rhs.id; }
bool operator < (const SpirvID<T>& rhs) const { return id < rhs.id; }
// value returns the numerical value of the identifier.
......
......@@ -21,6 +21,12 @@
#include "Vulkan/VkPipelineLayout.hpp"
#include "Device/Config.hpp"
#include <queue>
#ifdef Bool
#undef Bool // b/127920555
#endif
namespace sw
{
volatile int SpirvShader::serialCounter = 1; // Start at 1, 0 is invalid shader.
......@@ -1118,8 +1124,12 @@ namespace sw
}
}
void SpirvShader::emit(SpirvRoutine *routine) const
void SpirvShader::emit(SpirvRoutine *routine, RValue<SIMD::Int> const &activeLaneMask) const
{
EmitState state;
state.setActiveLaneMask(activeLaneMask);
state.routine = routine;
// Emit everything up to the first label
// TODO: Separate out dispatch of block from non-block instructions?
for (auto insn : *this)
......@@ -1128,22 +1138,82 @@ namespace sw
{
break;
}
EmitInstruction(routine, insn);
EmitInstruction(insn, &state);
}
// Emit the main function block
EmitBlock(routine, getBlock(mainBlockId));
// Emit all the blocks in BFS order, starting with the main block.
std::queue<Block::ID> pending;
pending.push(mainBlockId);
while (pending.size() > 0)
{
auto id = pending.front();
pending.pop();
if (state.visited.count(id) == 0)
{
EmitBlock(id, &state);
for (auto it : getBlock(id).outs)
{
pending.push(it);
}
}
}
}
void SpirvShader::EmitBlock(SpirvRoutine *routine, Block const &block) const
void SpirvShader::EmitBlock(Block::ID id, EmitState *state) const
{
for (auto insn : block)
if (state->visited.count(id) > 0)
{
EmitInstruction(routine, insn);
return; // Already processed this block.
}
state->visited.emplace(id);
auto &block = getBlock(id);
switch (block.kind)
{
case Block::Simple:
if (id != mainBlockId)
{
// Emit all preceeding blocks and set the activeLaneMask.
Intermediate activeLaneMask(1);
activeLaneMask.move(0, SIMD::Int(0));
for (auto in : block.ins)
{
EmitBlock(in, state);
auto inMask = state->getActiveLaneMaskEdge(in, id);
activeLaneMask.replace(0, activeLaneMask.Int(0) | inMask);
}
state->setActiveLaneMask(activeLaneMask.Int(0));
}
state->currentBlock = id;
EmitInstructions(block.begin(), block.end(), state);
break;
default:
UNIMPLEMENTED("Unhandled Block Kind: %d", int(block.kind));
}
}
void SpirvShader::EmitInstruction(SpirvRoutine *routine, InsnIterator insn) const
void SpirvShader::EmitInstructions(InsnIterator begin, InsnIterator end, EmitState *state) const
{
for (auto insn = begin; insn != end; insn++)
{
auto res = EmitInstruction(insn, state);
switch (res)
{
case EmitResult::Continue:
continue;
case EmitResult::Terminator:
break;
default:
UNREACHABLE("Unexpected EmitResult %d", int(res));
break;
}
}
}
SpirvShader::EmitResult SpirvShader::EmitInstruction(InsnIterator insn, EmitState *state) const
{
switch (insn.opcode())
{
......@@ -1188,7 +1258,7 @@ namespace sw
case spv::OpString:
// Nothing to do at emit time. These are either fully handled at analysis time,
// or don't require any work at all.
break;
return EmitResult::Continue;
case spv::OpLabel:
case spv::OpReturn:
......@@ -1196,54 +1266,43 @@ namespace sw
// Until then, there is nothing to do -- we expect there to be an initial OpLabel
// in the entrypoint function, for which we do nothing; and a final OpReturn at the
// end of the entrypoint function, for which we do nothing.
break;
return EmitResult::Continue;
case spv::OpVariable:
EmitVariable(insn, routine);
break;
return EmitVariable(insn, state);
case spv::OpLoad:
case spv::OpAtomicLoad:
EmitLoad(insn, routine);
break;
return EmitLoad(insn, state);
case spv::OpStore:
case spv::OpAtomicStore:
EmitStore(insn, routine);
break;
return EmitStore(insn, state);
case spv::OpAccessChain:
case spv::OpInBoundsAccessChain:
EmitAccessChain(insn, routine);
break;
return EmitAccessChain(insn, state);
case spv::OpCompositeConstruct:
EmitCompositeConstruct(insn, routine);
break;
return EmitCompositeConstruct(insn, state);
case spv::OpCompositeInsert:
EmitCompositeInsert(insn, routine);
break;
return EmitCompositeInsert(insn, state);
case spv::OpCompositeExtract:
EmitCompositeExtract(insn, routine);
break;
return EmitCompositeExtract(insn, state);
case spv::OpVectorShuffle:
EmitVectorShuffle(insn, routine);
break;
return EmitVectorShuffle(insn, state);
case spv::OpVectorExtractDynamic:
EmitVectorExtractDynamic(insn, routine);
break;
return EmitVectorExtractDynamic(insn, state);
case spv::OpVectorInsertDynamic:
EmitVectorInsertDynamic(insn, routine);
break;
return EmitVectorInsertDynamic(insn, state);
case spv::OpVectorTimesScalar:
EmitVectorTimesScalar(insn, routine);
break;
return EmitVectorTimesScalar(insn, state);
case spv::OpNot:
case spv::OpSNegate:
......@@ -1265,8 +1324,7 @@ namespace sw
case spv::OpDPdxFine:
case spv::OpDPdyFine:
case spv::OpFwidthFine:
EmitUnaryOp(insn, routine);
break;
return EmitUnaryOp(insn, state);
case spv::OpIAdd:
case spv::OpISub:
......@@ -1316,41 +1374,37 @@ namespace sw
case spv::OpLogicalNotEqual:
case spv::OpUMulExtended:
case spv::OpSMulExtended:
EmitBinaryOp(insn, routine);
break;
return EmitBinaryOp(insn, state);
case spv::OpDot:
EmitDot(insn, routine);
break;
return EmitDot(insn, state);
case spv::OpSelect:
EmitSelect(insn, routine);
break;
return EmitSelect(insn, state);
case spv::OpExtInst:
EmitExtendedInstruction(insn, routine);
break;
return EmitExtendedInstruction(insn, state);
case spv::OpAny:
EmitAny(insn, routine);
break;
return EmitAny(insn, state);
case spv::OpAll:
EmitAll(insn, routine);
break;
return EmitAll(insn, state);
case spv::OpBranch:
EmitBranch(insn, routine);
break;
return EmitBranch(insn, state);
default:
UNIMPLEMENTED("opcode: %s", OpcodeName(insn.opcode()).c_str());
break;
}
return EmitResult::Continue;
}
void SpirvShader::EmitVariable(InsnIterator insn, SpirvRoutine *routine) const
SpirvShader::EmitResult SpirvShader::EmitVariable(InsnIterator insn, EmitState *state) const
{
auto routine = state->routine;
Object::ID resultId = insn.word(2);
auto &object = getObject(resultId);
auto &objectTy = getType(object.type);
......@@ -1397,10 +1451,13 @@ namespace sw
default:
break;
}
return EmitResult::Continue;
}
void SpirvShader::EmitLoad(InsnIterator insn, SpirvRoutine *routine) const
SpirvShader::EmitResult SpirvShader::EmitLoad(InsnIterator insn, EmitState *state) const
{
auto routine = state->routine;
bool atomic = (insn.opcode() == spv::OpAtomicLoad);
Object::ID resultId = insn.word(2);
Object::ID pointerId = insn.word(3);
......@@ -1438,7 +1495,7 @@ namespace sw
}
bool interleavedByLane = IsStorageInterleavedByLane(pointerBaseTy.storageClass);
auto anyInactiveLanes = SignMask(~routine->activeLaneMask) != 0;
auto anyInactiveLanes = SignMask(~state->activeLaneMask()) != 0;
auto load = std::unique_ptr<SIMD::Float[]>(new SIMD::Float[resultTy.sizeInComponents]);
......@@ -1453,7 +1510,7 @@ namespace sw
// i wish i had a Float,Float,Float,Float constructor here..
for (int j = 0; j < SIMD::Width; j++)
{
If(Extract(routine->activeLaneMask, j) != 0)
If(Extract(state->activeLaneMask(), j) != 0)
{
Int offset = Int(i) + Extract(offsets, j);
if (interleavedByLane) { offset = offset * SIMD::Width + j; }
......@@ -1489,10 +1546,13 @@ namespace sw
{
dst.move(i, load[i]);
}
return EmitResult::Continue;
}
void SpirvShader::EmitStore(InsnIterator insn, SpirvRoutine *routine) const
SpirvShader::EmitResult SpirvShader::EmitStore(InsnIterator insn, EmitState *state) const
{
auto routine = state->routine;
bool atomic = (insn.opcode() == spv::OpAtomicStore);
Object::ID pointerId = insn.word(1);
Object::ID objectId = insn.word(atomic ? 4 : 2);
......@@ -1529,7 +1589,7 @@ namespace sw
}
bool interleavedByLane = IsStorageInterleavedByLane(pointerBaseTy.storageClass);
auto anyInactiveLanes = SignMask(~routine->activeLaneMask) != 0;
auto anyInactiveLanes = SignMask(~state->activeLaneMask()) != 0;
if (object.kind == Object::Kind::Constant)
{
......@@ -1545,7 +1605,7 @@ namespace sw
{
for (int j = 0; j < SIMD::Width; j++)
{
If(Extract(routine->activeLaneMask, j) != 0)
If(Extract(state->activeLaneMask(), j) != 0)
{
Int offset = Int(i) + Extract(offsets, j);
if (interleavedByLane) { offset = offset * SIMD::Width + j; }
......@@ -1579,7 +1639,7 @@ namespace sw
{
for (int j = 0; j < SIMD::Width; j++)
{
If(Extract(routine->activeLaneMask, j) != 0)
If(Extract(state->activeLaneMask(), j) != 0)
{
Int offset = Int(i) + Extract(offsets, j);
if (interleavedByLane) { offset = offset * SIMD::Width + j; }
......@@ -1611,10 +1671,13 @@ namespace sw
}
}
}
return EmitResult::Continue;
}
void SpirvShader::EmitAccessChain(InsnIterator insn, SpirvRoutine *routine) const
SpirvShader::EmitResult SpirvShader::EmitAccessChain(InsnIterator insn, EmitState *state) const
{
auto routine = state->routine;
Type::ID typeId = insn.word(1);
Object::ID resultId = insn.word(2);
Object::ID baseId = insn.word(3);
......@@ -1636,10 +1699,13 @@ namespace sw
{
dst.move(0, WalkAccessChain(baseId, numIndexes, indexes, routine));
}
return EmitResult::Continue;
}
void SpirvShader::EmitCompositeConstruct(InsnIterator insn, SpirvRoutine *routine) const
SpirvShader::EmitResult SpirvShader::EmitCompositeConstruct(InsnIterator insn, EmitState *state) const
{
auto routine = state->routine;
auto &type = getType(insn.word(1));
auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
auto offset = 0u;
......@@ -1656,10 +1722,13 @@ namespace sw
dst.move(offset++, srcObjectAccess.Float(j));
}
}
return EmitResult::Continue;
}
void SpirvShader::EmitCompositeInsert(InsnIterator insn, SpirvRoutine *routine) const
SpirvShader::EmitResult SpirvShader::EmitCompositeInsert(InsnIterator insn, EmitState *state) const
{
auto routine = state->routine;
Type::ID resultTypeId = insn.word(1);
auto &type = getType(resultTypeId);
auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
......@@ -1685,10 +1754,13 @@ namespace sw
{
dst.move(i, srcObjectAccess.Float(i));
}
return EmitResult::Continue;
}
void SpirvShader::EmitCompositeExtract(InsnIterator insn, SpirvRoutine *routine) const
SpirvShader::EmitResult SpirvShader::EmitCompositeExtract(InsnIterator insn, EmitState *state) const
{
auto routine = state->routine;
auto &type = getType(insn.word(1));
auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
auto &compositeObject = getObject(insn.word(3));
......@@ -1700,10 +1772,13 @@ namespace sw
{
dst.move(i, compositeObjectAccess.Float(firstComponent + i));
}
return EmitResult::Continue;
}
void SpirvShader::EmitVectorShuffle(InsnIterator insn, SpirvRoutine *routine) const
SpirvShader::EmitResult SpirvShader::EmitVectorShuffle(InsnIterator insn, EmitState *state) const
{
auto routine = state->routine;
auto &type = getType(insn.word(1));
auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
......@@ -1732,10 +1807,13 @@ namespace sw
dst.move(i, secondHalfAccess.Float(selector - firstHalfType.sizeInComponents));
}
}
return EmitResult::Continue;
}
void SpirvShader::EmitVectorExtractDynamic(sw::SpirvShader::InsnIterator insn, sw::SpirvRoutine *routine) const
SpirvShader::EmitResult SpirvShader::EmitVectorExtractDynamic(InsnIterator insn, EmitState *state) const
{
auto routine = state->routine;
auto &type = getType(insn.word(1));
auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
auto &srcType = getType(getObject(insn.word(3)).type);
......@@ -1751,10 +1829,12 @@ namespace sw
}
dst.move(0, v);
return EmitResult::Continue;
}
void SpirvShader::EmitVectorInsertDynamic(sw::SpirvShader::InsnIterator insn, sw::SpirvRoutine *routine) const
SpirvShader::EmitResult SpirvShader::EmitVectorInsertDynamic(InsnIterator insn, EmitState *state) const
{
auto routine = state->routine;
auto &type = getType(insn.word(1));
auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
......@@ -1767,10 +1847,12 @@ namespace sw
SIMD::UInt mask = CmpEQ(SIMD::UInt(i), index.UInt(0));
dst.move(i, (src.UInt(i) & ~mask) | (component.UInt(0) & mask));
}
return EmitResult::Continue;
}
void SpirvShader::EmitVectorTimesScalar(InsnIterator insn, SpirvRoutine *routine) const
SpirvShader::EmitResult SpirvShader::EmitVectorTimesScalar(InsnIterator insn, EmitState *state) const
{
auto routine = state->routine;
auto &type = getType(insn.word(1));
auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
auto lhs = GenericValue(this, routine, insn.word(3));
......@@ -1780,10 +1862,13 @@ namespace sw
{
dst.move(i, lhs.Float(i) * rhs.Float(0));
}
return EmitResult::Continue;
}
void SpirvShader::EmitUnaryOp(InsnIterator insn, SpirvRoutine *routine) const
SpirvShader::EmitResult SpirvShader::EmitUnaryOp(InsnIterator insn, EmitState *state) const
{
auto routine = state->routine;
auto &type = getType(insn.word(1));
auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
auto src = GenericValue(this, routine, insn.word(3));
......@@ -1879,10 +1964,13 @@ namespace sw
UNIMPLEMENTED("Unhandled unary operator %s", OpcodeName(insn.opcode()).c_str());
}
}
return EmitResult::Continue;
}
void SpirvShader::EmitBinaryOp(InsnIterator insn, SpirvRoutine *routine) const
SpirvShader::EmitResult SpirvShader::EmitBinaryOp(InsnIterator insn, EmitState *state) const
{
auto routine = state->routine;
auto &type = getType(insn.word(1));
auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
auto &lhsType = getType(getObject(insn.word(3)).type);
......@@ -2072,10 +2160,13 @@ namespace sw
UNIMPLEMENTED("Unhandled binary operator %s", OpcodeName(insn.opcode()).c_str());
}
}
return EmitResult::Continue;
}
void SpirvShader::EmitDot(InsnIterator insn, SpirvRoutine *routine) const
SpirvShader::EmitResult SpirvShader::EmitDot(InsnIterator insn, EmitState *state) const
{
auto routine = state->routine;
auto &type = getType(insn.word(1));
ASSERT(type.sizeInComponents == 1);
auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
......@@ -2084,10 +2175,12 @@ namespace sw
auto rhs = GenericValue(this, routine, insn.word(4));
dst.move(0, Dot(lhsType.sizeInComponents, lhs, rhs));
return EmitResult::Continue;
}
void SpirvShader::EmitSelect(InsnIterator insn, SpirvRoutine *routine) const
SpirvShader::EmitResult SpirvShader::EmitSelect(InsnIterator insn, EmitState *state) const
{
auto routine = state->routine;
auto &type = getType(insn.word(1));
auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
auto cond = GenericValue(this, routine, insn.word(3));
......@@ -2098,10 +2191,13 @@ namespace sw
{
dst.move(i, (cond.Int(i) & lhs.Int(i)) | (~cond.Int(i) & rhs.Int(i))); // FIXME: IfThenElse()
}
return EmitResult::Continue;
}
void SpirvShader::EmitExtendedInstruction(InsnIterator insn, SpirvRoutine *routine) const
SpirvShader::EmitResult SpirvShader::EmitExtendedInstruction(InsnIterator insn, EmitState *state) const
{
auto routine = state->routine;
auto &type = getType(insn.word(1));
auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
auto extInstIndex = static_cast<GLSLstd450>(insn.word(4));
......@@ -2427,6 +2523,8 @@ namespace sw
default:
UNIMPLEMENTED("Unhandled ExtInst %d", extInstIndex);
}
return EmitResult::Continue;
}
std::memory_order SpirvShader::MemoryOrder(spv::MemorySemanticsMask memorySemantics)
......@@ -2456,8 +2554,9 @@ namespace sw
return d;
}
void SpirvShader::EmitAny(InsnIterator insn, SpirvRoutine *routine) const
SpirvShader::EmitResult SpirvShader::EmitAny(InsnIterator insn, EmitState *state) const
{
auto routine = state->routine;
auto &type = getType(insn.word(1));
ASSERT(type.sizeInComponents == 1);
auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
......@@ -2472,10 +2571,12 @@ namespace sw
}
dst.move(0, result);
return EmitResult::Continue;
}
void SpirvShader::EmitAll(InsnIterator insn, SpirvRoutine *routine) const
SpirvShader::EmitResult SpirvShader::EmitAll(InsnIterator insn, EmitState *state) const
{
auto routine = state->routine;
auto &type = getType(insn.word(1));
ASSERT(type.sizeInComponents == 1);
auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
......@@ -2490,12 +2591,15 @@ namespace sw
}
dst.move(0, result);
return EmitResult::Continue;
}
void SpirvShader::EmitBranch(InsnIterator insn, SpirvRoutine *routine) const
SpirvShader::EmitResult SpirvShader::EmitBranch(InsnIterator insn, EmitState *state) const
{
auto blockId = Block::ID(insn.word(1));
EmitBlock(routine, getBlock(blockId));
auto target = Block::ID(insn.word(1));
auto edge = Block::Edge{state->currentBlock, target};
state->edgeActiveLaneMasks.emplace(edge, state->activeLaneMask());
return EmitResult::Terminator;
}
void SpirvShader::emitEpilog(SpirvRoutine *routine) const
......@@ -2613,6 +2717,36 @@ namespace sw
break;
}
}
void SpirvShader::EmitState::addOutputActiveLaneMaskEdge(Block::ID to, RValue<SIMD::Int> mask)
{
addActiveLaneMaskEdge(currentBlock, to, mask & activeLaneMask());
}
void SpirvShader::EmitState::addActiveLaneMaskEdge(Block::ID from, Block::ID to, RValue<SIMD::Int> mask)
{
auto edge = Block::Edge{from, to};
auto it = edgeActiveLaneMasks.find(edge);
if (it == edgeActiveLaneMasks.end())
{
edgeActiveLaneMasks.emplace(edge, mask);
}
else
{
auto combined = it->second | mask;
edgeActiveLaneMasks.erase(edge);
edgeActiveLaneMasks.emplace(edge, combined);
}
}
RValue<SIMD::Int> SpirvShader::EmitState::getActiveLaneMaskEdge(Block::ID from, Block::ID to)
{
auto edge = Block::Edge{from, to};
auto it = edgeActiveLaneMasks.find(edge);
ASSERT_MSG(it != edgeActiveLaneMasks.end(), "Could not find edge %d -> %d", from.value(), to.value());
return it->second;
}
SpirvRoutine::SpirvRoutine(vk::PipelineLayout const *pipelineLayout) :
pipelineLayout(pipelineLayout)
{
......
......@@ -438,7 +438,7 @@ namespace sw
std::vector<InterfaceComponent> outputs;
void emitProlog(SpirvRoutine *routine) const;
void emit(SpirvRoutine *routine) const;
void emit(SpirvRoutine *routine, RValue<SIMD::Int> const &activeLaneMask) const;
void emitEpilog(SpirvRoutine *routine) const;
using BuiltInHash = std::hash<std::underlying_type<spv::BuiltIn>::type>;
......@@ -475,9 +475,6 @@ namespace sw
HandleMap<Block> blocks;
Block::ID mainBlockId; // Block of the entry point function.
void EmitBlock(SpirvRoutine *routine, Block const &block) const;
void EmitInstruction(SpirvRoutine *routine, InsnIterator insn) const;
// DeclareType creates a Type for the given OpTypeX instruction, storing
// it into the types map. It is called from the analysis pass (constructor).
void DeclareType(InsnIterator insn);
......@@ -531,26 +528,74 @@ namespace sw
SIMD::Int WalkAccessChain(Object::ID id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const;
uint32_t WalkLiteralAccessChain(Type::ID id, uint32_t numIndexes, uint32_t const *indexes) const;
// EmitState holds control-flow state for the emit() pass.
class EmitState
{
public:
RValue<SIMD::Int> activeLaneMask() const
{
ASSERT(activeLaneMaskValue != nullptr);
return RValue<SIMD::Int>(activeLaneMaskValue);
}
void setActiveLaneMask(RValue<SIMD::Int> mask)
{
activeLaneMaskValue = mask.value;
}
// Add a new active lane mask edge from the current block to out.
// The edge mask value will be (mask AND activeLaneMaskValue).
// If multiple active lane masks are added for the same edge, then
// they will be ORed together.
void addOutputActiveLaneMaskEdge(Block::ID out, RValue<SIMD::Int> mask);
// Add a new active lane mask for the edge from -> to.
// If multiple active lane masks are added for the same edge, then
// they will be ORed together.
void addActiveLaneMaskEdge(Block::ID from, Block::ID to, RValue<SIMD::Int> mask);
// Lookup the active lane mask for the edge from -> to.
// Asserts if the edge does not exist.
RValue<SIMD::Int> getActiveLaneMaskEdge(Block::ID from, Block::ID to);
SpirvRoutine *routine = nullptr; // The current routine being built.
rr::Value *activeLaneMaskValue = nullptr; // The current active lane mask.
Block::ID currentBlock; // The current block being built.
Block::Set visited; // Blocks already built.
std::unordered_map<Block::Edge, RValue<SIMD::Int>, Block::Edge::Hash> edgeActiveLaneMasks;
};
// EmitResult is an enumerator of result values from the Emit functions.
enum class EmitResult
{
Continue, // No termination instructions.
Terminator, // Reached a termination instruction.
};
void EmitBlock(Block::ID id, EmitState *state) const;
void EmitInstructions(InsnIterator begin, InsnIterator end, EmitState *state) const;
EmitResult EmitInstruction(InsnIterator insn, EmitState *state) const;
// Emit pass instructions:
void EmitVariable(InsnIterator insn, SpirvRoutine *routine) const;
void EmitLoad(InsnIterator insn, SpirvRoutine *routine) const;
void EmitStore(InsnIterator insn, SpirvRoutine *routine) const;
void EmitAccessChain(InsnIterator insn, SpirvRoutine *routine) const;
void EmitCompositeConstruct(InsnIterator insn, SpirvRoutine *routine) const;
void EmitCompositeInsert(InsnIterator insn, SpirvRoutine *routine) const;
void EmitCompositeExtract(InsnIterator insn, SpirvRoutine *routine) const;
void EmitVectorShuffle(InsnIterator insn, SpirvRoutine *routine) const;
void EmitVectorTimesScalar(InsnIterator insn, SpirvRoutine *routine) const;
void EmitVectorExtractDynamic(InsnIterator insn, SpirvRoutine *routine) const;
void EmitVectorInsertDynamic(InsnIterator insn, SpirvRoutine *routine) const;
void EmitUnaryOp(InsnIterator insn, SpirvRoutine *routine) const;
void EmitBinaryOp(InsnIterator insn, SpirvRoutine *routine) const;
void EmitDot(InsnIterator insn, SpirvRoutine *routine) const;
void EmitSelect(InsnIterator insn, SpirvRoutine *routine) const;
void EmitExtendedInstruction(InsnIterator insn, SpirvRoutine *routine) const;
void EmitAny(InsnIterator insn, SpirvRoutine *routine) const;
void EmitAll(InsnIterator insn, SpirvRoutine *routine) const;
void EmitBranch(InsnIterator insn, SpirvRoutine *routine) const;
EmitResult EmitVariable(InsnIterator insn, EmitState *state) const;
EmitResult EmitLoad(InsnIterator insn, EmitState *state) const;
EmitResult EmitStore(InsnIterator insn, EmitState *state) const;
EmitResult EmitAccessChain(InsnIterator insn, EmitState *state) const;
EmitResult EmitCompositeConstruct(InsnIterator insn, EmitState *state) const;
EmitResult EmitCompositeInsert(InsnIterator insn, EmitState *state) const;
EmitResult EmitCompositeExtract(InsnIterator insn, EmitState *state) const;
EmitResult EmitVectorShuffle(InsnIterator insn, EmitState *state) const;
EmitResult EmitVectorTimesScalar(InsnIterator insn, EmitState *state) const;
EmitResult EmitVectorExtractDynamic(InsnIterator insn, EmitState *state) const;
EmitResult EmitVectorInsertDynamic(InsnIterator insn, EmitState *state) const;
EmitResult EmitUnaryOp(InsnIterator insn, EmitState *state) const;
EmitResult EmitBinaryOp(InsnIterator insn, EmitState *state) const;
EmitResult EmitDot(InsnIterator insn, EmitState *state) const;
EmitResult EmitSelect(InsnIterator insn, EmitState *state) const;
EmitResult EmitExtendedInstruction(InsnIterator insn, EmitState *state) const;
EmitResult EmitAny(InsnIterator insn, EmitState *state) const;
EmitResult EmitAll(InsnIterator insn, EmitState *state) const;
EmitResult EmitBranch(InsnIterator insn, EmitState *state) const;
// OpcodeName() returns the name of the opcode op.
// If NDEBUG is defined, then OpcodeName() will only return the numerical code.
......@@ -579,8 +624,6 @@ namespace sw
Value inputs = Value{MAX_INTERFACE_COMPONENTS};
Value outputs = Value{MAX_INTERFACE_COMPONENTS};
SIMD::Int activeLaneMask = SIMD::Int(0xFFFFFFFF);
std::array<Pointer<Byte>, vk::MAX_BOUND_DESCRIPTOR_SETS> descriptorSets;
Pointer<Byte> pushConstants;
......
......@@ -74,7 +74,8 @@ namespace sw
As<Float4>(Int4(index) + Int4(0, 1, 2, 3));
}
spirvShader->emit(&routine);
auto activeLaneMask = SIMD::Int(0xFFFFFFFF); // TODO: Control this.
spirvShader->emit(&routine, activeLaneMask);
if(currentLabel != -1)
{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment