SpirvShader: Move emit() instructions to their own functions
These are only going to grow.
Bug: b/126126820
Change-Id: I03a2b214e9968c31dabc4814b505c1f8c22349ae
Reviewed-on: https://swiftshader-review.googlesource.com/c/25552
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Reviewed-by: Chris Forbes <chrisforbes@google.com>
Tested-by: Ben Clayton <bclayton@google.com>
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index 87032d9..94c0a1f 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -836,248 +836,37 @@
break;
case spv::OpVariable:
- {
- ObjectID resultId = insn.word(2);
- auto &object = getObject(resultId);
- auto &objectTy = getType(object.type);
- if (object.kind == Object::Kind::InterfaceVariable && objectTy.storageClass == spv::StorageClassInput)
- {
- auto &dst = routine->getValue(resultId);
- int offset = 0;
- VisitInterface(resultId,
- [&](Decorations const &d, AttribType type) {
- auto scalarSlot = d.Location << 2 | d.Component;
- dst[offset++] = routine->inputs[scalarSlot];
- });
- }
+ EmitVariable(insn, routine);
break;
- }
+
case spv::OpLoad:
- {
- ObjectID objectId = insn.word(2);
- ObjectID pointerId = insn.word(3);
- auto &object = getObject(objectId);
- auto &objectTy = getType(object.type);
- auto &pointer = getObject(pointerId);
- auto &pointerBase = getObject(pointer.pointerBase);
- auto &pointerBaseTy = getType(pointerBase.type);
-
- ASSERT(getType(pointer.type).element == object.type);
- ASSERT(TypeID(insn.word(1)) == object.type);
-
- if (pointerBaseTy.storageClass == spv::StorageClassImage ||
- pointerBaseTy.storageClass == spv::StorageClassUniform ||
- pointerBaseTy.storageClass == spv::StorageClassUniformConstant)
- {
- UNIMPLEMENTED("Descriptor-backed load not yet implemented");
- }
-
- auto &ptrBase = routine->getValue(pointer.pointerBase);
- auto &dst = routine->createIntermediate(objectId, objectTy.sizeInComponents);
-
- if (pointer.kind == Object::Kind::Value)
- {
- auto offsets = As<SIMD::Int>(routine->getIntermediate(insn.word(3))[0]);
- for (auto i = 0u; i < objectTy.sizeInComponents; i++)
- {
- // i wish i had a Float,Float,Float,Float constructor here..
- SIMD::Float v;
- for (int j = 0; j < SIMD::Width; j++)
- {
- Int offset = Int(i) + Extract(offsets, j);
- v = Insert(v, Extract(ptrBase[offset], j), j);
- }
- dst.emplace(i, v);
- }
- }
- else
- {
- // no divergent offsets to worry about
- for (auto i = 0u; i < objectTy.sizeInComponents; i++)
- {
- dst.emplace(i, ptrBase[i]);
- }
- }
+ EmitLoad(insn, routine);
break;
- }
- case spv::OpAccessChain:
- {
- TypeID typeId = insn.word(1);
- ObjectID objectId = insn.word(2);
- ObjectID baseId = insn.word(3);
- auto &object = getObject(objectId);
- auto &type = getType(typeId);
- auto &pointerBase = getObject(object.pointerBase);
- auto &pointerBaseTy = getType(pointerBase.type);
- ASSERT(type.sizeInComponents == 1);
- ASSERT(getObject(baseId).pointerBase == object.pointerBase);
- if (pointerBaseTy.storageClass == spv::StorageClassImage ||
- pointerBaseTy.storageClass == spv::StorageClassUniform ||
- pointerBaseTy.storageClass == spv::StorageClassUniformConstant)
- {
- UNIMPLEMENTED("Descriptor-backed OpAccessChain not yet implemented");
- }
- auto &dst = routine->createIntermediate(objectId, type.sizeInComponents);
- dst.emplace(0, As<SIMD::Float>(WalkAccessChain(baseId, insn.wordCount() - 4, insn.wordPointer(4), routine)));
- break;
- }
case spv::OpStore:
- {
- ObjectID pointerId = insn.word(1);
- ObjectID objectId = insn.word(2);
- auto &object = getObject(objectId);
- auto &pointer = getObject(pointerId);
- auto &pointerTy = getType(pointer.type);
- auto &elementTy = getType(pointerTy.element);
- auto &pointerBase = getObject(pointer.pointerBase);
- auto &pointerBaseTy = getType(pointerBase.type);
-
- if (pointerBaseTy.storageClass == spv::StorageClassImage ||
- pointerBaseTy.storageClass == spv::StorageClassUniform ||
- pointerBaseTy.storageClass == spv::StorageClassUniformConstant)
- {
- UNIMPLEMENTED("Descriptor-backed store not yet implemented");
- }
-
- auto &ptrBase = routine->getValue(pointer.pointerBase);
-
- if (object.kind == Object::Kind::Constant)
- {
- auto src = reinterpret_cast<float *>(object.constantValue.get());
-
- if (pointer.kind == Object::Kind::Value)
- {
- auto offsets = As<SIMD::Int>(routine->getIntermediate(pointerId)[0]);
- for (auto i = 0u; i < elementTy.sizeInComponents; i++)
- {
- // Scattered store
- for (int j = 0; j < SIMD::Width; j++)
- {
- auto dst = ptrBase[Int(i) + Extract(offsets, j)];
- dst = Insert(dst, Float(src[i]), j);
- }
- }
- }
- else
- {
- // no divergent offsets
- for (auto i = 0u; i < elementTy.sizeInComponents; i++)
- {
- ptrBase[i] = RValue<SIMD::Float>(src[i]);
- }
- }
- }
- else
- {
- auto &src = routine->getIntermediate(objectId);
-
- if (pointer.kind == Object::Kind::Value)
- {
- auto offsets = As<SIMD::Int>(routine->getIntermediate(pointerId)[0]);
- for (auto i = 0u; i < elementTy.sizeInComponents; i++)
- {
- // Scattered store
- for (int j = 0; j < SIMD::Width; j++)
- {
- auto dst = ptrBase[Int(i) + Extract(offsets, j)];
- dst = Insert(dst, Extract(src[i], j), j);
- }
- }
- }
- else
- {
- // no divergent offsets
- for (auto i = 0u; i < elementTy.sizeInComponents; i++)
- {
- ptrBase[i] = src[i];
- }
- }
- }
+ EmitStore(insn, routine);
break;
- }
+
+ case spv::OpAccessChain:
+ EmitAccessChain(insn, routine);
+ break;
+
case spv::OpCompositeConstruct:
- {
- auto &type = getType(insn.word(1));
- auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
- auto offset = 0u;
-
- for (auto i = 0u; i < insn.wordCount() - 3; i++)
- {
- ObjectID srcObjectId = insn.word(3u + i);
- auto & srcObject = getObject(srcObjectId);
- auto & srcObjectTy = getType(srcObject.type);
- GenericValue srcObjectAccess(this, routine, srcObjectId);
-
- for (auto j = 0u; j < srcObjectTy.sizeInComponents; j++)
- dst.emplace(offset++, srcObjectAccess[j]);
- }
+ EmitCompositeConstruct(insn, routine);
break;
- }
+
case spv::OpCompositeInsert:
- {
- TypeID resultTypeId = insn.word(1);
- auto &type = getType(resultTypeId);
- auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
- auto &newPartObject = getObject(insn.word(3));
- auto &newPartObjectTy = getType(newPartObject.type);
- auto firstNewComponent = WalkLiteralAccessChain(resultTypeId, insn.wordCount() - 5, insn.wordPointer(5));
-
- GenericValue srcObjectAccess(this, routine, insn.word(4));
- GenericValue newPartObjectAccess(this, routine, insn.word(3));
-
- // old components before
- for (auto i = 0u; i < firstNewComponent; i++)
- dst.emplace(i, srcObjectAccess[i]);
- // new part
- for (auto i = 0u; i < newPartObjectTy.sizeInComponents; i++)
- dst.emplace(firstNewComponent + i, newPartObjectAccess[i]);
- // old components after
- for (auto i = firstNewComponent + newPartObjectTy.sizeInComponents; i < type.sizeInComponents; i++)
- dst.emplace(i, srcObjectAccess[i]);
+ EmitCompositeInsert(insn, routine);
break;
- }
+
case spv::OpCompositeExtract:
- {
- auto &type = getType(insn.word(1));
- auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
- auto &compositeObject = getObject(insn.word(3));
- TypeID compositeTypeId = compositeObject.definition.word(1);
- auto firstComponent = WalkLiteralAccessChain(compositeTypeId, insn.wordCount() - 4, insn.wordPointer(4));
-
- GenericValue compositeObjectAccess(this, routine, insn.word(3));
- for (auto i = 0u; i < type.sizeInComponents; i++)
- dst.emplace(i, compositeObjectAccess[firstComponent + i]);
+ EmitCompositeExtract(insn, routine);
break;
- }
+
case spv::OpVectorShuffle:
- {
- auto &type = getType(insn.word(1));
- auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
-
- GenericValue firstHalfAccess(this, routine, insn.word(3));
- GenericValue secondHalfAccess(this, routine, insn.word(4));
-
- for (auto i = 0u; i < type.sizeInComponents; i++)
- {
- auto selector = insn.word(5 + i);
- if (selector == static_cast<uint32_t>(-1))
- {
- // Undefined value. Until we decide to do real undef values, zero is as good
- // a value as any
- dst.emplace(i, RValue<SIMD::Float>(0.0f));
- }
- else if (selector < type.sizeInComponents)
- {
- dst.emplace(i, firstHalfAccess[selector]);
- }
- else
- {
- dst.emplace(i, secondHalfAccess[selector - type.sizeInComponents]);
- }
- }
+ EmitVectorShuffle(insn, routine);
break;
- }
+
default:
printf("emit: ignoring opcode %s\n", OpcodeName(insn.opcode()).c_str());
break;
@@ -1085,6 +874,257 @@
}
}
+ void SpirvShader::EmitVariable(InsnIterator insn, SpirvRoutine *routine) const
+ {
+ ObjectID resultId = insn.word(2);
+ auto &object = getObject(resultId);
+ auto &objectTy = getType(object.type);
+ if (object.kind == Object::Kind::InterfaceVariable && objectTy.storageClass == spv::StorageClassInput)
+ {
+ auto &dst = routine->getValue(resultId);
+ int offset = 0;
+ VisitInterface(resultId,
+ [&](Decorations const &d, AttribType type) {
+ auto scalarSlot = d.Location << 2 | d.Component;
+ dst[offset++] = routine->inputs[scalarSlot];
+ });
+ }
+ }
+
+ void SpirvShader::EmitLoad(InsnIterator insn, SpirvRoutine *routine) const
+ {
+ ObjectID objectId = insn.word(2);
+ ObjectID pointerId = insn.word(3);
+ auto &object = getObject(objectId);
+ auto &objectTy = getType(object.type);
+ auto &pointer = getObject(pointerId);
+ auto &pointerBase = getObject(pointer.pointerBase);
+ auto &pointerBaseTy = getType(pointerBase.type);
+
+ ASSERT(getType(pointer.type).element == object.type);
+ ASSERT(TypeID(insn.word(1)) == object.type);
+
+ if (pointerBaseTy.storageClass == spv::StorageClassImage ||
+ pointerBaseTy.storageClass == spv::StorageClassUniform ||
+ pointerBaseTy.storageClass == spv::StorageClassUniformConstant)
+ {
+ UNIMPLEMENTED("Descriptor-backed load not yet implemented");
+ }
+
+ auto &ptrBase = routine->getValue(pointer.pointerBase);
+ auto &dst = routine->createIntermediate(objectId, objectTy.sizeInComponents);
+
+ if (pointer.kind == Object::Kind::Value)
+ {
+ auto offsets = As<SIMD::Int>(routine->getIntermediate(insn.word(3))[0]);
+ for (auto i = 0u; i < objectTy.sizeInComponents; i++)
+ {
+ // i wish i had a Float,Float,Float,Float constructor here..
+ SIMD::Float v;
+ for (int j = 0; j < SIMD::Width; j++)
+ {
+ Int offset = Int(i) + Extract(offsets, j);
+ v = Insert(v, Extract(ptrBase[offset], j), j);
+ }
+ dst.emplace(i, v);
+ }
+ }
+ else
+ {
+ // no divergent offsets to worry about
+ for (auto i = 0u; i < objectTy.sizeInComponents; i++)
+ {
+ dst.emplace(i, ptrBase[i]);
+ }
+ }
+ }
+
+ void SpirvShader::EmitAccessChain(InsnIterator insn, SpirvRoutine *routine) const
+ {
+ TypeID typeId = insn.word(1);
+ ObjectID objectId = insn.word(2);
+ ObjectID baseId = insn.word(3);
+ auto &object = getObject(objectId);
+ auto &type = getType(typeId);
+ auto &pointerBase = getObject(object.pointerBase);
+ auto &pointerBaseTy = getType(pointerBase.type);
+ ASSERT(type.sizeInComponents == 1);
+ ASSERT(getObject(baseId).pointerBase == object.pointerBase);
+
+ if (pointerBaseTy.storageClass == spv::StorageClassImage ||
+ pointerBaseTy.storageClass == spv::StorageClassUniform ||
+ pointerBaseTy.storageClass == spv::StorageClassUniformConstant)
+ {
+ UNIMPLEMENTED("Descriptor-backed OpAccessChain not yet implemented");
+ }
+ auto &dst = routine->createIntermediate(objectId, type.sizeInComponents);
+ dst.emplace(0, As<SIMD::Float>(WalkAccessChain(baseId, insn.wordCount() - 4, insn.wordPointer(4), routine)));
+ }
+
+ void SpirvShader::EmitStore(InsnIterator insn, SpirvRoutine *routine) const
+ {
+ ObjectID pointerId = insn.word(1);
+ ObjectID objectId = insn.word(2);
+ auto &object = getObject(objectId);
+ auto &pointer = getObject(pointerId);
+ auto &pointerTy = getType(pointer.type);
+ auto &elementTy = getType(pointerTy.element);
+ auto &pointerBase = getObject(pointer.pointerBase);
+ auto &pointerBaseTy = getType(pointerBase.type);
+
+ if (pointerBaseTy.storageClass == spv::StorageClassImage ||
+ pointerBaseTy.storageClass == spv::StorageClassUniform ||
+ pointerBaseTy.storageClass == spv::StorageClassUniformConstant)
+ {
+ UNIMPLEMENTED("Descriptor-backed store not yet implemented");
+ }
+
+ auto &ptrBase = routine->getValue(pointer.pointerBase);
+
+ if (object.kind == Object::Kind::Constant)
+ {
+ auto src = reinterpret_cast<float *>(object.constantValue.get());
+
+ if (pointer.kind == Object::Kind::Value)
+ {
+ auto offsets = As<SIMD::Int>(routine->getIntermediate(pointerId)[0]);
+ for (auto i = 0u; i < elementTy.sizeInComponents; i++)
+ {
+ // Scattered store
+ for (int j = 0; j < SIMD::Width; j++)
+ {
+ auto dst = ptrBase[Int(i) + Extract(offsets, j)];
+ dst = Insert(dst, Float(src[i]), j);
+ }
+ }
+ }
+ else
+ {
+ // no divergent offsets
+ for (auto i = 0u; i < elementTy.sizeInComponents; i++)
+ {
+ ptrBase[i] = RValue<SIMD::Float>(src[i]);
+ }
+ }
+ }
+ else
+ {
+ auto &src = routine->getIntermediate(objectId);
+
+ if (pointer.kind == Object::Kind::Value)
+ {
+ auto offsets = As<SIMD::Int>(routine->getIntermediate(pointerId)[0]);
+ for (auto i = 0u; i < elementTy.sizeInComponents; i++)
+ {
+ // Scattered store
+ for (int j = 0; j < SIMD::Width; j++)
+ {
+ auto dst = ptrBase[Int(i) + Extract(offsets, j)];
+ dst = Insert(dst, Extract(src[i], j), j);
+ }
+ }
+ }
+ else
+ {
+ // no divergent offsets
+ for (auto i = 0u; i < elementTy.sizeInComponents; i++)
+ {
+ ptrBase[i] = src[i];
+ }
+ }
+ }
+ }
+
+ void SpirvShader::EmitCompositeConstruct(InsnIterator insn, SpirvRoutine *routine) const
+ {
+ auto &type = getType(insn.word(1));
+ auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
+ auto offset = 0u;
+
+ for (auto i = 0u; i < insn.wordCount() - 3; i++)
+ {
+ ObjectID srcObjectId = insn.word(3u + i);
+ auto & srcObject = getObject(srcObjectId);
+ auto & srcObjectTy = getType(srcObject.type);
+ GenericValue srcObjectAccess(this, routine, srcObjectId);
+
+ for (auto j = 0u; j < srcObjectTy.sizeInComponents; j++)
+ dst.emplace(offset++, srcObjectAccess[j]);
+ }
+ }
+
+ void SpirvShader::EmitCompositeInsert(InsnIterator insn, SpirvRoutine *routine) const
+ {
+ TypeID resultTypeId = insn.word(1);
+ auto &type = getType(resultTypeId);
+ auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
+ auto &newPartObject = getObject(insn.word(3));
+ auto &newPartObjectTy = getType(newPartObject.type);
+ auto firstNewComponent = WalkLiteralAccessChain(resultTypeId, insn.wordCount() - 5, insn.wordPointer(5));
+
+ GenericValue srcObjectAccess(this, routine, insn.word(4));
+ GenericValue newPartObjectAccess(this, routine, insn.word(3));
+
+ // old components before
+ for (auto i = 0u; i < firstNewComponent; i++)
+ {
+ dst.emplace(i, srcObjectAccess[i]);
+ }
+ // new part
+ for (auto i = 0u; i < newPartObjectTy.sizeInComponents; i++)
+ {
+ dst.emplace(firstNewComponent + i, newPartObjectAccess[i]);
+ }
+ // old components after
+ for (auto i = firstNewComponent + newPartObjectTy.sizeInComponents; i < type.sizeInComponents; i++)
+ {
+ dst.emplace(i, srcObjectAccess[i]);
+ }
+ }
+
+ void SpirvShader::EmitCompositeExtract(InsnIterator insn, SpirvRoutine *routine) const
+ {
+ auto &type = getType(insn.word(1));
+ auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
+ auto &compositeObject = getObject(insn.word(3));
+ TypeID compositeTypeId = compositeObject.definition.word(1);
+ auto firstComponent = WalkLiteralAccessChain(compositeTypeId, insn.wordCount() - 4, insn.wordPointer(4));
+
+ GenericValue compositeObjectAccess(this, routine, insn.word(3));
+ for (auto i = 0u; i < type.sizeInComponents; i++)
+ {
+ dst.emplace(i, compositeObjectAccess[firstComponent + i]);
+ }
+ }
+
+ void SpirvShader::EmitVectorShuffle(InsnIterator insn, SpirvRoutine *routine) const
+ {
+ auto &type = getType(insn.word(1));
+ auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
+
+ GenericValue firstHalfAccess(this, routine, insn.word(3));
+ GenericValue secondHalfAccess(this, routine, insn.word(4));
+
+ for (auto i = 0u; i < type.sizeInComponents; i++)
+ {
+ auto selector = insn.word(5 + i);
+ if (selector == static_cast<uint32_t>(-1))
+ {
+ // Undefined value. Until we decide to do real undef values, zero is as good
+ // a value as any
+ dst.emplace(i, RValue<SIMD::Float>(0.0f));
+ }
+ else if (selector < type.sizeInComponents)
+ {
+ dst.emplace(i, firstHalfAccess[selector]);
+ }
+ else
+ {
+ dst.emplace(i, secondHalfAccess[selector - type.sizeInComponents]);
+ }
+ }
+ }
+
void SpirvShader::emitEpilog(SpirvRoutine *routine) const
{
for (auto insn : *this)
diff --git a/src/Pipeline/SpirvShader.hpp b/src/Pipeline/SpirvShader.hpp
index 0081149..c877ad7 100644
--- a/src/Pipeline/SpirvShader.hpp
+++ b/src/Pipeline/SpirvShader.hpp
@@ -381,6 +381,16 @@
SIMD::Int WalkAccessChain(ObjectID id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const;
uint32_t WalkLiteralAccessChain(TypeID id, uint32_t numIndexes, uint32_t const *indexes) 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;
+
// OpcodeName returns the name of the opcode op.
// If NDEBUG is defined, then OpcodeName will only return the numerical code.
static std::string OpcodeName(spv::Op op);