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 ...@@ -119,7 +119,7 @@ namespace sw
auto localInvocationIndex = SIMD::Int(subgroupIndex * SIMD::Width) + SIMD::Int(0, 1, 2, 3); auto localInvocationIndex = SIMD::Int(subgroupIndex * SIMD::Width) + SIMD::Int(0, 1, 2, 3);
// Disable lanes where (invocationIDs >= numInvocations) // Disable lanes where (invocationIDs >= numInvocations)
routine.activeLaneMask = CmpLT(localInvocationIndex, SIMD::Int(numInvocations)); auto activeLaneMask = CmpLT(localInvocationIndex, SIMD::Int(numInvocations));
SIMD::Int localInvocationID[3]; SIMD::Int localInvocationID[3];
{ {
...@@ -162,7 +162,7 @@ namespace sw ...@@ -162,7 +162,7 @@ namespace sw
}); });
// Process numLanes of the workgroup. // Process numLanes of the workgroup.
shader->emit(&routine); shader->emit(&routine, activeLaneMask);
} }
} }
......
...@@ -33,7 +33,8 @@ namespace sw ...@@ -33,7 +33,8 @@ namespace sw
routine.pushConstants = data + OFFSET(DrawData, pushConstants); routine.pushConstants = data + OFFSET(DrawData, pushConstants);
spirvShader->emit(&routine); auto activeLaneMask = SIMD::Int(0xFFFFFFFF); // TODO: Control this.
spirvShader->emit(&routine, activeLaneMask);
spirvShader->emitEpilog(&routine); spirvShader->emitEpilog(&routine);
for(int i = 0; i < RENDERTARGETS; i++) for(int i = 0; i < RENDERTARGETS; i++)
......
...@@ -32,6 +32,7 @@ namespace sw ...@@ -32,6 +32,7 @@ namespace sw
SpirvID() : id(0) {} SpirvID() : id(0) {}
SpirvID(uint32_t id) : id(id) {} 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; }
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. // value returns the numerical value of the identifier.
......
...@@ -21,6 +21,12 @@ ...@@ -21,6 +21,12 @@
#include "Vulkan/VkPipelineLayout.hpp" #include "Vulkan/VkPipelineLayout.hpp"
#include "Device/Config.hpp" #include "Device/Config.hpp"
#include <queue>
#ifdef Bool
#undef Bool // b/127920555
#endif
namespace sw namespace sw
{ {
volatile int SpirvShader::serialCounter = 1; // Start at 1, 0 is invalid shader. volatile int SpirvShader::serialCounter = 1; // Start at 1, 0 is invalid shader.
...@@ -1118,8 +1124,12 @@ namespace sw ...@@ -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 // Emit everything up to the first label
// TODO: Separate out dispatch of block from non-block instructions? // TODO: Separate out dispatch of block from non-block instructions?
for (auto insn : *this) for (auto insn : *this)
...@@ -1128,22 +1138,82 @@ namespace sw ...@@ -1128,22 +1138,82 @@ namespace sw
{ {
break; break;
} }
EmitInstruction(routine, insn); EmitInstruction(insn, &state);
} }
// Emit the main function block // Emit all the blocks in BFS order, starting with the main block.
EmitBlock(routine, getBlock(mainBlockId)); 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()) switch (insn.opcode())
{ {
...@@ -1188,7 +1258,7 @@ namespace sw ...@@ -1188,7 +1258,7 @@ namespace sw
case spv::OpString: case spv::OpString:
// Nothing to do at emit time. These are either fully handled at analysis time, // Nothing to do at emit time. These are either fully handled at analysis time,
// or don't require any work at all. // or don't require any work at all.
break; return EmitResult::Continue;
case spv::OpLabel: case spv::OpLabel:
case spv::OpReturn: case spv::OpReturn:
...@@ -1196,54 +1266,43 @@ namespace sw ...@@ -1196,54 +1266,43 @@ namespace sw
// Until then, there is nothing to do -- we expect there to be an initial OpLabel // 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 // 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. // end of the entrypoint function, for which we do nothing.
break; return EmitResult::Continue;
case spv::OpVariable: case spv::OpVariable:
EmitVariable(insn, routine); return EmitVariable(insn, state);
break;
case spv::OpLoad: case spv::OpLoad:
case spv::OpAtomicLoad: case spv::OpAtomicLoad:
EmitLoad(insn, routine); return EmitLoad(insn, state);
break;
case spv::OpStore: case spv::OpStore:
case spv::OpAtomicStore: case spv::OpAtomicStore:
EmitStore(insn, routine); return EmitStore(insn, state);
break;
case spv::OpAccessChain: case spv::OpAccessChain:
case spv::OpInBoundsAccessChain: case spv::OpInBoundsAccessChain:
EmitAccessChain(insn, routine); return EmitAccessChain(insn, state);
break;
case spv::OpCompositeConstruct: case spv::OpCompositeConstruct:
EmitCompositeConstruct(insn, routine); return EmitCompositeConstruct(insn, state);
break;
case spv::OpCompositeInsert: case spv::OpCompositeInsert:
EmitCompositeInsert(insn, routine); return EmitCompositeInsert(insn, state);
break;
case spv::OpCompositeExtract: case spv::OpCompositeExtract:
EmitCompositeExtract(insn, routine); return EmitCompositeExtract(insn, state);
break;
case spv::OpVectorShuffle: case spv::OpVectorShuffle:
EmitVectorShuffle(insn, routine); return EmitVectorShuffle(insn, state);
break;
case spv::OpVectorExtractDynamic: case spv::OpVectorExtractDynamic:
EmitVectorExtractDynamic(insn, routine); return EmitVectorExtractDynamic(insn, state);
break;
case spv::OpVectorInsertDynamic: case spv::OpVectorInsertDynamic:
EmitVectorInsertDynamic(insn, routine); return EmitVectorInsertDynamic(insn, state);
break;
case spv::OpVectorTimesScalar: case spv::OpVectorTimesScalar:
EmitVectorTimesScalar(insn, routine); return EmitVectorTimesScalar(insn, state);
break;
case spv::OpNot: case spv::OpNot:
case spv::OpSNegate: case spv::OpSNegate:
...@@ -1265,8 +1324,7 @@ namespace sw ...@@ -1265,8 +1324,7 @@ namespace sw
case spv::OpDPdxFine: case spv::OpDPdxFine:
case spv::OpDPdyFine: case spv::OpDPdyFine:
case spv::OpFwidthFine: case spv::OpFwidthFine:
EmitUnaryOp(insn, routine); return EmitUnaryOp(insn, state);
break;
case spv::OpIAdd: case spv::OpIAdd:
case spv::OpISub: case spv::OpISub:
...@@ -1316,41 +1374,37 @@ namespace sw ...@@ -1316,41 +1374,37 @@ namespace sw
case spv::OpLogicalNotEqual: case spv::OpLogicalNotEqual:
case spv::OpUMulExtended: case spv::OpUMulExtended:
case spv::OpSMulExtended: case spv::OpSMulExtended:
EmitBinaryOp(insn, routine); return EmitBinaryOp(insn, state);
break;
case spv::OpDot: case spv::OpDot:
EmitDot(insn, routine); return EmitDot(insn, state);
break;
case spv::OpSelect: case spv::OpSelect:
EmitSelect(insn, routine); return EmitSelect(insn, state);
break;
case spv::OpExtInst: case spv::OpExtInst:
EmitExtendedInstruction(insn, routine); return EmitExtendedInstruction(insn, state);
break;
case spv::OpAny: case spv::OpAny:
EmitAny(insn, routine); return EmitAny(insn, state);
break;
case spv::OpAll: case spv::OpAll:
EmitAll(insn, routine); return EmitAll(insn, state);
break;
case spv::OpBranch: case spv::OpBranch:
EmitBranch(insn, routine); return EmitBranch(insn, state);
break;
default: default:
UNIMPLEMENTED("opcode: %s", OpcodeName(insn.opcode()).c_str()); UNIMPLEMENTED("opcode: %s", OpcodeName(insn.opcode()).c_str());
break; 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); Object::ID resultId = insn.word(2);
auto &object = getObject(resultId); auto &object = getObject(resultId);
auto &objectTy = getType(object.type); auto &objectTy = getType(object.type);
...@@ -1397,10 +1451,13 @@ namespace sw ...@@ -1397,10 +1451,13 @@ namespace sw
default: default:
break; 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); bool atomic = (insn.opcode() == spv::OpAtomicLoad);
Object::ID resultId = insn.word(2); Object::ID resultId = insn.word(2);
Object::ID pointerId = insn.word(3); Object::ID pointerId = insn.word(3);
...@@ -1438,7 +1495,7 @@ namespace sw ...@@ -1438,7 +1495,7 @@ namespace sw
} }
bool interleavedByLane = IsStorageInterleavedByLane(pointerBaseTy.storageClass); 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]); auto load = std::unique_ptr<SIMD::Float[]>(new SIMD::Float[resultTy.sizeInComponents]);
...@@ -1453,7 +1510,7 @@ namespace sw ...@@ -1453,7 +1510,7 @@ namespace sw
// i wish i had a Float,Float,Float,Float constructor here.. // i wish i had a Float,Float,Float,Float constructor here..
for (int j = 0; j < SIMD::Width; j++) 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); Int offset = Int(i) + Extract(offsets, j);
if (interleavedByLane) { offset = offset * SIMD::Width + j; } if (interleavedByLane) { offset = offset * SIMD::Width + j; }
...@@ -1489,10 +1546,13 @@ namespace sw ...@@ -1489,10 +1546,13 @@ namespace sw
{ {
dst.move(i, load[i]); 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); bool atomic = (insn.opcode() == spv::OpAtomicStore);
Object::ID pointerId = insn.word(1); Object::ID pointerId = insn.word(1);
Object::ID objectId = insn.word(atomic ? 4 : 2); Object::ID objectId = insn.word(atomic ? 4 : 2);
...@@ -1529,7 +1589,7 @@ namespace sw ...@@ -1529,7 +1589,7 @@ namespace sw
} }
bool interleavedByLane = IsStorageInterleavedByLane(pointerBaseTy.storageClass); bool interleavedByLane = IsStorageInterleavedByLane(pointerBaseTy.storageClass);
auto anyInactiveLanes = SignMask(~routine->activeLaneMask) != 0; auto anyInactiveLanes = SignMask(~state->activeLaneMask()) != 0;
if (object.kind == Object::Kind::Constant) if (object.kind == Object::Kind::Constant)
{ {
...@@ -1545,7 +1605,7 @@ namespace sw ...@@ -1545,7 +1605,7 @@ namespace sw
{ {
for (int j = 0; j < SIMD::Width; j++) 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); Int offset = Int(i) + Extract(offsets, j);
if (interleavedByLane) { offset = offset * SIMD::Width + j; } if (interleavedByLane) { offset = offset * SIMD::Width + j; }
...@@ -1579,7 +1639,7 @@ namespace sw ...@@ -1579,7 +1639,7 @@ namespace sw
{ {
for (int j = 0; j < SIMD::Width; j++) 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); Int offset = Int(i) + Extract(offsets, j);
if (interleavedByLane) { offset = offset * SIMD::Width + j; } if (interleavedByLane) { offset = offset * SIMD::Width + j; }
...@@ -1611,10 +1671,13 @@ namespace sw ...@@ -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); Type::ID typeId = insn.word(1);
Object::ID resultId = insn.word(2); Object::ID resultId = insn.word(2);
Object::ID baseId = insn.word(3); Object::ID baseId = insn.word(3);
...@@ -1636,10 +1699,13 @@ namespace sw ...@@ -1636,10 +1699,13 @@ namespace sw
{ {
dst.move(0, WalkAccessChain(baseId, numIndexes, indexes, routine)); 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 &type = getType(insn.word(1));
auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents); auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
auto offset = 0u; auto offset = 0u;
...@@ -1656,10 +1722,13 @@ namespace sw ...@@ -1656,10 +1722,13 @@ namespace sw
dst.move(offset++, srcObjectAccess.Float(j)); 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); Type::ID resultTypeId = insn.word(1);
auto &type = getType(resultTypeId); auto &type = getType(resultTypeId);
auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents); auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
...@@ -1685,10 +1754,13 @@ namespace sw ...@@ -1685,10 +1754,13 @@ namespace sw
{ {
dst.move(i, srcObjectAccess.Float(i)); 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 &type = getType(insn.word(1));
auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents); auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
auto &compositeObject = getObject(insn.word(3)); auto &compositeObject = getObject(insn.word(3));
...@@ -1700,10 +1772,13 @@ namespace sw ...@@ -1700,10 +1772,13 @@ namespace sw
{ {
dst.move(i, compositeObjectAccess.Float(firstComponent + i)); 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 &type = getType(insn.word(1));
auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents); auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
...@@ -1732,10 +1807,13 @@ namespace sw ...@@ -1732,10 +1807,13 @@ namespace sw
dst.move(i, secondHalfAccess.Float(selector - firstHalfType.sizeInComponents)); 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 &type = getType(insn.word(1));
auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents); auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
auto &srcType = getType(getObject(insn.word(3)).type); auto &srcType = getType(getObject(insn.word(3)).type);
...@@ -1751,10 +1829,12 @@ namespace sw ...@@ -1751,10 +1829,12 @@ namespace sw
} }
dst.move(0, v); 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 &type = getType(insn.word(1));
auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents); auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
...@@ -1767,10 +1847,12 @@ namespace sw ...@@ -1767,10 +1847,12 @@ namespace sw
SIMD::UInt mask = CmpEQ(SIMD::UInt(i), index.UInt(0)); SIMD::UInt mask = CmpEQ(SIMD::UInt(i), index.UInt(0));
dst.move(i, (src.UInt(i) & ~mask) | (component.UInt(0) & mask)); 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 &type = getType(insn.word(1));
auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents); auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
auto lhs = GenericValue(this, routine, insn.word(3)); auto lhs = GenericValue(this, routine, insn.word(3));
...@@ -1780,10 +1862,13 @@ namespace sw ...@@ -1780,10 +1862,13 @@ namespace sw
{ {
dst.move(i, lhs.Float(i) * rhs.Float(0)); 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 &type = getType(insn.word(1));
auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents); auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
auto src = GenericValue(this, routine, insn.word(3)); auto src = GenericValue(this, routine, insn.word(3));
...@@ -1879,10 +1964,13 @@ namespace sw ...@@ -1879,10 +1964,13 @@ namespace sw
UNIMPLEMENTED("Unhandled unary operator %s", OpcodeName(insn.opcode()).c_str()); 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 &type = getType(insn.word(1));
auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents); auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
auto &lhsType = getType(getObject(insn.word(3)).type); auto &lhsType = getType(getObject(insn.word(3)).type);
...@@ -2072,10 +2160,13 @@ namespace sw ...@@ -2072,10 +2160,13 @@ namespace sw
UNIMPLEMENTED("Unhandled binary operator %s", OpcodeName(insn.opcode()).c_str()); 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)); auto &type = getType(insn.word(1));
ASSERT(type.sizeInComponents == 1); ASSERT(type.sizeInComponents == 1);
auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents); auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
...@@ -2084,10 +2175,12 @@ namespace sw ...@@ -2084,10 +2175,12 @@ namespace sw
auto rhs = GenericValue(this, routine, insn.word(4)); auto rhs = GenericValue(this, routine, insn.word(4));
dst.move(0, Dot(lhsType.sizeInComponents, lhs, rhs)); 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 &type = getType(insn.word(1));
auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents); auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
auto cond = GenericValue(this, routine, insn.word(3)); auto cond = GenericValue(this, routine, insn.word(3));
...@@ -2098,10 +2191,13 @@ namespace sw ...@@ -2098,10 +2191,13 @@ namespace sw
{ {
dst.move(i, (cond.Int(i) & lhs.Int(i)) | (~cond.Int(i) & rhs.Int(i))); // FIXME: IfThenElse() 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 &type = getType(insn.word(1));
auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents); auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
auto extInstIndex = static_cast<GLSLstd450>(insn.word(4)); auto extInstIndex = static_cast<GLSLstd450>(insn.word(4));
...@@ -2427,6 +2523,8 @@ namespace sw ...@@ -2427,6 +2523,8 @@ namespace sw
default: default:
UNIMPLEMENTED("Unhandled ExtInst %d", extInstIndex); UNIMPLEMENTED("Unhandled ExtInst %d", extInstIndex);
} }
return EmitResult::Continue;
} }
std::memory_order SpirvShader::MemoryOrder(spv::MemorySemanticsMask memorySemantics) std::memory_order SpirvShader::MemoryOrder(spv::MemorySemanticsMask memorySemantics)
...@@ -2456,8 +2554,9 @@ namespace sw ...@@ -2456,8 +2554,9 @@ namespace sw
return d; 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)); auto &type = getType(insn.word(1));
ASSERT(type.sizeInComponents == 1); ASSERT(type.sizeInComponents == 1);
auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents); auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
...@@ -2472,10 +2571,12 @@ namespace sw ...@@ -2472,10 +2571,12 @@ namespace sw
} }
dst.move(0, result); 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)); auto &type = getType(insn.word(1));
ASSERT(type.sizeInComponents == 1); ASSERT(type.sizeInComponents == 1);
auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents); auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
...@@ -2490,12 +2591,15 @@ namespace sw ...@@ -2490,12 +2591,15 @@ namespace sw
} }
dst.move(0, result); 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)); auto target = Block::ID(insn.word(1));
EmitBlock(routine, getBlock(blockId)); auto edge = Block::Edge{state->currentBlock, target};
state->edgeActiveLaneMasks.emplace(edge, state->activeLaneMask());
return EmitResult::Terminator;
} }
void SpirvShader::emitEpilog(SpirvRoutine *routine) const void SpirvShader::emitEpilog(SpirvRoutine *routine) const
...@@ -2613,6 +2717,36 @@ namespace sw ...@@ -2613,6 +2717,36 @@ namespace sw
break; 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) : SpirvRoutine::SpirvRoutine(vk::PipelineLayout const *pipelineLayout) :
pipelineLayout(pipelineLayout) pipelineLayout(pipelineLayout)
{ {
......
...@@ -438,7 +438,7 @@ namespace sw ...@@ -438,7 +438,7 @@ namespace sw
std::vector<InterfaceComponent> outputs; std::vector<InterfaceComponent> outputs;
void emitProlog(SpirvRoutine *routine) const; 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; void emitEpilog(SpirvRoutine *routine) const;
using BuiltInHash = std::hash<std::underlying_type<spv::BuiltIn>::type>; using BuiltInHash = std::hash<std::underlying_type<spv::BuiltIn>::type>;
...@@ -475,9 +475,6 @@ namespace sw ...@@ -475,9 +475,6 @@ namespace sw
HandleMap<Block> blocks; HandleMap<Block> blocks;
Block::ID mainBlockId; // Block of the entry point function. 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 // DeclareType creates a Type for the given OpTypeX instruction, storing
// it into the types map. It is called from the analysis pass (constructor). // it into the types map. It is called from the analysis pass (constructor).
void DeclareType(InsnIterator insn); void DeclareType(InsnIterator insn);
...@@ -531,26 +528,74 @@ namespace sw ...@@ -531,26 +528,74 @@ namespace sw
SIMD::Int WalkAccessChain(Object::ID id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const; 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; 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: // Emit pass instructions:
void EmitVariable(InsnIterator insn, SpirvRoutine *routine) const; EmitResult EmitVariable(InsnIterator insn, EmitState *state) const;
void EmitLoad(InsnIterator insn, SpirvRoutine *routine) const; EmitResult EmitLoad(InsnIterator insn, EmitState *state) const;
void EmitStore(InsnIterator insn, SpirvRoutine *routine) const; EmitResult EmitStore(InsnIterator insn, EmitState *state) const;
void EmitAccessChain(InsnIterator insn, SpirvRoutine *routine) const; EmitResult EmitAccessChain(InsnIterator insn, EmitState *state) const;
void EmitCompositeConstruct(InsnIterator insn, SpirvRoutine *routine) const; EmitResult EmitCompositeConstruct(InsnIterator insn, EmitState *state) const;
void EmitCompositeInsert(InsnIterator insn, SpirvRoutine *routine) const; EmitResult EmitCompositeInsert(InsnIterator insn, EmitState *state) const;
void EmitCompositeExtract(InsnIterator insn, SpirvRoutine *routine) const; EmitResult EmitCompositeExtract(InsnIterator insn, EmitState *state) const;
void EmitVectorShuffle(InsnIterator insn, SpirvRoutine *routine) const; EmitResult EmitVectorShuffle(InsnIterator insn, EmitState *state) const;
void EmitVectorTimesScalar(InsnIterator insn, SpirvRoutine *routine) const; EmitResult EmitVectorTimesScalar(InsnIterator insn, EmitState *state) const;
void EmitVectorExtractDynamic(InsnIterator insn, SpirvRoutine *routine) const; EmitResult EmitVectorExtractDynamic(InsnIterator insn, EmitState *state) const;
void EmitVectorInsertDynamic(InsnIterator insn, SpirvRoutine *routine) const; EmitResult EmitVectorInsertDynamic(InsnIterator insn, EmitState *state) const;
void EmitUnaryOp(InsnIterator insn, SpirvRoutine *routine) const; EmitResult EmitUnaryOp(InsnIterator insn, EmitState *state) const;
void EmitBinaryOp(InsnIterator insn, SpirvRoutine *routine) const; EmitResult EmitBinaryOp(InsnIterator insn, EmitState *state) const;
void EmitDot(InsnIterator insn, SpirvRoutine *routine) const; EmitResult EmitDot(InsnIterator insn, EmitState *state) const;
void EmitSelect(InsnIterator insn, SpirvRoutine *routine) const; EmitResult EmitSelect(InsnIterator insn, EmitState *state) const;
void EmitExtendedInstruction(InsnIterator insn, SpirvRoutine *routine) const; EmitResult EmitExtendedInstruction(InsnIterator insn, EmitState *state) const;
void EmitAny(InsnIterator insn, SpirvRoutine *routine) const; EmitResult EmitAny(InsnIterator insn, EmitState *state) const;
void EmitAll(InsnIterator insn, SpirvRoutine *routine) const; EmitResult EmitAll(InsnIterator insn, EmitState *state) const;
void EmitBranch(InsnIterator insn, SpirvRoutine *routine) const; EmitResult EmitBranch(InsnIterator insn, EmitState *state) const;
// OpcodeName() returns the name of the opcode op. // OpcodeName() returns the name of the opcode op.
// If NDEBUG is defined, then OpcodeName() will only return the numerical code. // If NDEBUG is defined, then OpcodeName() will only return the numerical code.
...@@ -579,8 +624,6 @@ namespace sw ...@@ -579,8 +624,6 @@ namespace sw
Value inputs = Value{MAX_INTERFACE_COMPONENTS}; Value inputs = Value{MAX_INTERFACE_COMPONENTS};
Value outputs = 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; std::array<Pointer<Byte>, vk::MAX_BOUND_DESCRIPTOR_SETS> descriptorSets;
Pointer<Byte> pushConstants; Pointer<Byte> pushConstants;
......
...@@ -74,7 +74,8 @@ namespace sw ...@@ -74,7 +74,8 @@ namespace sw
As<Float4>(Int4(index) + Int4(0, 1, 2, 3)); 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) 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