15 #include <spirv/unified1/GLSL.std.450.h>
16 #include <spirv/unified1/spirv.h>
33 #define OP(Index, Type) Objects[Inst->getOperand(Index)].get<Type>()
48 const std::vector<Object> &InitialObjects,
49 std::shared_ptr<Memory> PipelineMemory,
Workgroup *Group,
51 : Dev(Dev), Group(Group), GlobalId(GlobalId), PipelineMemory(PipelineMemory)
68 Objects[V.first] = V.second;
74 const Type *Ty = V->getType();
81 Objects[V->getId()] =
Object(Ty, Address);
82 if (V->getInitializer())
97 #define DISPATCH(Op, Func) \
99 execute##Func(Inst); \
105 DISPATCH(SpvOpAccessChain, AccessChain);
108 DISPATCH(SpvOpAtomicAnd, AtomicOp<uint32_t>);
109 DISPATCH(SpvOpAtomicCompareExchange, AtomicCompareExchange);
110 DISPATCH(SpvOpAtomicExchange, AtomicOp<uint32_t>);
111 DISPATCH(SpvOpAtomicIAdd, AtomicOp<uint32_t>);
112 DISPATCH(SpvOpAtomicIDecrement, AtomicOp<uint32_t>);
113 DISPATCH(SpvOpAtomicIIncrement, AtomicOp<uint32_t>);
114 DISPATCH(SpvOpAtomicISub, AtomicOp<uint32_t>);
115 DISPATCH(SpvOpAtomicLoad, AtomicOp<uint32_t>);
116 DISPATCH(SpvOpAtomicOr, AtomicOp<uint32_t>);
117 DISPATCH(SpvOpAtomicSMax, AtomicOp<int32_t>);
118 DISPATCH(SpvOpAtomicSMin, AtomicOp<int32_t>);
119 DISPATCH(SpvOpAtomicStore, AtomicOp<uint32_t>);
120 DISPATCH(SpvOpAtomicUMax, AtomicOp<uint32_t>);
121 DISPATCH(SpvOpAtomicUMin, AtomicOp<uint32_t>);
122 DISPATCH(SpvOpAtomicXor, AtomicOp<uint32_t>);
124 DISPATCH(SpvOpBitwiseAnd, BitwiseAnd);
125 DISPATCH(SpvOpBitwiseOr, BitwiseOr);
126 DISPATCH(SpvOpBitwiseXor, BitwiseXor);
128 DISPATCH(SpvOpBranchConditional, BranchConditional);
129 DISPATCH(SpvOpCompositeConstruct, CompositeConstruct);
130 DISPATCH(SpvOpCompositeExtract, CompositeExtract);
131 DISPATCH(SpvOpCompositeInsert, CompositeInsert);
132 DISPATCH(SpvOpControlBarrier, ControlBarrier);
133 DISPATCH(SpvOpConvertFToS, ConvertFToS);
134 DISPATCH(SpvOpConvertFToU, ConvertFToU);
135 DISPATCH(SpvOpConvertSToF, ConvertSToF);
136 DISPATCH(SpvOpConvertUToF, ConvertUToF);
137 DISPATCH(SpvOpCopyMemory, CopyMemory);
138 DISPATCH(SpvOpCopyObject, CopyObject);
147 DISPATCH(SpvOpFOrdEqual, FOrdEqual);
148 DISPATCH(SpvOpFOrdGreaterThan, FOrdGreaterThan);
149 DISPATCH(SpvOpFOrdGreaterThanEqual, FOrdGreaterThanEqual);
150 DISPATCH(SpvOpFOrdLessThan, FOrdLessThan);
151 DISPATCH(SpvOpFOrdLessThanEqual, FOrdLessThanEqual);
152 DISPATCH(SpvOpFOrdNotEqual, FOrdNotEqual);
155 DISPATCH(SpvOpFunctionCall, FunctionCall);
156 DISPATCH(SpvOpFUnordEqual, FUnordEqual);
157 DISPATCH(SpvOpFUnordGreaterThan, FUnordGreaterThan);
158 DISPATCH(SpvOpFUnordGreaterThanEqual, FUnordGreaterThanEqual);
159 DISPATCH(SpvOpFUnordLessThan, FUnordLessThan);
160 DISPATCH(SpvOpFUnordLessThanEqual, FUnordLessThanEqual);
161 DISPATCH(SpvOpFUnordNotEqual, FUnordNotEqual);
165 DISPATCH(SpvOpImageFetch, ImageRead);
166 DISPATCH(SpvOpImageQuerySize, ImageQuerySize);
167 DISPATCH(SpvOpImageQuerySizeLod, ImageQuerySize);
168 DISPATCH(SpvOpImageRead, ImageRead);
169 DISPATCH(SpvOpImageSampleExplicitLod, ImageSampleExplicitLod);
170 DISPATCH(SpvOpImageWrite, ImageWrite);
172 DISPATCH(SpvOpInBoundsAccessChain, AccessChain);
173 DISPATCH(SpvOpINotEqual, INotEqual);
179 DISPATCH(SpvOpLogicalEqual, LogicalEqual);
180 DISPATCH(SpvOpLogicalNotEqual, LogicalNotEqual);
181 DISPATCH(SpvOpLogicalOr, LogicalOr);
182 DISPATCH(SpvOpLogicalAnd, LogicalAnd);
183 DISPATCH(SpvOpLogicalNot, LogicalNot);
184 DISPATCH(SpvOpMatrixTimesScalar, MatrixTimesScalar);
185 DISPATCH(SpvOpMatrixTimesVector, MatrixTimesVector);
188 DISPATCH(SpvOpPtrAccessChain, AccessChain);
190 DISPATCH(SpvOpReturnValue, ReturnValue);
195 DISPATCH(SpvOpSGreaterThan, SGreaterThan);
196 DISPATCH(SpvOpSGreaterThanEqual, SGreaterThanEqual);
197 DISPATCH(SpvOpShiftLeftLogical, ShiftLeftLogical);
198 DISPATCH(SpvOpShiftRightArithmetic, ShiftRightArithmetic);
199 DISPATCH(SpvOpShiftRightLogical, ShiftRightLogical);
200 DISPATCH(SpvOpSLessThan, SLessThan);
201 DISPATCH(SpvOpSLessThanEqual, SLessThanEqual);
209 DISPATCH(SpvOpUGreaterThan, UGreaterThan);
210 DISPATCH(SpvOpUGreaterThanEqual, UGreaterThanEqual);
211 DISPATCH(SpvOpULessThan, ULessThan);
212 DISPATCH(SpvOpULessThanEqual, ULessThanEqual);
215 DISPATCH(SpvOpUnreachable, Unreachable);
217 DISPATCH(SpvOpVectorExtractDynamic, VectorExtractDynamic);
218 DISPATCH(SpvOpVectorInsertDynamic, VectorInsertDynamic);
219 DISPATCH(SpvOpVectorShuffle, VectorShuffle);
220 DISPATCH(SpvOpVectorTimesMatrix, VectorTimesMatrix);
221 DISPATCH(SpvOpVectorTimesScalar, VectorTimesScalar);
226 NOP(SpvOpMemoryBarrier);
228 NOP(SpvOpSelectionMerge);
253 if (V->isBufferVariable())
255 std::stringstream Err;
256 Err <<
"Invalid base pointer for descriptor set entry ("
257 << V->getDecoration(SpvDecorationDescriptorSet) <<
","
258 << V->getDecoration(SpvDecorationBinding) <<
")";
271 assert(
false &&
"Invalid base pointer for AccessChain");
274 uint64_t Result = Base.
get<uint64_t>();
279 if (Ty->isMatrix() || Ty->isVector())
283 uint32_t FirstIndexOperand = 3;
286 if (Inst->
getOpcode() == SpvOpPtrAccessChain)
291 FirstIndexOperand = 4;
310 for (uint32_t i = FirstIndexOperand; i < Inst->
getNumOperands(); i++)
317 Index = IndexObj.
get<uint16_t>();
320 Index = IndexObj.
get<uint32_t>();
323 Index = IndexObj.
get<uint64_t>();
335 if (Index < Ty->getElementCount())
341 Dev.
reportError(
"Descriptor array element exceeds array size",
false);
345 else if (Ty->isMatrix() && MatrixLayout)
349 Result += Index * MatrixLayout.
Stride;
353 else if (Ty->isVector() && MatrixLayout)
357 Result += Index * ElemTy->
getSize();
359 Result += Index * MatrixLayout.
Stride;
363 Result += Ty->getElementOffset(Index);
369 auto &Decorations = Ty->getStructMemberDecorations((uint32_t)Index);
370 if (Decorations.count(SpvDecorationMatrixStride))
373 MatrixLayout.
Stride = Decorations.at(SpvDecorationMatrixStride);
374 if (Decorations.count(SpvDecorationColMajor))
380 assert(Decorations.count(SpvDecorationRowMajor));
392 if (MatrixLayout && (Ty->isVector() || Ty->isMatrix()))
393 Objects[Id].setMatrixLayout(MatrixLayout);
401 for (uint32_t i = 0; i < Vector.getType()->getElementCount(); i++)
403 if (!Vector.get<
bool>(i))
417 for (uint32_t i = 0; i < Vector.getType()->getElementCount(); i++)
419 if (Vector.get<
bool>(i))
430 assert(Inst->
getOpcode() != SpvOpAtomicCompareExchange);
433 uint32_t PtrOp = (Inst->
getOpcode() == SpvOpAtomicStore) ? 0 : 2;
466 UnequalSemantics, Value, Comparator);
479 executeOpUInt<2>(Inst, [](
auto A,
auto B) -> decltype(A) {
return A & B; });
484 executeOpUInt<2>(Inst, [](
auto A,
auto B) -> decltype(A) {
return A | B; });
489 executeOpUInt<2>(Inst, [](
auto A,
auto B) -> decltype(A) {
return A ^ B; });
499 bool Condition =
OP(0,
bool);
523 std::vector<uint32_t> Indices(Inst->
getOperands() + 3,
533 std::vector<uint32_t> Indices(Inst->
getOperands() + 4,
537 Objects[Id].insert(Indices, Element);
552 executeOpFP<1>(Inst, [](
auto A) -> int16_t {
return (int16_t)A; });
555 executeOpFP<1>(Inst, [](
auto A) -> int32_t {
return (int32_t)A; });
558 executeOpFP<1>(Inst, [](
auto A) -> int64_t {
return (int64_t)A; });
561 assert(
false &&
"Unhandled integer size for OpConvertFToS");
570 executeOpFP<1>(Inst, [](
auto A) -> uint16_t {
return (uint16_t)A; });
573 executeOpFP<1>(Inst, [](
auto A) -> uint32_t {
return (uint32_t)A; });
576 executeOpFP<1>(Inst, [](
auto A) -> uint64_t {
return (uint64_t)A; });
579 assert(
false &&
"Unhandled integer size for OpConvertFToU");
588 executeOpSInt<1>(Inst, [](
auto A) ->
float {
return (
float)A; });
591 executeOpSInt<1>(Inst, [](
auto A) ->
double {
return (
double)A; });
594 assert(
false &&
"Unhandled floating point size for OpConvertUToF");
603 executeOpUInt<1>(Inst, [](
auto A) ->
float {
return (
float)A; });
606 executeOpUInt<1>(Inst, [](
auto A) ->
double {
return (
double)A; });
609 assert(
false &&
"Unhandled floating point size for OpConvertUToF");
625 uint64_t DstAddress = Dst.
get<uint64_t>();
626 uint64_t SrcAddress = Src.
get<uint64_t>();
628 Memory::copy(DstAddress, DstMem, SrcAddress, SrcMem, NumBytes);
646 Result += A.
get<
float>(i) * B.
get<
float>(i);
654 Result += A.
get<
double>(i) * B.
get<
double>(i);
659 assert(
false &&
"Unhandled floating point size for OpDot");
670 executeOpFP<1, 4>(Inst, [](
auto X) -> decltype(X) {
return acos(X); });
672 case GLSLstd450Acosh:
673 executeOpFP<1, 4>(Inst, [](
auto X) -> decltype(X) {
return acosh(X); });
676 executeOpFP<1, 4>(Inst, [](
auto X) -> decltype(X) {
return asin(X); });
678 case GLSLstd450Asinh:
679 executeOpFP<1, 4>(Inst, [](
auto X) -> decltype(X) {
return asinh(X); });
682 executeOpFP<1, 4>(Inst, [](
auto X) -> decltype(X) {
return atan(X); });
684 case GLSLstd450Atanh:
685 executeOpFP<1, 4>(Inst, [](
auto X) -> decltype(X) {
return atanh(X); });
687 case GLSLstd450Atan2:
689 Inst, [](
auto Y,
auto X) -> decltype(X) {
return atan2(Y, X); });
692 executeOpFP<1, 4>(Inst, [](
auto X) -> decltype(X) {
return cos(X); });
695 executeOpFP<1, 4>(Inst, [](
auto X) -> decltype(X) {
return cosh(X); });
698 executeOpFP<1, 4>(Inst, [](
auto X) -> decltype(X) {
return fabs(X); });
703 Inst, [](
auto A,
auto B,
auto C) -> decltype(A) {
return A * B + C; });
706 case GLSLstd450Floor:
707 executeOpFP<1, 4>(Inst, [](
auto X) -> decltype(X) {
return floor(X); });
709 case GLSLstd450InverseSqrt:
710 executeOpFP<1, 4>(Inst,
711 [](
auto X) -> decltype(X) {
return 1.f / sqrt(X); });
713 case GLSLstd450NClamp:
714 executeOpFP<3, 4>(Inst, [](
auto X,
auto Min,
auto Max) -> decltype(X) {
715 return fmin(fmax(X, Min), Max);
720 executeOpFP<2, 4>(Inst,
721 [](
auto X,
auto Y) -> decltype(X) {
return fmax(X, Y); });
725 executeOpFP<2, 4>(Inst,
726 [](
auto X,
auto Y) -> decltype(X) {
return fmin(X, Y); });
729 executeOpFP<1, 4>(Inst, [](
auto X) -> decltype(X) {
return sin(X); });
732 executeOpFP<1, 4>(Inst, [](
auto X) -> decltype(X) {
return sinh(X); });
735 executeOpFP<1, 4>(Inst, [](
auto X) -> decltype(X) {
return sqrt(X); });
738 executeOpFP<1, 4>(Inst, [](
auto X) -> decltype(X) {
return tan(X); });
741 executeOpFP<1, 4>(Inst, [](
auto X) -> decltype(X) {
return tanh(X); });
744 Dev.
reportError(
"Unimplemented GLSL.std.450 extended instruction",
true);
750 executeOpFP<2>(Inst, [](
auto A,
auto B) -> decltype(A) {
return A + B; });
758 executeOpFP<1>(Inst, [](
auto A) ->
float {
return (
float)A; });
761 executeOpFP<1>(Inst, [](
auto A) ->
double {
return (
double)A; });
764 assert(
false &&
"Unhandled floating point size for OpFConvert");
770 executeOpFP<2>(Inst, [](
auto A,
auto B) -> decltype(A) {
return A / B; });
775 executeOpFP<2>(Inst, [](
auto A,
auto B) -> decltype(A) {
776 return A - (B * floor(A / B));
782 executeOpFP<2>(Inst, [](
auto A,
auto B) -> decltype(A) {
return A * B; });
787 executeOpFP<1>(Inst, [](
auto A) -> decltype(A) {
return -A; });
792 executeOpFP<2>(Inst, [](
auto A,
auto B) ->
bool {
793 return A == B && !std::isunordered(A, B);
799 executeOpFP<2>(Inst, [](
auto A,
auto B) ->
bool {
800 return A > B && !std::isunordered(A, B);
806 executeOpFP<2>(Inst, [](
auto A,
auto B) ->
bool {
807 return A >= B && !std::isunordered(A, B);
813 executeOpFP<2>(Inst, [](
auto A,
auto B) ->
bool {
814 return A < B && !std::isunordered(A, B);
820 executeOpFP<2>(Inst, [](
auto A,
auto B) ->
bool {
821 return A <= B && !std::isunordered(A, B);
827 executeOpFP<2>(Inst, [](
auto A,
auto B) ->
bool {
828 return A != B && !std::isunordered(A, B);
835 [](
auto A,
auto B) -> decltype(A) {
return fmod(A, B); });
840 executeOpFP<2>(Inst, [](
auto A,
auto B) -> decltype(A) {
return A - B; });
866 executeOpFP<2>(Inst, [](
auto A,
auto B) ->
bool {
867 return A == B || std::isunordered(A, B);
873 executeOpFP<2>(Inst, [](
auto A,
auto B) ->
bool {
874 return A > B || std::isunordered(A, B);
880 executeOpFP<2>(Inst, [](
auto A,
auto B) ->
bool {
881 return A >= B || std::isunordered(A, B);
887 executeOpFP<2>(Inst, [](
auto A,
auto B) ->
bool {
888 return A < B || std::isunordered(A, B);
894 executeOpFP<2>(Inst, [](
auto A,
auto B) ->
bool {
895 return A <= B || std::isunordered(A, B);
901 executeOpFP<2>(Inst, [](
auto A,
auto B) ->
bool {
902 return A != B || std::isunordered(A, B);
908 executeOpUInt<2>(Inst, [](
auto A,
auto B) -> decltype(A) {
return A + B; });
913 executeOpUInt<2>(Inst, [](
auto A,
auto B) ->
bool {
return A == B; });
923 (
const uint8_t *)&(SI->
Image));
933 assert(Result.getType()->getScalarType()->getBitWidth() == 32);
937 if (Inst->
getOpcode() == SpvOpImageQuerySizeLod)
941 uint32_t ArraySizeIndex;
946 Result.set<uint32_t>(Image->
getWidth(Level), 0);
952 Result.set<uint32_t>(Image->
getWidth(Level), 0);
953 Result.set<uint32_t>(Image->
getHeight(Level), 1);
957 Result.set<uint32_t>(Image->
getWidth(Level), 0);
958 Result.set<uint32_t>(Image->
getHeight(Level), 1);
959 Result.set<uint32_t>(Image->
getDepth(Level), 2);
990 const Type *CoordType = Coord.getType();
992 assert(NumCoords <= 3);
998 Layer = Coord.get<uint32_t>(--NumCoords);
1001 uint32_t X = Coord.get<uint32_t>(0);
1002 uint32_t Y = (NumCoords > 1) ? Coord.get<uint32_t>(1) : 0;
1003 uint32_t Z = (NumCoords > 2) ? Coord.get<uint32_t>(2) : 0;
1012 if (OperandMask & SpvImageOperandsLodMask)
1015 OperandMask ^= SpvImageOperandsLodMask;
1026 Image->
read(T, X, Y, Z, Layer, Level);
1044 assert(NumCoords <= 3);
1050 Layer = Coord.
get<
float>(--NumCoords);
1053 float X = Coord.
get<
float>(0);
1054 float Y = (NumCoords > 1) ? Coord.
get<
float>(1) : 0;
1055 float Z = (NumCoords > 2) ? Coord.
get<
float>(2) : 0;
1060 assert(Inst->
getOperand(4) == SpvImageOperandsLodMask);
1065 Sampler->
sample(Image, Texel, X, Y, Z, Layer);
1080 const Type *CoordType = Coord.getType();
1082 assert(NumCoords <= 3);
1088 Layer = Coord.get<uint32_t>(--NumCoords);
1091 uint32_t X = Coord.get<uint32_t>(0);
1092 uint32_t Y = (NumCoords > 1) ? Coord.get<uint32_t>(1) : 0;
1093 uint32_t Z = (NumCoords > 2) ? Coord.get<uint32_t>(2) : 0;
1097 Image->
write(Texel, X, Y, Z, Layer);
1102 executeOpUInt<2>(Inst, [](
auto A,
auto B) -> decltype(A) {
return A * B; });
1107 executeOpUInt<2>(Inst, [](
auto A,
auto B) ->
bool {
return A != B; });
1112 executeOpFP<1>(Inst, [](
auto A) ->
bool {
return std::isinf(A); });
1117 executeOpFP<1>(Inst, [](
auto A) ->
bool {
return std::isnan(A); });
1122 executeOpUInt<2>(Inst, [](
auto A,
auto B) -> decltype(A) {
return A - B; });
1141 executeOp<bool, 2>(Inst, [](
bool A,
bool B) {
return A && B; });
1146 executeOp<bool, 2>(Inst, [](
bool A,
bool B) {
return A == B; });
1151 executeOp<bool, 1>(Inst, [](
bool A) {
return !A; });
1156 executeOp<bool, 2>(Inst, [](
bool A,
bool B) {
return A != B; });
1161 executeOp<bool, 2>(Inst, [](
bool A,
bool B) {
return A || B; });
1171 assert(ScalarType->
isFloat());
1181 Element.
set(Element.
get<
float>() * Scalar.
get<
float>());
1184 Element.
set(Element.
get<
double>() * Scalar.
get<
double>());
1190 Matrix.
insert({col, row}, Element);
1204 assert(ScalarType->
isFloat());
1215 R += Vector.
get<
float>(col) * Matrix.
extract({col, row}).get<float>();
1223 R += Vector.
get<
double>(col) * Matrix.
extract({col, row}).get<double>();
1237 executeOpUInt<1>(Inst, [](
auto A) -> decltype(A) {
return ~A; });
1254 assert(
false &&
"no matching predecessor block for OpPhi");
1287 for (uint64_t Address : SE.Allocations)
1309 ((
SampledImage *)(Result.getData()))->Sampler = Sampler;
1318 executeOpSInt<1>(Inst, [](
auto A) -> int16_t {
return (int16_t)A; });
1321 executeOpSInt<1>(Inst, [](
auto A) -> int32_t {
return (int32_t)A; });
1324 executeOpSInt<1>(Inst, [](
auto A) -> int64_t {
return (int64_t)A; });
1327 assert(
false &&
"Unhandled integer size for OpSConvert");
1333 executeOpSInt<2>(Inst, [](
auto A,
auto B) -> decltype(A) {
return A / B; });
1345 Objects[Id] = Condition.
get<
bool>() ? Object1 : Object2;
1350 for (uint32_t i = 0; i < Result.getType()->getElementCount(); i++)
1355 Objects[Id] = Result;
1361 executeOpSInt<2>(Inst, [](
auto A,
auto B) ->
bool {
return A > B; });
1366 executeOpSInt<2>(Inst, [](
auto A,
auto B) ->
bool {
return A >= B; });
1371 executeOpUInt<2>(Inst, [](
auto A,
auto B) -> decltype(A) {
return A << B; });
1376 executeOpSInt<2>(Inst, [](
auto A,
auto B) -> decltype(A) {
return A >> B; });
1381 executeOpUInt<2>(Inst, [](
auto A,
auto B) -> decltype(A) {
return A >> B; });
1386 executeOpSInt<2>(Inst, [](
auto A,
auto B) ->
bool {
return A < B; });
1391 executeOpSInt<2>(Inst, [](
auto A,
auto B) ->
bool {
return A <= B; });
1396 executeOpSInt<2>(Inst, [](
auto A,
auto B) -> decltype(A) {
1397 return (std::abs(A) % B) * (B < 0 ? -1 : 1);
1403 executeOpSInt<1>(Inst, [](
auto A) -> decltype(A) {
return -A; });
1408 executeOpSInt<2>(Inst, [](
auto A,
auto B) -> decltype(A) {
return A % B; });
1416 Objects[Id].
store(Mem, Dest);
1425 Dev.reportError(
"OpSwitch is only implemented for 32-bit selectors",
true);
1443 executeOpUInt<1>(Inst, [](
auto A) -> uint16_t {
return (uint16_t)A; });
1446 executeOpUInt<1>(Inst, [](
auto A) -> uint32_t {
return (uint32_t)A; });
1449 executeOpUInt<1>(Inst, [](
auto A) -> uint64_t {
return (uint64_t)A; });
1452 assert(
false &&
"Unhandled integer size for OpUConvert");
1458 executeOpUInt<2>(Inst, [](
auto A,
auto B) -> decltype(A) {
return A / B; });
1463 executeOpUInt<2>(Inst, [](
auto A,
auto B) ->
bool {
return A > B; });
1468 executeOpUInt<2>(Inst, [](
auto A,
auto B) ->
bool {
return A >= B; });
1473 executeOpUInt<2>(Inst, [](
auto A,
auto B) ->
bool {
return A < B; });
1478 executeOpUInt<2>(Inst, [](
auto A,
auto B) ->
bool {
return A <= B; });
1488 Dev.reportError(
"OpUnreachable instruction executed",
true);
1493 executeOpUInt<2>(Inst, [](
auto A,
auto B) -> decltype(A) {
return A % B; });
1498 assert(Inst->
getOperand(2) == SpvStorageClassFunction);
1502 uint64_t Address = PrivateMemory->allocate(AllocSize);
1510 if (!CallStack.empty())
1511 CallStack.back().Allocations.push_back(Address);
1518 switch (Objects[Inst->
getOperand(3)].getType()->getSize())
1521 Index =
OP(3, uint16_t);
1524 Index = (uint16_t)
OP(3, uint32_t);
1527 Index = (uint16_t)
OP(3, uint64_t);
1530 assert(
false &&
"Unhandled index size in OpVectorExtractDynamic");
1535 Dev.reportError(
"Vector index out of range");
1536 Objects[Id] = Vector.
extract({Index});
1543 switch (Objects[Inst->
getOperand(4)].getType()->getSize())
1546 Index =
OP(4, uint16_t);
1549 Index = (uint16_t)
OP(4, uint32_t);
1552 Index = (uint16_t)
OP(4, uint64_t);
1555 assert(
false &&
"Unhandled index size in OpVectorInsertDynamic");
1561 Dev.reportError(
"Vector index out of range");
1562 Objects[Id] = Vector;
1563 Objects[Id].
insert({Index}, Component);
1578 if (Idx == 0xFFFFFFFF)
1580 else if (Idx < Vec1Length)
1581 Result.insert({i}, Vec1.extract({Idx}));
1583 Result.insert({i}, Vec2.
extract({Idx - Vec1Length}));
1586 Objects[Id] = Result;
1596 assert(ScalarType->
isFloat());
1607 R += Vector.
get<
float>(row) * Matrix.
extract({col, row}).get<float>();
1615 R += Vector.
get<
double>(row) * Matrix.
extract({col, row}).get<double>();
1620 Dev.reportError(
"Unhandled floating point size",
true);
1633 float Scalar = Objects[Inst->
getOperand(3)].get<
float>();
1634 executeOp<float, 1>(Inst, [&](
float A) {
return A * Scalar; });
1639 double Scalar = Objects[Inst->
getOperand(3)].get<
double>();
1640 executeOp<double, 1>(Inst, [&](
double A) {
return A * Scalar; });
1644 assert(
false &&
"Unhandled floating point size for OpDot");
1648 Memory &Invocation::getMemory(uint32_t StorageClass)
1650 switch (StorageClass)
1652 case SpvStorageClassPushConstant:
1653 case SpvStorageClassStorageBuffer:
1654 case SpvStorageClassUniform:
1655 case SpvStorageClassUniformConstant:
1656 return Dev.getGlobalMemory();
1657 case SpvStorageClassWorkgroup:
1658 assert(Group &&
"Not executing within a workgroup.");
1659 return Group->getLocalMemory();
1660 case SpvStorageClassInput:
1661 case SpvStorageClassOutput:
1662 return *PipelineMemory;
1663 case SpvStorageClassFunction:
1664 case SpvStorageClassPrivate:
1665 return *PrivateMemory;
1667 assert(
false &&
"Unhandled storage class");
1672 Object Invocation::getObject(uint32_t Id)
const
1674 if (Id < Objects.size())
1684 return CurrentInstruction ? READY : FINISHED;
1687 void Invocation::moveToBlock(uint32_t Id)
1689 const Block *B = CurrentFunction->getBlock(Id);
1691 PreviousBlock = CurrentBlock;
1695 void Invocation::step()
1697 assert(getState() == READY);
1698 assert(CurrentInstruction);
1702 if (!PhiTemps.empty() && I->
getOpcode() != SpvOpPhi &&
1705 for (
auto &P : PhiTemps)
1706 Objects[P.first] = std::move(P.second);
1714 if (I == CurrentInstruction)
1715 CurrentInstruction = CurrentInstruction->next();
1717 Dev.reportInstructionExecuted(
this, I);
1719 if (getState() == FINISHED)
1720 Dev.reportInvocationComplete(
this);
1725 template <
typename OpTy,
typename F>
1726 static auto apply(
const std::array<OpTy, 1> Operands,
const F &Op)
1728 return Op(Operands[0]);
1731 template <
typename OpTy,
typename F>
1732 static auto apply(
const std::array<OpTy, 2> Operands,
const F &Op)
1734 return Op(Operands[0], Operands[1]);
1737 template <
typename OpTy,
typename F>
1738 static auto apply(
const std::array<OpTy, 3> Operands,
const F &Op)
1740 return Op(Operands[0], Operands[1], Operands[2]);
1743 template <
typename OpTy,
unsigned N,
unsigned Offset,
typename F>
1748 std::array<OpTy, N> Operands;
1754 for (
unsigned j = 0; j < N; j++)
1755 Operands[j] = Objects[Inst->
getOperand(Offset + j)].
get<OpTy>(i);
1758 Result.set(apply(Operands, Op), i);
1761 Objects[Id] = Result;
1764 template <
unsigned N,
unsigned Offset,
typename F>
1767 const Type *OpType = Objects[Inst->
getOperand(Offset)].getType();
1769 assert(OpType->
isInt());
1773 executeOp<int8_t, N, Offset>(Inst, Op);
1776 executeOp<int16_t, N, Offset>(Inst, Op);
1779 executeOp<int32_t, N, Offset>(Inst, Op);
1782 executeOp<int64_t, N, Offset>(Inst, Op);
1785 assert(
false &&
"Unhandled binary operation integer width");
1789 template <
unsigned N,
unsigned Offset,
typename F>
1792 const Type *OpType = Objects[Inst->
getOperand(Offset)].getType();
1798 executeOp<float, N, Offset>(Inst, Op);
1801 executeOp<double, N, Offset>(Inst, Op);
1804 assert(
false &&
"Unhandled binary operation floating point size");
1808 template <
unsigned N,
unsigned Offset,
typename F>
1811 const Type *OpType = Objects[Inst->
getOperand(Offset)].getType();
1813 assert(OpType->
isInt());
1817 executeOp<uint8_t, N>(Inst, Op);
1820 executeOp<uint16_t, N>(Inst, Op);
1823 executeOp<uint32_t, N>(Inst, Op);
1826 executeOp<uint64_t, N>(Inst, Op);
1829 assert(
false &&
"Unhandled binary operation integer width");
This class represents a module-scope variable declaration.
Instruction & getLabel() const
Returns the label instruction for this block.
This file declares the Block class.
void executeImageWrite(const Instruction *Inst)
const DescriptorElement * getDescriptorElements() const
Returns the descriptor array element information.
This file declares the Workgroup class.
void reportError(const std::string &Error, bool Fatal=false)
Report an error that has occurred during emulation.
std::vector< std::pair< uint32_t, Object > > PhiTemps
Temporary OpPhi results to be applied when we reach first non-OpPhi.
bool isScalar() const
Returns true if this is a scalar type.
void executeCompositeConstruct(const Instruction *Inst)
void executeFRem(const Instruction *Inst)
void executePhi(const Instruction *Inst)
void executeIsInf(const Instruction *Inst)
This file declares the Device class.
void write(const Image::Texel &T, uint32_t X, uint32_t Y=0, uint32_t Z=0, uint32_t Layer=0, uint32_t MipLevel=0) const
Write a texel to the image view at the specified coordinate.
This class represents an image object.
uint32_t PreviousBlock
The previous block (for OpPhi).
bool isFloat() const
Returns true if this is a floating point type.
std::vector< StackEntry > CallStack
The function call stack.
#define DISPATCH(Op, Func)
size_t getSize() const
Returns the size of this type in bytes.
std::vector< uint64_t > Allocations
Function scope allocations within this stack frame.
void executeExtInst(const Instruction *Inst)
void executeFAdd(const Instruction *Inst)
static void copy(uint64_t DstAddress, Memory &DstMem, uint64_t SrcAddress, const Memory &SrcMem, uint64_t NumBytes)
Copy data between memory instances.
A data structure holding information for a function call.
uint32_t atomicCmpXchg(uint64_t Address, uint32_t Scope, uint32_t EqualSemantics, uint32_t UnequalSemantics, uint32_t Value, uint32_t Comparator)
Perform an atomic compare-exchange operation at Address.
bool Discarded
True when fragment was discarded.
void release(uint64_t Address)
Release the allocation with base address Address.
A combination of an image and a sampler used to access it.
void executeCopyObject(const Instruction *Inst)
Structure to describe the memory layout of a matrix.
const Function * getFunction() const
Returns the function specified by this entry point.
void executeCompositeInsert(const Instruction *Inst)
void executeImageQuerySize(const Instruction *Inst)
void executeConvertUToF(const Instruction *Inst)
This file declares the Module class.
size_t getElementOffset(uint64_t Index) const
Returns the byte offset of the element at Index.
const Type * getElementType(uint64_t Index=0) const
Returns the type of the element at Index.
const Type * getScalarType() const
Returns the element type for vector types, or this for scalar types.
void executeINotEqual(const Instruction *Inst)
Object toObject(const Type *Ty) const
Create an object with type Ty from the texel data.
bool isInt() const
Returns true if this is an integer type.
Memory * PrivateMemory
The private memory instance.
Device & Dev
The device this invocation is executing on.
void executeAtomicOp(const Instruction *Inst)
void executeIsNan(const Instruction *Inst)
void sample(const ImageView *Image, Image::Texel &Texel, float S, float T=0, float R=0, float A=0, float Lod=0) const
Sample a texel from an image at the specified coordinates.
std::shared_ptr< const Module > getModule() const
Return the module this pipeline stage is using.
void executeFUnordGreaterThan(const Instruction *Inst)
void executeAll(const Instruction *Inst)
void executeFOrdLessThanEqual(const Instruction *Inst)
This class represents a view into a range of image subresources.
This file declares the EntryPoint class.
This class represents a function in a SPIR-V Module.
void executeKill(const Instruction *Inst)
void executeAccessChain(const Instruction *Inst)
void executeMatrixTimesScalar(const Instruction *Inst)
void executeFDiv(const Instruction *Inst)
~Invocation()
Destroy this invocation.
void executeReturn(const Instruction *Inst)
void executeFSub(const Instruction *Inst)
const Instruction * CallInst
The calling instruction.
void store(Memory &Mem, uint64_t Address) const
Store the value of this object to memory at Address.
void executeFOrdNotEqual(const Instruction *Inst)
const EntryPoint * getEntryPoint() const
Return the entry point this pipeline stage will invoke.
uint32_t getOperand(unsigned i) const
Returns the operand at index i;.
void executeSelect(const Instruction *Inst)
Invocation(Device &Dev, const std::vector< Object > &InitialObjects)
Create a standalone invocation for a device, with an initial set of result objects.
void executeBitwiseXor(const Instruction *Inst)
void set(T Value, uint32_t Element=0)
Set the value of this object to a scalar of type T.
uint32_t getDimensionality() const
Returns the dimensionality of an image type.
std::shared_ptr< const Module > CurrentModule
The current module.
uint16_t getOpcode() const
Returns the opcode.
void executeIAdd(const Instruction *Inst)
This class represents a single texel with four 32-bit component values.
uint32_t getElementCount() const
Returns the number of elements in this array, struct, or vector type.
void executeAtomicCompareExchange(const Instruction *Inst)
void executeImageSampleExplicitLod(const Instruction *Inst)
void executeNot(const Instruction *Inst)
void executeBitcast(const Instruction *Inst)
This file declares the Instruction class.
const class ImageView * Image
uint32_t getNumArrayLayers() const
Returns the number of array layers in the image view.
static Object load(const Type *Ty, const Memory &Mem, uint64_t Address)
Create an object of type Ty from the data at Address.
void executeFOrdLessThan(const Instruction *Inst)
uint32_t getWidth(uint32_t Level=0) const
Get the width of the image view at the specified mip level.
void executeFUnordNotEqual(const Instruction *Inst)
This file declares the Type class.
void executeSampledImage(const Instruction *Inst)
const Function * CallFunc
The function containing CallInst.
Class representing a 3-dimensional size or ID.
uint32_t getFirstBlockId() const
Returns the ID of the first block in this function.
State
Used to indicate whether an invocation is ready to execute, waiting at a barrier, or complete...
void executeFMul(const Instruction *Inst)
void execute(const Instruction *Inst)
Execute Inst in this invocation.
enum talvos::PtrMatrixLayout::@4 Order
Specifies the order of the elements in memory.
void executeConvertSToF(const Instruction *Inst)
void executeIEqual(const Instruction *Inst)
void executeFUnordLessThan(const Instruction *Inst)
void executeCompositeExtract(const Instruction *Inst)
uint32_t Stride
The stride in bytes between columns (COL_MAJOR) or rows (ROW_MAJOR).
T atomic(uint64_t Address, uint32_t Opcode, uint32_t Scope, uint32_t Semantics, T Value=0)
Atomically apply operation defined by Opcode to Address.
This class represents an address space in the virtual device.
uint32_t getDepth(uint32_t Level=0) const
Get the depth of the image view at the specified mip level.
void executeSDiv(const Instruction *Inst)
void executeISub(const Instruction *Inst)
This file declares the PipelineStage class.
const VariableList & getVariables() const
Return the workgroup scope variable pointer values.
void executeLogicalEqual(const Instruction *Inst)
This file declares data structures and functions for handling images.
uint32_t getBitWidth() const
Returns the bit-width of this type.
const Instruction * CurrentInstruction
The current instruction.
uint32_t getStorageClass() const
Returns the storage class of this type.
size_t getNumParams() const
Returns the number of parameters in this function.
A Device instance encapsulates properties and state for the virtual device.
void executeLogicalNotEqual(const Instruction *Inst)
void executeLogicalAnd(const Instruction *Inst)
void executeAny(const Instruction *Inst)
uint32_t CallBlock
The block containing CallInst.
This class represents a workgroup executing a compute command.
void executeMatrixTimesVector(const Instruction *Inst)
void executeCopyMemory(const Instruction *Inst)
void executeConvertFToU(const Instruction *Inst)
uint8_t * getData()
Returns a mutable pointer to the raw data backing this object.
void executeLogicalNot(const Instruction *Inst)
void executeFOrdGreaterThan(const Instruction *Inst)
This class represents a sampler object.
uint16_t getNumOperands() const
Returns the number of operands this instruction has.
uint32_t getParamId(uint32_t I) const
Returns the ID of the parameter at index I.
const Type * getType() const
Returns the type of this object.
This class encapsulates information about a pipeline stage.
const Type * getResultType() const
Returns the result type of this instruction, or nullptr if it does not produce a result.
void reportInvocationBegin(const Invocation *Invoc)
uint32_t getHeight(uint32_t Level=0) const
Get the height of the image view at the specified mip level.
void executeBitwiseAnd(const Instruction *Inst)
This file declares the Memory class.
bool AtBarrier
True when at a barrier.
const uint32_t * getOperands() const
Returns the operands.
void executeFUnordLessThanEqual(const Instruction *Inst)
void executeBitwiseOr(const Instruction *Inst)
void executeDot(const Instruction *Inst)
const PtrMatrixLayout & getMatrixLayout() const
Get the matrix layout for this object.
void executeFNegate(const Instruction *Inst)
void executeFUnordGreaterThanEqual(const Instruction *Inst)
void executeImageRead(const Instruction *Inst)
void executeLoad(const Instruction *Inst)
This class represents a SPIR-V type.
This file declares the Function class.
void insert(const std::vector< uint32_t > &Indices, const Object &Element)
Insert the value of Element into a composite object.
void executeFConvert(const Instruction *Inst)
This file declares the Invocation class.
uint64_t allocate(uint64_t NumBytes)
Allocate a new buffer of size NumBytes.
void executeConvertFToS(const Instruction *Inst)
std::vector< Object > Objects
Set of result objects.
bool isArrayedImage() const
Returns the Arrayed flag of an image type.
void executeControlBarrier(const Instruction *Inst)
#define OP(Index, Type)
Get scalar operand at index Index with type Type.
void executeImage(const Instruction *Inst)
This class represents an instruction result.
void store(uint64_t Address, uint64_t NumBytes, const uint8_t *Data)
Store NumBytes of data from Data to Address.
void moveToBlock(uint32_t Id)
Move this invocation to the block with ID Id.
void executeReturnValue(const Instruction *Inst)
void executeBranch(const Instruction *Inst)
void executeIMul(const Instruction *Inst)
const Instruction * next() const
Get the next instruction in the containing block.
uint32_t CurrentBlock
The current block.
void executeBranchConditional(const Instruction *Inst)
const class Sampler * Sampler
void executeFUnordEqual(const Instruction *Inst)
This class represents a SPIR-V instruction.
void executeSConvert(const Instruction *Inst)
void executeLogicalOr(const Instruction *Inst)
This file declares the Variable class.
void executeFOrdEqual(const Instruction *Inst)
void executeFunctionCall(const Instruction *Inst)
T get(uint32_t Element=0) const
Get the value of this object as a scalar of type T.
Object extract(const std::vector< uint32_t > &Indices) const
Extract an element from a composite object.
Memory & getMemory(uint32_t StorageClass)
Returns the memory instance associated with StorageClass.
const Function * CurrentFunction
The current function.
void executeFOrdGreaterThanEqual(const Instruction *Inst)
std::shared_ptr< Memory > PipelineMemory
Memory used for input and output storage classes.
void read(Image::Texel &T, uint32_t X, uint32_t Y=0, uint32_t Z=0, uint32_t Layer=0, uint32_t MipLevel=0) const
Read a texel from the image view at the specified coordinate.
uint64_t Address
Address of descriptor element.
void executeFMod(const Instruction *Inst)
A block of instructions ending with a termination instruction.