SpirvShader: Move spec ops to new cpp file
Bug: b/145336353
Change-Id: I202a8c4a126b2de25703bdde6409e878d4f33d31
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/38815
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
Tested-by: Ben Clayton <bclayton@google.com>
diff --git a/src/Pipeline/BUILD.gn b/src/Pipeline/BUILD.gn
index 7f158fb..0422f97 100644
--- a/src/Pipeline/BUILD.gn
+++ b/src/Pipeline/BUILD.gn
@@ -45,6 +45,7 @@
"SpirvShaderGroup.cpp",
"SpirvShaderMemory.cpp",
"SpirvShaderSampling.cpp",
+ "SpirvShaderSpec.cpp",
"VertexProgram.cpp",
"VertexRoutine.cpp",
]
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index b8632d3..f8fc6d0 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -3809,299 +3809,6 @@
return scopeObj.constantValue[0];
}
- void SpirvShader::EvalSpecConstantOp(InsnIterator insn)
- {
- auto opcode = static_cast<spv::Op>(insn.word(3));
-
- switch (opcode)
- {
- case spv::OpIAdd:
- case spv::OpISub:
- case spv::OpIMul:
- case spv::OpUDiv:
- case spv::OpSDiv:
- case spv::OpUMod:
- case spv::OpSMod:
- case spv::OpSRem:
- case spv::OpShiftRightLogical:
- case spv::OpShiftRightArithmetic:
- case spv::OpShiftLeftLogical:
- case spv::OpBitwiseOr:
- case spv::OpLogicalOr:
- case spv::OpBitwiseAnd:
- case spv::OpLogicalAnd:
- case spv::OpBitwiseXor:
- case spv::OpLogicalEqual:
- case spv::OpIEqual:
- case spv::OpLogicalNotEqual:
- case spv::OpINotEqual:
- case spv::OpULessThan:
- case spv::OpSLessThan:
- case spv::OpUGreaterThan:
- case spv::OpSGreaterThan:
- case spv::OpULessThanEqual:
- case spv::OpSLessThanEqual:
- case spv::OpUGreaterThanEqual:
- case spv::OpSGreaterThanEqual:
- EvalSpecConstantBinaryOp(insn);
- break;
-
- case spv::OpSConvert:
- case spv::OpFConvert:
- case spv::OpUConvert:
- case spv::OpSNegate:
- case spv::OpNot:
- case spv::OpLogicalNot:
- case spv::OpQuantizeToF16:
- EvalSpecConstantUnaryOp(insn);
- break;
-
- case spv::OpSelect:
- {
- auto &result = CreateConstant(insn);
- auto const &cond = getObject(insn.word(4));
- auto condIsScalar = (getType(cond.type).sizeInComponents == 1);
- auto const &left = getObject(insn.word(5));
- auto const &right = getObject(insn.word(6));
-
- for (auto i = 0u; i < getType(result.type).sizeInComponents; i++)
- {
- auto sel = cond.constantValue[condIsScalar ? 0 : i];
- result.constantValue[i] = sel ? left.constantValue[i] : right.constantValue[i];
- }
- break;
- }
-
- case spv::OpCompositeExtract:
- {
- auto &result = CreateConstant(insn);
- auto const &compositeObject = getObject(insn.word(4));
- auto firstComponent = WalkLiteralAccessChain(compositeObject.type, insn.wordCount() - 5, insn.wordPointer(5));
-
- for (auto i = 0u; i < getType(result.type).sizeInComponents; i++)
- {
- result.constantValue[i] = compositeObject.constantValue[firstComponent + i];
- }
- break;
- }
-
- case spv::OpCompositeInsert:
- {
- auto &result = CreateConstant(insn);
- auto const &newPart = getObject(insn.word(4));
- auto const &oldObject = getObject(insn.word(5));
- auto firstNewComponent = WalkLiteralAccessChain(result.type, insn.wordCount() - 6, insn.wordPointer(6));
-
- // old components before
- for (auto i = 0u; i < firstNewComponent; i++)
- {
- result.constantValue[i] = oldObject.constantValue[i];
- }
- // new part
- for (auto i = 0u; i < getType(newPart.type).sizeInComponents; i++)
- {
- result.constantValue[firstNewComponent + i] = newPart.constantValue[i];
- }
- // old components after
- for (auto i = firstNewComponent + getType(newPart.type).sizeInComponents; i < getType(result.type).sizeInComponents; i++)
- {
- result.constantValue[i] = oldObject.constantValue[i];
- }
- break;
- }
-
- case spv::OpVectorShuffle:
- {
- auto &result = CreateConstant(insn);
- auto const &firstHalf = getObject(insn.word(4));
- auto const &secondHalf = getObject(insn.word(5));
-
- for (auto i = 0u; i < getType(result.type).sizeInComponents; i++)
- {
- auto selector = insn.word(6 + i);
- if (selector == static_cast<uint32_t>(-1))
- {
- // Undefined value, we'll use zero
- result.constantValue[i] = 0;
- }
- else if (selector < getType(firstHalf.type).sizeInComponents)
- {
- result.constantValue[i] = firstHalf.constantValue[selector];
- }
- else
- {
- result.constantValue[i] = secondHalf.constantValue[selector - getType(firstHalf.type).sizeInComponents];
- }
- }
- break;
- }
-
- default:
- // Other spec constant ops are possible, but require capabilities that are
- // not exposed in our Vulkan implementation (eg Kernel), so we should never
- // get here for correct shaders.
- UNSUPPORTED("EvalSpecConstantOp op: %s", OpcodeName(opcode).c_str());
- }
- }
-
- void SpirvShader::EvalSpecConstantUnaryOp(InsnIterator insn)
- {
- auto &result = CreateConstant(insn);
-
- auto opcode = static_cast<spv::Op>(insn.word(3));
- auto const &lhs = getObject(insn.word(4));
- auto size = getType(lhs.type).sizeInComponents;
-
- for (auto i = 0u; i < size; i++)
- {
- auto &v = result.constantValue[i];
- auto l = lhs.constantValue[i];
-
- switch (opcode)
- {
- case spv::OpSConvert:
- case spv::OpFConvert:
- case spv::OpUConvert:
- UNREACHABLE("Not possible until we have multiple bit widths");
- break;
-
- case spv::OpSNegate:
- v = -(int)l;
- break;
- case spv::OpNot:
- case spv::OpLogicalNot:
- v = ~l;
- break;
-
- case spv::OpQuantizeToF16:
- {
- // Can do this nicer with host code, but want to perfectly mirror the reactor code we emit.
- auto abs = bit_cast<float>(l & 0x7FFFFFFF);
- auto sign = l & 0x80000000;
- auto isZero = abs < 0.000061035f ? ~0u : 0u;
- auto isInf = abs > 65504.0f ? ~0u : 0u;
- auto isNaN = (abs != abs) ? ~0u : 0u;
- auto isInfOrNan = isInf | isNaN;
- v = l & 0xFFFFE000;
- v &= ~isZero | 0x80000000;
- v = sign | (isInfOrNan & 0x7F800000) | (~isInfOrNan & v);
- v |= isNaN & 0x400000;
- break;
- }
- default:
- UNREACHABLE("EvalSpecConstantUnaryOp op: %s", OpcodeName(opcode).c_str());
- }
- }
- }
-
- void SpirvShader::EvalSpecConstantBinaryOp(InsnIterator insn)
- {
- auto &result = CreateConstant(insn);
-
- auto opcode = static_cast<spv::Op>(insn.word(3));
- auto const &lhs = getObject(insn.word(4));
- auto const &rhs = getObject(insn.word(5));
- auto size = getType(lhs.type).sizeInComponents;
-
- for (auto i = 0u; i < size; i++)
- {
- auto &v = result.constantValue[i];
- auto l = lhs.constantValue[i];
- auto r = rhs.constantValue[i];
-
- switch (opcode)
- {
- case spv::OpIAdd:
- v = l + r;
- break;
- case spv::OpISub:
- v = l - r;
- break;
- case spv::OpIMul:
- v = l * r;
- break;
- case spv::OpUDiv:
- v = (r == 0) ? 0 : l / r;
- break;
- case spv::OpUMod:
- v = (r == 0) ? 0 : l % r;
- break;
- case spv::OpSDiv:
- if (r == 0) r = UINT32_MAX;
- if (l == static_cast<uint32_t>(INT32_MIN)) l = UINT32_MAX;
- v = static_cast<int32_t>(l) / static_cast<int32_t>(r);
- break;
- case spv::OpSRem:
- if (r == 0) r = UINT32_MAX;
- if (l == static_cast<uint32_t>(INT32_MIN)) l = UINT32_MAX;
- v = static_cast<int32_t>(l) % static_cast<int32_t>(r);
- break;
- case spv::OpSMod:
- if (r == 0) r = UINT32_MAX;
- if (l == static_cast<uint32_t>(INT32_MIN)) l = UINT32_MAX;
- // Test if a signed-multiply would be negative.
- v = static_cast<int32_t>(l) % static_cast<int32_t>(r);
- if ((v & 0x80000000) != (r & 0x80000000))
- v += r;
- break;
- case spv::OpShiftRightLogical:
- v = l >> r;
- break;
- case spv::OpShiftRightArithmetic:
- v = static_cast<int32_t>(l) >> r;
- break;
- case spv::OpShiftLeftLogical:
- v = l << r;
- break;
- case spv::OpBitwiseOr:
- case spv::OpLogicalOr:
- v = l | r;
- break;
- case spv::OpBitwiseAnd:
- case spv::OpLogicalAnd:
- v = l & r;
- break;
- case spv::OpBitwiseXor:
- v = l ^ r;
- break;
- case spv::OpLogicalEqual:
- case spv::OpIEqual:
- v = (l == r) ? ~0u : 0u;
- break;
- case spv::OpLogicalNotEqual:
- case spv::OpINotEqual:
- v = (l != r) ? ~0u : 0u;
- break;
- case spv::OpULessThan:
- v = l < r ? ~0u : 0u;
- break;
- case spv::OpSLessThan:
- v = static_cast<int32_t>(l) < static_cast<int32_t>(r) ? ~0u : 0u;
- break;
- case spv::OpUGreaterThan:
- v = l > r ? ~0u : 0u;
- break;
- case spv::OpSGreaterThan:
- v = static_cast<int32_t>(l) > static_cast<int32_t>(r) ? ~0u : 0u;
- break;
- case spv::OpULessThanEqual:
- v = l <= r ? ~0u : 0u;
- break;
- case spv::OpSLessThanEqual:
- v = static_cast<int32_t>(l) <= static_cast<int32_t>(r) ? ~0u : 0u;
- break;
- case spv::OpUGreaterThanEqual:
- v = l >= r ? ~0u : 0u;
- break;
- case spv::OpSGreaterThanEqual:
- v = static_cast<int32_t>(l) >= static_cast<int32_t>(r) ? ~0u : 0u;
- break;
- default:
- UNREACHABLE("EvalSpecConstantBinaryOp op: %s", OpcodeName(opcode).c_str());
- }
- }
- }
-
void SpirvShader::emitEpilog(SpirvRoutine *routine) const
{
for (auto insn : *this)
diff --git a/src/Pipeline/SpirvShaderSpec.cpp b/src/Pipeline/SpirvShaderSpec.cpp
new file mode 100644
index 0000000..38e0267
--- /dev/null
+++ b/src/Pipeline/SpirvShaderSpec.cpp
@@ -0,0 +1,315 @@
+// Copyright 2019 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "SpirvShader.hpp"
+
+#include <spirv/unified1/spirv.hpp>
+#include <spirv/unified1/GLSL.std.450.h>
+
+namespace sw {
+
+void SpirvShader::EvalSpecConstantOp(InsnIterator insn)
+{
+ auto opcode = static_cast<spv::Op>(insn.word(3));
+
+ switch (opcode)
+ {
+ case spv::OpIAdd:
+ case spv::OpISub:
+ case spv::OpIMul:
+ case spv::OpUDiv:
+ case spv::OpSDiv:
+ case spv::OpUMod:
+ case spv::OpSMod:
+ case spv::OpSRem:
+ case spv::OpShiftRightLogical:
+ case spv::OpShiftRightArithmetic:
+ case spv::OpShiftLeftLogical:
+ case spv::OpBitwiseOr:
+ case spv::OpLogicalOr:
+ case spv::OpBitwiseAnd:
+ case spv::OpLogicalAnd:
+ case spv::OpBitwiseXor:
+ case spv::OpLogicalEqual:
+ case spv::OpIEqual:
+ case spv::OpLogicalNotEqual:
+ case spv::OpINotEqual:
+ case spv::OpULessThan:
+ case spv::OpSLessThan:
+ case spv::OpUGreaterThan:
+ case spv::OpSGreaterThan:
+ case spv::OpULessThanEqual:
+ case spv::OpSLessThanEqual:
+ case spv::OpUGreaterThanEqual:
+ case spv::OpSGreaterThanEqual:
+ EvalSpecConstantBinaryOp(insn);
+ break;
+
+ case spv::OpSConvert:
+ case spv::OpFConvert:
+ case spv::OpUConvert:
+ case spv::OpSNegate:
+ case spv::OpNot:
+ case spv::OpLogicalNot:
+ case spv::OpQuantizeToF16:
+ EvalSpecConstantUnaryOp(insn);
+ break;
+
+ case spv::OpSelect:
+ {
+ auto &result = CreateConstant(insn);
+ auto const &cond = getObject(insn.word(4));
+ auto condIsScalar = (getType(cond.type).sizeInComponents == 1);
+ auto const &left = getObject(insn.word(5));
+ auto const &right = getObject(insn.word(6));
+
+ for (auto i = 0u; i < getType(result.type).sizeInComponents; i++)
+ {
+ auto sel = cond.constantValue[condIsScalar ? 0 : i];
+ result.constantValue[i] = sel ? left.constantValue[i] : right.constantValue[i];
+ }
+ break;
+ }
+
+ case spv::OpCompositeExtract:
+ {
+ auto &result = CreateConstant(insn);
+ auto const &compositeObject = getObject(insn.word(4));
+ auto firstComponent = WalkLiteralAccessChain(compositeObject.type, insn.wordCount() - 5, insn.wordPointer(5));
+
+ for (auto i = 0u; i < getType(result.type).sizeInComponents; i++)
+ {
+ result.constantValue[i] = compositeObject.constantValue[firstComponent + i];
+ }
+ break;
+ }
+
+ case spv::OpCompositeInsert:
+ {
+ auto &result = CreateConstant(insn);
+ auto const &newPart = getObject(insn.word(4));
+ auto const &oldObject = getObject(insn.word(5));
+ auto firstNewComponent = WalkLiteralAccessChain(result.type, insn.wordCount() - 6, insn.wordPointer(6));
+
+ // old components before
+ for (auto i = 0u; i < firstNewComponent; i++)
+ {
+ result.constantValue[i] = oldObject.constantValue[i];
+ }
+ // new part
+ for (auto i = 0u; i < getType(newPart.type).sizeInComponents; i++)
+ {
+ result.constantValue[firstNewComponent + i] = newPart.constantValue[i];
+ }
+ // old components after
+ for (auto i = firstNewComponent + getType(newPart.type).sizeInComponents; i < getType(result.type).sizeInComponents; i++)
+ {
+ result.constantValue[i] = oldObject.constantValue[i];
+ }
+ break;
+ }
+
+ case spv::OpVectorShuffle:
+ {
+ auto &result = CreateConstant(insn);
+ auto const &firstHalf = getObject(insn.word(4));
+ auto const &secondHalf = getObject(insn.word(5));
+
+ for (auto i = 0u; i < getType(result.type).sizeInComponents; i++)
+ {
+ auto selector = insn.word(6 + i);
+ if (selector == static_cast<uint32_t>(-1))
+ {
+ // Undefined value, we'll use zero
+ result.constantValue[i] = 0;
+ }
+ else if (selector < getType(firstHalf.type).sizeInComponents)
+ {
+ result.constantValue[i] = firstHalf.constantValue[selector];
+ }
+ else
+ {
+ result.constantValue[i] = secondHalf.constantValue[selector - getType(firstHalf.type).sizeInComponents];
+ }
+ }
+ break;
+ }
+
+ default:
+ // Other spec constant ops are possible, but require capabilities that are
+ // not exposed in our Vulkan implementation (eg Kernel), so we should never
+ // get here for correct shaders.
+ UNSUPPORTED("EvalSpecConstantOp op: %s", OpcodeName(opcode).c_str());
+ }
+}
+
+void SpirvShader::EvalSpecConstantUnaryOp(InsnIterator insn)
+{
+ auto &result = CreateConstant(insn);
+
+ auto opcode = static_cast<spv::Op>(insn.word(3));
+ auto const &lhs = getObject(insn.word(4));
+ auto size = getType(lhs.type).sizeInComponents;
+
+ for (auto i = 0u; i < size; i++)
+ {
+ auto &v = result.constantValue[i];
+ auto l = lhs.constantValue[i];
+
+ switch (opcode)
+ {
+ case spv::OpSConvert:
+ case spv::OpFConvert:
+ case spv::OpUConvert:
+ UNREACHABLE("Not possible until we have multiple bit widths");
+ break;
+
+ case spv::OpSNegate:
+ v = -(int)l;
+ break;
+ case spv::OpNot:
+ case spv::OpLogicalNot:
+ v = ~l;
+ break;
+
+ case spv::OpQuantizeToF16:
+ {
+ // Can do this nicer with host code, but want to perfectly mirror the reactor code we emit.
+ auto abs = bit_cast<float>(l & 0x7FFFFFFF);
+ auto sign = l & 0x80000000;
+ auto isZero = abs < 0.000061035f ? ~0u : 0u;
+ auto isInf = abs > 65504.0f ? ~0u : 0u;
+ auto isNaN = (abs != abs) ? ~0u : 0u;
+ auto isInfOrNan = isInf | isNaN;
+ v = l & 0xFFFFE000;
+ v &= ~isZero | 0x80000000;
+ v = sign | (isInfOrNan & 0x7F800000) | (~isInfOrNan & v);
+ v |= isNaN & 0x400000;
+ break;
+ }
+ default:
+ UNREACHABLE("EvalSpecConstantUnaryOp op: %s", OpcodeName(opcode).c_str());
+ }
+ }
+}
+
+void SpirvShader::EvalSpecConstantBinaryOp(InsnIterator insn)
+{
+ auto &result = CreateConstant(insn);
+
+ auto opcode = static_cast<spv::Op>(insn.word(3));
+ auto const &lhs = getObject(insn.word(4));
+ auto const &rhs = getObject(insn.word(5));
+ auto size = getType(lhs.type).sizeInComponents;
+
+ for (auto i = 0u; i < size; i++)
+ {
+ auto &v = result.constantValue[i];
+ auto l = lhs.constantValue[i];
+ auto r = rhs.constantValue[i];
+
+ switch (opcode)
+ {
+ case spv::OpIAdd:
+ v = l + r;
+ break;
+ case spv::OpISub:
+ v = l - r;
+ break;
+ case spv::OpIMul:
+ v = l * r;
+ break;
+ case spv::OpUDiv:
+ v = (r == 0) ? 0 : l / r;
+ break;
+ case spv::OpUMod:
+ v = (r == 0) ? 0 : l % r;
+ break;
+ case spv::OpSDiv:
+ if (r == 0) r = UINT32_MAX;
+ if (l == static_cast<uint32_t>(INT32_MIN)) l = UINT32_MAX;
+ v = static_cast<int32_t>(l) / static_cast<int32_t>(r);
+ break;
+ case spv::OpSRem:
+ if (r == 0) r = UINT32_MAX;
+ if (l == static_cast<uint32_t>(INT32_MIN)) l = UINT32_MAX;
+ v = static_cast<int32_t>(l) % static_cast<int32_t>(r);
+ break;
+ case spv::OpSMod:
+ if (r == 0) r = UINT32_MAX;
+ if (l == static_cast<uint32_t>(INT32_MIN)) l = UINT32_MAX;
+ // Test if a signed-multiply would be negative.
+ v = static_cast<int32_t>(l) % static_cast<int32_t>(r);
+ if ((v & 0x80000000) != (r & 0x80000000))
+ v += r;
+ break;
+ case spv::OpShiftRightLogical:
+ v = l >> r;
+ break;
+ case spv::OpShiftRightArithmetic:
+ v = static_cast<int32_t>(l) >> r;
+ break;
+ case spv::OpShiftLeftLogical:
+ v = l << r;
+ break;
+ case spv::OpBitwiseOr:
+ case spv::OpLogicalOr:
+ v = l | r;
+ break;
+ case spv::OpBitwiseAnd:
+ case spv::OpLogicalAnd:
+ v = l & r;
+ break;
+ case spv::OpBitwiseXor:
+ v = l ^ r;
+ break;
+ case spv::OpLogicalEqual:
+ case spv::OpIEqual:
+ v = (l == r) ? ~0u : 0u;
+ break;
+ case spv::OpLogicalNotEqual:
+ case spv::OpINotEqual:
+ v = (l != r) ? ~0u : 0u;
+ break;
+ case spv::OpULessThan:
+ v = l < r ? ~0u : 0u;
+ break;
+ case spv::OpSLessThan:
+ v = static_cast<int32_t>(l) < static_cast<int32_t>(r) ? ~0u : 0u;
+ break;
+ case spv::OpUGreaterThan:
+ v = l > r ? ~0u : 0u;
+ break;
+ case spv::OpSGreaterThan:
+ v = static_cast<int32_t>(l) > static_cast<int32_t>(r) ? ~0u : 0u;
+ break;
+ case spv::OpULessThanEqual:
+ v = l <= r ? ~0u : 0u;
+ break;
+ case spv::OpSLessThanEqual:
+ v = static_cast<int32_t>(l) <= static_cast<int32_t>(r) ? ~0u : 0u;
+ break;
+ case spv::OpUGreaterThanEqual:
+ v = l >= r ? ~0u : 0u;
+ break;
+ case spv::OpSGreaterThanEqual:
+ v = static_cast<int32_t>(l) >= static_cast<int32_t>(r) ? ~0u : 0u;
+ break;
+ default:
+ UNREACHABLE("EvalSpecConstantBinaryOp op: %s", OpcodeName(opcode).c_str());
+ }
+ }
+}
+
+} // namespace sw
\ No newline at end of file
diff --git a/src/Vulkan/vulkan.vcxproj b/src/Vulkan/vulkan.vcxproj
index 956dfa7..d575588 100644
--- a/src/Vulkan/vulkan.vcxproj
+++ b/src/Vulkan/vulkan.vcxproj
@@ -170,6 +170,7 @@
<ClCompile Include="..\Pipeline\SpirvShaderGroup.cpp" />
<ClCompile Include="..\Pipeline\SpirvShaderMemory.cpp" />
<ClCompile Include="..\Pipeline\SpirvShaderSampling.cpp" />
+ <ClCompile Include="..\Pipeline\SpirvShaderSpec.cpp" />
<ClCompile Include="..\Pipeline\SpirvShader_dbg.cpp" />
<ClCompile Include="..\Pipeline\VertexProgram.cpp" />
<ClCompile Include="..\Pipeline\VertexRoutine.cpp" />
diff --git a/src/Vulkan/vulkan.vcxproj.filters b/src/Vulkan/vulkan.vcxproj.filters
index cb566bb..1117b53 100644
--- a/src/Vulkan/vulkan.vcxproj.filters
+++ b/src/Vulkan/vulkan.vcxproj.filters
@@ -261,6 +261,9 @@
<ClCompile Include="..\Pipeline\SpirvShaderSampling.cpp">
<Filter>Source Files\Pipeline</Filter>
</ClCompile>
+ <ClCompile Include="..\Pipeline\SpirvShaderSpec.cpp">
+ <Filter>Source Files\Pipeline</Filter>
+ </ClCompile>
<ClCompile Include="..\Pipeline\SpirvShader_dbg.cpp">
<Filter>Source Files\Pipeline</Filter>
</ClCompile>